intarray2bmp.hpp (7218B)
1 // intarray2bmp.hpp 2 // 3 // Convert an array of integer values to a bitmap. 4 // Copyright 2009 Michael Thomas Greer 5 // 6 // Boost Software License - Version 1.0 - August 17th, 2003 7 // 8 // Permission is hereby granted, free of charge, to any person or organization 9 // obtaining a copy of the software and accompanying documentation covered by 10 // this license (the "Software") to use, reproduce, display, distribute, 11 // execute, and transmit the Software, and to prepare derivative works of the 12 // Software, and to permit third-parties to whom the Software is furnished to 13 // do so, all subject to the following: 14 // 15 // The copyright notices in the Software and this entire statement, including 16 // the above license grant, this restriction and the following disclaimer, 17 // must be included in all copies of the Software, in whole or in part, and 18 // all derivative works of the Software, unless such copies or derivative 19 // works are solely in the form of machine-executable object code generated by 20 // a source language processor. 21 // 22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 25 // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 26 // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 27 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 // DEALINGS IN THE SOFTWARE. 29 // 30 31 #ifndef INTARRAY2BMP_HPP 32 #define INTARRAY2BMP_HPP 33 34 #include <fstream> 35 #include <iostream> 36 #include <string> 37 38 namespace intarray2bmp 39 { 40 41 //-------------------------------------------------------------------------- 42 // This little helper is to write little-endian values to file. 43 // 44 struct lwrite 45 { 46 unsigned long value; 47 unsigned size; 48 lwrite( unsigned long value, unsigned size ): 49 value( value ), size( size ) 50 { } 51 }; 52 53 //-------------------------------------------------------------------------- 54 inline std::ostream& operator << ( std::ostream& outs, const lwrite& v ) 55 { 56 unsigned long value = v.value; 57 for (unsigned cntr = 0; cntr < v.size; cntr++, value >>= 8) 58 outs.put( static_cast <char> (value & 0xFF) ); 59 return outs; 60 } 61 62 //-------------------------------------------------------------------------- 63 // Take an integer array and convert it into a color image. 64 // 65 // This first version takes an array of array style of array: 66 // int* a[ 10 ] 67 // 68 // The second, overloaded version takes a flat C-style array: 69 // int a[ 10 ][ 10 ] 70 // 71 template <typename IntType> 72 bool intarray2bmp( 73 const std::string& filename, 74 IntType** intarray, 75 unsigned rows, 76 unsigned columns, 77 IntType min_value, 78 IntType max_value 79 ) { 80 // This is the difference between each color based upon 81 // the number of distinct values in the input array. 82 double granularity = 360.0 / ((double)( max_value - min_value ) + 1); 83 84 // Open the output BMP file 85 std::ofstream f( filename.c_str(), 86 std::ios::out | std::ios::trunc | std::ios::binary ); 87 if (!f) return false; 88 89 // Some basic 90 unsigned long headers_size = 14 // sizeof( BITMAPFILEHEADER ) 91 + 40; // sizeof( BITMAPINFOHEADER ) 92 unsigned long padding_size = (4 - ((columns * 3) % 4)) % 4; 93 unsigned long pixel_data_size = rows * ((columns * 3) + padding_size); 94 95 // Write the BITMAPFILEHEADER 96 f.put( 'B' ).put( 'M' ); // bfType 97 f << lwrite( headers_size + pixel_data_size, 4 ); // bfSize 98 f << lwrite( 0, 2 ); // bfReserved1 99 f << lwrite( 0, 2 ); // bfReserved2 100 f << lwrite( headers_size, 4 ); // bfOffBits 101 102 // Write the BITMAPINFOHEADER 103 f << lwrite( 40, 4 ); // biSize 104 f << lwrite( columns, 4 ); // biWidth 105 f << lwrite( rows, 4 ); // biHeight 106 f << lwrite( 1, 2 ); // biPlanes 107 f << lwrite( 24, 2 ); // biBitCount 108 f << lwrite( 0, 4 ); // biCompression=BI_RGB 109 f << lwrite( pixel_data_size, 4 ); // biSizeImage 110 f << lwrite( 0, 4 ); // biXPelsPerMeter 111 f << lwrite( 0, 4 ); // biYPelsPerMeter 112 f << lwrite( 0, 4 ); // biClrUsed 113 f << lwrite( 0, 4 ); // biClrImportant 114 115 // Write the pixel data 116 for (unsigned row = rows; row; row--) // bottom-to-top 117 { 118 for (unsigned col = 0; col < columns; col++) // left-to-right 119 { 120 unsigned char red, green, blue; 121 // 122 // This is how we convert an integer value to a color: 123 // by mapping it evenly along the CIECAM02 hue color domain. 124 // 125 // http://en.wikipedia.org/wiki/Hue 126 // http://en.wikipedia.org/wiki/hsl_and_hsv#conversion_from_hsv_to_rgb 127 // 128 // The following algorithm takes a few shortcuts since 129 // both 'value' and 'saturation' are always 1.0. 130 // 131 double hue = (intarray[ row - 1 ][ col ] - min_value) * granularity; 132 int H = (int)( hue / 60 ) % 6; 133 double F = (hue / 60) - H; 134 double Q = 1.0 - F; 135 136 #define c( x ) (255 * x) 137 switch (H) 138 { 139 case 0: red = c(1); green = c(F); blue = c(0); break; 140 case 1: red = c(Q); green = c(1); blue = c(0); break; 141 case 2: red = c(0); green = c(1); blue = c(F); break; 142 case 3: red = c(0); green = c(Q); blue = c(1); break; 143 case 4: red = c(F); green = c(0); blue = c(1); break; 144 default: red = c(1); green = c(0); blue = c(Q); 145 } 146 #undef c 147 148 f.put( static_cast <char> (blue) ) 149 .put( static_cast <char> (green) ) 150 .put( static_cast <char> (red) ); 151 } 152 153 if (padding_size) f << lwrite( 0, padding_size ); 154 } 155 156 // All done! 157 return f.good(); 158 } 159 160 //-------------------------------------------------------------------------- 161 template <typename IntType> 162 bool intarray2bmp( 163 const std::string& filename, 164 IntType* intarray, 165 unsigned rows, 166 unsigned columns, 167 IntType min_value, 168 IntType max_value 169 ) { 170 IntType** ia = new( std::nothrow ) IntType* [ rows ]; 171 for (unsigned row = 0; row < rows; row++) 172 { 173 ia[ row ] = intarray + (row * columns); 174 } 175 bool result = intarray2bmp( 176 filename, ia, rows, columns, min_value, max_value 177 ); 178 delete [] ia; 179 return result; 180 } 181 182 bool boolarray2bmp( 183 const std::string& filename, 184 bool a[ROWS][COLS] 185 ) { 186 187 return intarray2bmp(filename, (bool*)a, ROWS, COLS, false, true); 188 } 189 190 191 } // namespace intarray2bmp 192 193 #endif 194 195 // end intarray2bmp.hpp