Integer array to BMP

I have a problem concerning transforming int array into bmp image. I wanted to add a post in this topic: http://www.cplusplus.com/forum/beginner/12848/ , but unfortunately it is closed. Actually I have a question concerning the code written by Duoas. I have a function which takes values from the file and I want to convert it into bmp with the use of Duoas code. I do it like that(it's Duoas code + my load and main function) Is it something wrong with how I do it or it's rather sth wrong with the file. I would really appreciate your help.
It compiles without errors but when I run it: core dumped.
According to gdb debugger problem is here: double hue = (intarray[ row - 1 ][ col ] - min_value) * granularity; programs stops, segmentation fault I have no idea why...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#ifndef INTARRAY2BMP_HPP
#define INTARRAY2BMP_HPP

#include <fstream>
#include <iostream>
#include <string>

    #include <cstdlib>
#include <stdint.h>
#include <cstdio>
#include <iostream>
#include <string>
#include <istream>
#include <cstring>
#include <fstream>
#include <sstream>
#include <cctype>

using namespace std;
using std::cout;
using std::endl;

ifstream file;

void Load(int16_t** height_pointer) {
    ifstream file;
    file.open ("0_dlc.000", ios::in|ios::binary);
    if( file.good() == true )
{
    cout << "Uzyskano dostep do pliku!" << endl;
}
else cout<< "File cannot open" <<endl;
    *height_pointer = new int16_t[512*512];
    //ifstream file ("0_dlc.000", ios::in|ios::binary);
    file.seekg (40960, file.beg); // 565248 - channel 2, 1089536-channel 3
    file.read((char *)*height_pointer, 2*512*512);
    file.close();
    cout<<*height_pointer[0]<<endl;
}

