Integer array to BMP

The topic : http://www.cplusplus.com/forum/beginner/4307/
is no longer accessible.. so.. stating my question here..

I have an Integer array stored in.. x[10][10]

it has numbers between 0-9 stored at all array..

what I wanted to achieve was to represent each number with a colored 'square' or pixel... and get the output..

i accomplished the square by changing the background color and printing a " "

http://img149.imageshack.us/gal.php?g=56878271.jpg

ex : Please see the images attached..
0 = white
4 = red... so on..

now I want to save this output into any Image file.. (not using print screen because doesnt work for large arrays..

..

If someone can tell me the in the simplest manner possible (for a noob) on how to achieve this..
Before you go any further... why exactly do you want to do this?

Your data is 4 * 10 * 10 = 400 bytes long. But you are only using 4/32 * 4 * 10 * 10 = 50 bytes --> 12.5% of that. Further, the bitmap header information for your bitmaps will be nearly 100 bytes of additional data...

Also, I don't understand how console graphics have anything to do with a Win32 bitmap. They are completely different things.

Why not just write your data to file as a straight byte array? You can even encode the array size in it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bool write_int_array_as_byte( const string& filename, const int* a, unsigned width, unsigned height )
  {
  ofstream f( filename.c_str(), ios::binary );
  if (!f) return false;

  // Put the width and height as 16-bit entities, stored in little-endian format (LSB first)
  f.put(  width        & 0xFF );
  f.put( (width  >> 8) & 0xFF );

  f.put(  height       & 0xFF );
  f.put( (height >> 8) & 0xFF );

  // Now put the individual byte values of the array in row-major order
  for (int y = 0; y < height; y++)
  for (int x = 0; x < width;  x++)
    f.put( a[ (y * width) + x ] & 0xFF );

  f.close();
  return true;
  }

A file like that would cost you only the size of the array in bytes plus the header information (which in this case, is four bytes): 2 + 2 + (1 * 10 * 10) = 104 bytes. (You could make it smaller, but it probably isn't worth the effort.)

The file is also easy to read...

Tell us what you want to do.
What i am doing is simulation of a deposition process... (scientific calculation using random numbers and monte carlo method)..

see the image link...

http://img149.imageshack.us/gal.php?g=56878271.jpg

the figure on the left has different numbers stored in it.. each number represents a specific material which will be deposited on that very place...

the array represents the material surface...

to make it easy to understand... i just represented each number with a color ( image on the right)...

now... the problem with c++ console is that it cannot display .. for like .. if i want the simulation result of 500x500 which i will ... (this is 10x10)..

so.. what i wanted to do .. was to somehow.. have this / similar output saved in an image file..

i can save the number array in a file.. that is fine.. now i want an image file pf representative colors.. so that its easy to understand whats going on.. and what material will be deposited where..

hence the question..

i have an array [10][10] .. each array block (100 such blocks right..) stores a number between 0-9 representing the material deposited.. how to convert this into a picture file.. by assigning each number with a representative color ?

Thanks :)
Last edited on
Here is a tutorial about how to write a bitmap.
http://delphi.about.com/od/graphics/l/aa101803a.htm
If you want, I'll write you a little thing to create a simple BMP or TGA file.

Will the range always be less than 28?
Do you want to specify your own colors? Or will a simple range across the HSV scale do?
Can your output device handle TrueColor? Or 256 simultaneous colors? Or less?
Thanks for the tutorial.. am going through it..

have i been clear with the explanation of my problem ?



Will the range always be less than 2^8?'

range.. as in ? no of colors ? then yes...


Do you want to specify your own colors? Or will a simple range across the HSV scale do?

any colors that show the contrast between them prominently will do just fine...


Can your output device handle TrueColor? Or 256 simultaneous colors? Or less?

yes... its a 32 bit desktop color depth (if that is what you are referring to)...



i only need.. lets say.. to an upper limit of 20 colors for now..



Duoas, if you don't mind me asking, why did you store the height and width in LE format in the code you posted above? And what does the '& 0xFF' do?
x86 hardware stores multibyte values in LE format.
The '& 0xFF' gets rid of extraneous bits. I'm not sure it is entirely necessary, but it should prevent any overflow problems...

I'll get you some code "pretty soon now"...
I don't know if you still need this, but here's a little module I wrote for you to do what you want. (I think.)

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
// intarray2bmp.hpp
//
// Convert an array of integer values to a bitmap.
// Copyright 2009 Michael Thomas Greer
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//

#ifndef INTARRAY2BMP_HPP
#define INTARRAY2BMP_HPP

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

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

#endif

// end intarray2bmp.hpp 

To use it, just pass the correct argument type:
1
2
3
  int* image[ 50 ];
  ...
  bool result = intarray2bmp::intarray2bmp( "foo.bmp", image, 50, 50, MYMIN, MYMAX );
1
2
3
  int image[ 50 ][ 50 ];
  ...
  bool result = intarray2bmp::intarray2bmp( "foo.bmp", &(image[0][0]), 50, 50, MYMIN, MYMAX );

Presumably MYMIN is zero and MYMAX is nine (at least, according to the information you gave me above).

Notice also that the function is templated, so that you can use an array of char, or short, or long, etc. You'll just have to make sure that all argument types match:
1
2
3
4
5
  unsigned char image[ 50 ][ 50 ];
  ...
  bool result = intarray2bmp::intarray2bmp <unsigned char> ( "foo.bmp", &(image[0][0]), 50, 50, 0, 9 );
//or
  bool result = intarray2bmp::intarray2bmp( "foo.bmp", &(image[0][0]), 50, 50, (unsigned char)0, (unsigned char)9 );


Enjoy!
Hey.. Thanks a lot.. Will Try it ..
Topic archived. No new replies allowed.