34 #ifndef __INCLUDE_MIST_BMP__
35 #define __INCLUDE_MIST_BMP__
38 #ifndef __INCLUDE_MIST_H__
43 #ifndef __INCLUDE_MIST_COLOR_H__
44 #include "../config/color.h"
47 #ifndef __INCLUDE_MIST_ENDIAN__
48 #include "../config/endian.h"
51 #ifndef __INCLUDE_MIST_LIMITS__
52 #include "../limits.h"
68 namespace __bmp_controller__
71 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
72 #pragma pack( push, bmp_align, 1 )
77 unsigned char rgbBlue;
78 unsigned char rgbGreen;
80 unsigned char rgbReserved;
83 struct _bitmapinfoheader_
89 unsigned short biPlanes;
90 unsigned short biBitCount;
91 unsigned int biCompression;
92 unsigned int biSizeImage;
93 signed int biXPelsPerMeter;
94 signed int biYPelsPerMeter;
95 unsigned int biClrUsed;
96 unsigned int biClrImportant;
99 struct _bitmapfileheader_
102 unsigned short bfType;
104 unsigned short bfReserved1;
105 unsigned short bfReserved2;
106 unsigned int bfOffBits;
109 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
110 #pragma pack( pop, bmp_align )
114 template <
class T,
class Allocator >
115 struct bmp_controller
117 typedef typename array2< T, Allocator >::size_type size_type;
118 typedef _pixel_converter_< T > pixel_converter;
119 typedef typename pixel_converter::color_type color_type;
121 static bool is_supported( size_type bmp_bits )
141 static size_type get_bmp_line_bytes( size_type width, size_type bmp_bits )
147 size_type tmp = width / 8;
148 width = width == tmp * 8 ? tmp : tmp + 1;
154 size_type tmp = width / 2;
155 width = width == tmp * 2 ? tmp : tmp + 1;
181 static size_type get_bmp_palette_num( size_type bmp_bits )
205 static size_type get_bmp_line_strip( size_type width, size_type bmp_bits )
207 size_type line_bytes = get_bmp_line_bytes( width, bmp_bits );
208 size_type rest = line_bytes % 4;
211 return( line_bytes );
215 return( line_bytes + 4 - rest );
219 static size_type get_bmp_bytes(
const array2< T, Allocator > &image, size_type bmp_bits )
221 return( _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes + _rgbquad_::bytes * get_bmp_palette_num( bmp_bits ) + image.height( ) * get_bmp_line_strip( image.width( ), bmp_bits ) );
233 const __PALETTE__ &operator =(
const __PALETTE__ &c )
235 if(
this == &c )
return( *
this );
242 bool operator ==(
const __PALETTE__ &c )
const {
return( red == c.red && green == c.green && blue == c.blue ); }
243 bool operator <(
const __PALETTE__ &c )
const
245 if( red < c.red )
return(
true );
246 if( red != c.red && green < c.green )
return(
true );
247 if( red != c.red && green != c.green && blue < c.blue )
return(
true );
250 static bool compare_value(
const __PALETTE__ &c1,
const __PALETTE__ &c2 ){
return( c1.value > c2.value ); }
252 __PALETTE__(
unsigned char r = 0,
unsigned char g = 0,
unsigned char b = 0,
unsigned long v = 0 ) : red( r ), green( g ), blue( b ), value( v ){ }
255 static double distance(
const __PALETTE__ &c1,
const __PALETTE__ &c2 )
257 return( ( c1.red - c2.red ) * ( c1.red - c2.red ) + ( c1.green - c2.green ) * ( c1.green - c2.green ) + ( c1.blue - c2.blue ) * ( c1.blue - c2.blue ) );
261 static void create_default_palette( std::deque< __PALETTE__ > &palette )
267 for( i = 0 ; i < 6 ; i++ )
269 for( j = 0 ; j < 6 ; j++ )
271 for( k = 0 ; k < 6 ; k++ )
273 palette.push_back( __PALETTE__( k * 51, j * 51, i * 51 ) );
277 for( i = 1 ; i < 32 ; i++ )
279 palette.push_back( __PALETTE__( i * 8, i * 8, i * 8 ) );
281 palette.push_back( __PALETTE__( 255, 255, 255 ) );
284 static void eliminate_palette( std::deque< __PALETTE__ > &palette, size_type palette_num )
286 if( palette.size( ) == palette_num )
return;
287 if( palette.size( ) < palette_num )
289 size_type num = palette_num - palette.size( );
290 for( size_type i = 0 ; i < num ; i++ ) palette.push_back( __PALETTE__( ) );
295 std::sort( palette.begin( ), palette.end( ), __PALETTE__::compare_value );
298 palette.erase( palette.begin( ) + palette_num, palette.end( ) );
302 static void create_adaptive_palette(
const array2< T, Allocator > &image, _rgbquad_ *palette, size_type palette_num )
304 size_type width = image.width( );
305 size_type height = image.height( );
307 std::deque< __PALETTE__ > adaptive_palette;
308 std::map< __PALETTE__, __PALETTE__ > palette_table;
310 unsigned char r, g, b;
314 for( i = 0 ; i < width * height ; i++ )
316 color_type c = pixel_converter::convert_from( image[i] );
317 r =
static_cast< unsigned char >( c.r );
318 g =
static_cast< unsigned char >( c.g );
319 b =
static_cast< unsigned char >( c.b );
321 if( palette_table.find( __PALETTE__( r, g, b ) ) != palette_table.end( ) )
323 palette_table[ __PALETTE__( r, g, b ) ].value += 1;
327 palette_table[ __PALETTE__( r, g, b ) ] = __PALETTE__( r, g, b, 0 );
331 typename std::map< __PALETTE__, __PALETTE__ >::iterator ite = palette_table.begin( );
332 for( ; ite != palette_table.end( ) ; ++ite )
334 adaptive_palette.push_back( ite->second );
337 eliminate_palette( adaptive_palette, palette_num );
340 for( i = 0 ; i < palette_num ; i++ )
342 palette[i].rgbRed = adaptive_palette[i].red;
343 palette[i].rgbGreen = adaptive_palette[i].green;
344 palette[i].rgbBlue = adaptive_palette[i].blue;
345 palette[i].rgbReserved = 0;
348 adaptive_palette.clear( );
349 palette_table.clear( );
352 static size_type find_palette_index(
const T &pixel, _rgbquad_ *palette, size_type palette_num )
354 unsigned char r, g, b, pr, pg, pb;
355 color_type c = pixel_converter::convert_from( pixel );
356 r =
static_cast< unsigned char >( c.r );
357 g =
static_cast< unsigned char >( c.g );
358 b =
static_cast< unsigned char >( c.b );
360 double minimum, distance;
361 size_type k, index = 0;
363 pr = palette[0].rgbRed;
364 pg = palette[0].rgbGreen;
365 pb = palette[0].rgbBlue;
368 minimum = ( r - pr ) * ( r - pr ) + ( g - pg ) * ( g - pg ) + ( b - pb ) * ( b - pb );
370 for( k = 1 ; k < palette_num ; k++ )
373 pr = palette[k].rgbRed;
374 pg = palette[k].rgbGreen;
375 pb = palette[k].rgbBlue;
378 distance = ( r - pr ) * ( r - pr ) + ( g - pg ) * ( g - pg ) + ( b - pb ) * ( b - pb );
381 if( minimum > distance )
391 static bool convert_from_bmp_data(
unsigned char *bmp, size_type num_bytes, array2< T, Allocator > &image )
394 _bitmapfileheader_ *pfilehead = reinterpret_cast < _bitmapfileheader_ * > ( bmp );
395 _bitmapinfoheader_ *pinfohead = reinterpret_cast < _bitmapinfoheader_ * > ( bmp + _bitmapfileheader_::bytes );
396 _rgbquad_ *palette = reinterpret_cast < _rgbquad_ * > ( bmp + _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes );
398 _bitmapfileheader_ &filehead = *pfilehead;
399 _bitmapinfoheader_ &infohead = *pinfohead;
401 if( filehead.bfType !=
'M' * 256 +
'B' && filehead.bfType !=
'm' * 256 +
'b' )
404 std::cerr <<
"This is not a bitmap format!" << std::endl;
408 size_type bmp_bits = infohead.biBitCount;
409 size_type width = infohead.biWidth;
410 size_type height = infohead.biHeight;
412 if( infohead.biCompression != 0 )
415 std::cerr <<
"Compressed bitmap format is not supported." << std::endl;
419 if( !is_supported( bmp_bits ) )
422 std::cerr <<
"This format is not supported currently!" << std::endl;
426 image.resize( width, height );
428 size_type i, j, jj, line_bytes = get_bmp_line_strip( width, bmp_bits );
429 unsigned char *pixel = bmp +
static_cast< size_type
>( filehead.bfOffBits );
431 if( line_bytes * height > num_bytes - static_cast< size_type >( filehead.bfOffBits ) )
435 std::cerr <<
"This bitmap has incorrect BMP header." << std::endl;
439 for( jj = 0 ; jj < height ; jj++ )
446 size_type rest = width % 8;
447 size_type w = ( width - rest ) / 8;
450 for( i = 0 ; i < w ; i++ )
453 for( k = 0 ; k < 8 ; k++ )
455 index = ( pix & 0x80 ) == 0 ? 0 : 1;
456 image( i * 8 + k, j ) = pixel_converter::convert_to( palette[ index ].rgbRed, palette[ index ].rgbGreen, palette[ index ].rgbBlue );
463 for( i = 0 ; i < rest ; i++ )
465 index = ( pix & 0x80 ) == 0 ? 0 : 1;
466 image( w * 8 + i, j ) = pixel_converter::convert_to( palette[ index ].rgbRed, palette[ index ].rgbGreen, palette[ index ].rgbBlue );
475 size_type rest = width % 2;
476 size_type w = ( width - rest ) / 2;
478 for( i = 0 ; i < w ; i++ )
480 index = ( pixel[ i ] >> 4 ) & 0x0f;
481 image( i * 2 + 0, j ) = pixel_converter::convert_to( palette[ index ].rgbRed, palette[ index ].rgbGreen, palette[ index ].rgbBlue );
482 index = ( pixel[ i ] ) & 0x0f;
483 image( i * 2 + 1, j ) = pixel_converter::convert_to( palette[ index ].rgbRed, palette[ index ].rgbGreen, palette[ index ].rgbBlue );
487 index = ( pixel[ w ] >> 4 ) & 0x0f;
488 image( i * 2 + 0, j ) = pixel_converter::convert_to( palette[ index ].rgbRed, palette[ index ].rgbGreen, palette[ index ].rgbBlue );
494 for( i = 0 ; i < width ; i++ )
496 image( i, j ) = pixel_converter::convert_to( palette[ pixel[ i ] ].rgbRed, palette[ pixel[ i ] ].rgbGreen, palette[ pixel[ i ] ].rgbBlue );
504 for( i = 0 ; i < width ; i++ )
506 image( i, j ) = pixel_converter::convert_to( pixel[ i * 3 + 2 ], pixel[ i * 3 + 1 ], pixel[ i * 3 + 0 ] );
511 for( i = 0 ; i < width ; i++ )
513 image( i, j ) = pixel_converter::convert_to( pixel[ i * 4 + 2 ], pixel[ i * 4 + 1 ], pixel[ i * 4 + 0 ] );
526 static bool convert_to_bmp_data(
const array2< T, Allocator > &image,
unsigned char *bmp, size_type bmp_bits )
528 size_type num_bytes = get_bmp_bytes( image, bmp_bits );
529 size_type color_num = get_bmp_palette_num( bmp_bits );
530 size_type width = image.width( );
531 size_type height = image.height( );
534 memset( bmp, 0,
sizeof(
unsigned char ) * num_bytes );
537 _bitmapfileheader_ *pfilehead = reinterpret_cast < _bitmapfileheader_ * > ( bmp );
538 _bitmapinfoheader_ *pinfohead = reinterpret_cast < _bitmapinfoheader_ * > ( bmp + _bitmapfileheader_::bytes );
539 _rgbquad_ *palette = reinterpret_cast < _rgbquad_ * > ( bmp + _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes );
541 _bitmapfileheader_ &filehead = *pfilehead;
542 _bitmapinfoheader_ &infohead = *pinfohead;
545 filehead.bfType = 0x4d42;
546 filehead.bfSize =
static_cast< unsigned int >( num_bytes );
547 filehead.bfOffBits =
static_cast< unsigned int >( _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes + _rgbquad_::bytes * color_num );
550 infohead.biSize = _bitmapinfoheader_::bytes;
551 infohead.biWidth =
static_cast< int >( width );
552 infohead.biHeight =
static_cast< int >( height );
553 infohead.biPlanes = 1;
554 infohead.biBitCount =
static_cast< unsigned short >( bmp_bits );
555 infohead.biCompression = 0;
562 create_adaptive_palette( image, palette, color_num );
568 size_type i, j, jj, line_bytes = get_bmp_line_strip( width, bmp_bits );
569 unsigned char *pixel = bmp + _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes + _rgbquad_::bytes * color_num;
570 for( jj = 0 ; jj < height ; jj++ )
577 size_type rest = width % 8;
578 size_type w = ( width - rest ) / 8;
579 for( i = 0 ; i < w ; i++ )
581 pixel[ i ] = (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 0, j ), palette, color_num ) ) & 0x01 ) << 7;
582 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 1, j ), palette, color_num ) ) & 0x01 ) << 6;
583 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 2, j ), palette, color_num ) ) & 0x01 ) << 5;
584 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 3, j ), palette, color_num ) ) & 0x01 ) << 4;
585 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 4, j ), palette, color_num ) ) & 0x01 ) << 3;
586 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 5, j ), palette, color_num ) ) & 0x01 ) << 2;
587 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 6, j ), palette, color_num ) ) & 0x01 ) << 1;
588 pixel[ i ] |= (
static_cast< unsigned char >( find_palette_index( image( i * 8 + 7, j ), palette, color_num ) ) & 0x01 );
590 unsigned char pix = 0;
591 for( i = 0 ; i < rest ; i++ )
593 pix |= (
static_cast< unsigned char >( find_palette_index( image( w * 8 + i, j ), palette, color_num ) ) & 0x01 ) << ( 7 - i );
601 size_type rest = width % 2;
602 size_type w = ( width - rest ) / 2;
603 for( i = 0 ; i < w ; i++ )
605 pixel[ i ] =
static_cast< unsigned char >( find_palette_index( image( i * 2 + 0, j ), palette, color_num ) ) << 4;
606 pixel[ i ] |=
static_cast< unsigned char >( find_palette_index( image( i * 2 + 1, j ), palette, color_num ) );
610 pixel[ w ] =
static_cast< unsigned char >( find_palette_index( image( w * 2 + i, j ), palette, color_num ) ) << 4;
616 for( i = 0 ; i < width ; i++ )
618 pixel[ i ] =
static_cast< unsigned char >( find_palette_index( image( i, j ), palette, color_num ) );
626 for( i = 0 ; i < width ; i++ )
628 color_type c =
limits_0_255( pixel_converter::convert_from( image( i, j ) ) );
629 pixel[ i * 3 + 0 ] =
static_cast< unsigned char >( c.b );
630 pixel[ i * 3 + 1 ] =
static_cast< unsigned char >( c.g );
631 pixel[ i * 3 + 2 ] =
static_cast< unsigned char >( c.r );
636 for( i = 0 ; i < width ; i++ )
638 color_type c =
limits_0_255( pixel_converter::convert_from( image( i, j ) ) );
639 pixel[ i * 4 + 0 ] =
static_cast< unsigned char >( c.b );
640 pixel[ i * 4 + 1 ] =
static_cast< unsigned char >( c.g );
641 pixel[ i * 4 + 2 ] =
static_cast< unsigned char >( c.r );
654 static bool read( array2< T, Allocator > &image,
const std::string &filename )
656 typedef typename array2< T, Allocator >::size_type size_type;
660 if( ( fp = fopen( filename.c_str( ),
"rb" ) ) == NULL )
return(
false );
662 fseek( fp, 0, SEEK_END );
663 filesize = ftell( fp );
664 fseek( fp, 0, SEEK_SET );
666 unsigned char *buff =
new unsigned char[ filesize + 1 ];
667 unsigned char *pointer = buff;
668 size_type read_size = 0;
669 while( feof( fp ) == 0 )
671 read_size = fread( pointer,
sizeof(
unsigned char ), 1024, fp );
672 if( read_size < 1024 )
676 pointer += read_size;
680 bool ret = convert_from_bmp_data( buff, filesize, image );
685 static bool write(
const array2< T, Allocator > &image,
const std::string &filename, size_type bmp_bits )
687 typedef typename array2< T, Allocator >::size_type size_type;
689 if( image.width( ) == 0 )
691 std::cerr <<
"Image width is zero!" << std::endl;
694 else if( image.height( ) == 0 )
696 std::cerr <<
"Image height is zero!" << std::endl;
699 else if( !is_supported( bmp_bits ) )
701 std::cerr <<
"This format is not supported currently!" << std::endl;
705 size_type size = get_bmp_bytes( image, bmp_bits );
706 unsigned char *buff =
new unsigned char[ size + 1 ];
707 bool ret = convert_to_bmp_data( image, buff, bmp_bits );
716 if( ( fp = fopen( filename.c_str( ),
"wb" ) ) == NULL )
724 unsigned char *pointer = buff;
725 size_type write_size = 0, writed_size = 0;
728 write_size = size < 1024 ? size : 1024;
730 writed_size = fwrite( pointer,
sizeof(
unsigned char ), write_size, fp );
731 pointer += writed_size;
733 if( write_size != writed_size )
775 template <
class T,
class Allocator >
778 return( __bmp_controller__::bmp_controller< T, Allocator >::read( image, filename ) );
792 template <
class T,
class Allocator >
814 template <
class T,
class Allocator >
817 return( __bmp_controller__::bmp_controller< T, Allocator >::write( image, filename, bmp_bits ) );
836 template <
class T,
class Allocator >
853 #endif // __INCLUDE_MIST_BMP__