namespace intarray2bmp
  {

  //--------------------------------------------------------------------------
  // This little helper is to write little-endian values to file.
  //
  struct lwrite
    {
    unsigned long value;
    unsigned      size;
    lwrite( unsigned long value, unsigned size ):
      value( value ), size( size )
      { }
    };

  //--------------------------------------------------------------------------
  inline std::ostream& operator << ( std::ostream& outs, const lwrite& v )
    {
    unsigned long value = v.value;
    for (unsigned cntr = 0; cntr < v.size; cntr++, value >>= 8)
      outs.put( static_cast <char> (value & 0xFF) );
    return outs;
    }

  //--------------------------------------------------------------------------
  // Take an integer array and convert it into a color image.
  //
  // This first version takes an array of array style of array:
  //   int* a[ 10 ]
  //
  // The second, overloaded version takes a flat C-style array:
  //   int a[ 10 ][ 10 ]
  //
  template <typename IntType>
  bool intarray2bmp(
    const std::string& filename,
    IntType**          intarray,
    unsigned           rows,
    unsigned           columns,
    IntType            min_value,
    IntType            max_value
    ) {
    // This is the difference between each color based upon
    // the number of distinct values in the input array.
    double granularity = 360.0 / ((double)( max_value - min_value ) + 1);

    // Open the output BMP file
    std::ofstream f( filename.c_str(),
                     std::ios::out | std::ios::trunc | std::ios::binary );
    if (!f) return false;

    // Some basic
    unsigned long headers_size    = 14  // sizeof( BITMAPFILEHEADER )
                                  + 40; // sizeof( BITMAPINFOHEADER )
    unsigned long padding_size    = (4 - ((columns * 3) % 4)) % 4;
    unsigned long pixel_data_size = rows * ((columns * 3) + padding_size);

    // Write the BITMAPFILEHEADER
    f.put( 'B' ).put( 'M' );                           // bfType
    f << lwrite( headers_size + pixel_data_size, 4 );  // bfSize
    f << lwrite( 0,                              2 );  // bfReserved1
    f << lwrite( 0,                              2 );  // bfReserved2
    f << lwrite( headers_size,                   4 );  // bfOffBits

    // Write the BITMAPINFOHEADER
    f << lwrite( 40,                             4 );  // biSize
    f << lwrite( columns,                        4 );  // biWidth
    f << lwrite( rows,                           4 );  // biHeight
    f << lwrite( 1,                              2 );  // biPlanes
    f << lwrite( 24,                             2 );  // biBitCount
    f << lwrite( 0,                              4 );  // biCompression=BI_RGB
    f << lwrite( pixel_data_size,                4 );  // biSizeImage
    f << lwrite( 0,                              4 );  // biXPelsPerMeter
    f << lwrite( 0,                              4 );  // biYPelsPerMeter
    f << lwrite( 0,                              4 );  // biClrUsed
    f << lwrite( 0,                              4 );  // biClrImportant

    // Write the pixel data
    for (unsigned row = rows; row; row--)           // bottom-to-top
      {
      for (unsigned col = 0; col < columns; col++)  // left-to-right
        {
        unsigned char red, green, blue;
        //
        // This is how we convert an integer value to a color:
        // by mapping it evenly along the CIECAM02 hue color domain.
        //
        // http://en.wikipedia.org/wiki/Hue
        // http://en.wikipedia.org/wiki/hsl_and_hsv#conversion_from_hsv_to_rgb
        //
        // The following algorithm takes a few shortcuts since
        // both 'value' and 'saturation' are always 1.0.
        //
        double hue = (intarray[ row - 1 ][ col ] - min_value) * granularity;
        int    H = (int)( hue / 60 ) % 6;
        double F = (hue / 60) - H;
        double Q = 1.0 - F;

        #define c( x ) (255 * x)
        switch (H)
          {
          case 0:  red = c(1);  green = c(F);  blue = c(0);  break;
          case 1:  red = c(Q);  green = c(1);  blue = c(0);  break;
          case 2:  red = c(0);  green = c(1);  blue = c(F);  break;
          case 3:  red = c(0);  green = c(Q);  blue = c(1);  break;
          case 4:  red = c(F);  green = c(0);  blue = c(1);  break;
          default: red = c(1);  green = c(0);  blue = c(Q);
          }
        #undef c

        f.put( static_cast <char> (blue)  )
         .put( static_cast <char> (green) )
         .put( static_cast <char> (red)   );
        }

      if (padding_size) f << lwrite( 0, padding_size );
      }

    // All done!
    return f.good();
    }

  //--------------------------------------------------------------------------
  template <typename IntType>
  bool intarray2bmp(
    const std::string& filename,
    IntType*           intarray,
    unsigned           rows,
    unsigned           columns,
    IntType            min_value,
    IntType            max_value
    ) {
    IntType** ia = new( std::nothrow ) IntType* [ rows ];
    for (unsigned row = 0; row < rows; row++)
      {
      ia[ row ] = intarray + (row * columns);
      }
    bool result = intarray2bmp(
                    filename, ia, rows, columns, min_value, max_value
                    );
    delete [] ia;
    return result;
    }

  } // namespace intarray2bmp
main()
{
  int16_t* image;
  Load(&image);
  bool result = intarray2bmp::intarray2bmp( "foo.bmp", (int*)(image), 512, 512, -4000, 4000 ); 
  
/*
int16_t* image;

bool result = intarray2bmp::intarray2bmp( "foo.bmp", (int*)(image), 512, 512, 0, 500 ); //image do poczatku pliku
*/

}

#endif
Last edited on
Are you sure your load routine returns what you expect? Line 25 and 33
Chances are you are trying to read memory not allocated to the array, since your types don't match. (Assuming that int16_t != int).

But first, your file load needs some better care.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int16_t* Load(const char* filename) 
{
    ifstream file;
    file.open (filename, ios::in|ios::binary);
    file.seekg (40960, file.beg); // 565248 - channel 2, 1089536-channel 3
    if(file)
    {
        cout << "Z powodzeniem otworzył " << filename << endl;
        int16_t* result = new int16_t[512*512];
        file.read((char *)result, 2*512*512);
cout<<*result[0]<<endl;
        return result;
    }
    else 
    {
        cout<< "nie można otworzyć " << filename << endl;
        return NULL;
    }
}

1
2
3
4
5
6
7
8
9
10
11
main()
{
    int16_t* image = Load("0_dlc.000");
    if (image) 
    {
        // don't cast to some other integer type here!
        intarray2bmp::intarray2bmp("foo.bmp", image, 512, 512, -4000, 4000 );
    }
    delete [] image;
    return 0;
}

Be sure to be consistent with braces and to clean up after yourself.

Hope this helps.
Topic archived. No new replies allowed.