- メインページ
- モジュール
- ネームスペース
- データ構造
- ファイル

- ファイル一覧
- グローバル

bmp.h
説明を見る。
1 //
2 // Copyright (c) 2003-2011, MIST Project, Nagoya University
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification,
6 // are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // 3. Neither the name of the Nagoya University nor the names of its contributors
16 // may be used to endorse or promote products derived from this software
17 // without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
20 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25 // IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
26 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 //
28
33
34 #ifndef __INCLUDE_MIST_BMP__
35 #define __INCLUDE_MIST_BMP__
36
37
38 #ifndef __INCLUDE_MIST_H__
39 #include "../mist.h"
40 #endif
41
42 // カラー画像の設定を読み込む
43 #ifndef __INCLUDE_MIST_COLOR_H__
44 #include "../config/color.h"
45 #endif
46
47 #ifndef __INCLUDE_MIST_ENDIAN__
48 #include "../config/endian.h"
49 #endif
50
51 #ifndef __INCLUDE_MIST_LIMITS__
52 #include "../limits.h"
53 #endif
54
55 #include <cstdio>
56 #include <iostream>
57 #include <string>
58
59 #include <deque>
60 #include <map>
61 #include <algorithm>
62
63
64 // mist名前空間の始まり
65 _MIST_BEGIN
66
67
68 namespace __bmp_controller__
69 {
70 // 構造体内のアライメントを1バイトに設定し，パディングを禁止する
71 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
72 #pragma pack( push, bmp_align, 1 )
73 #endif
74 struct _rgbquad_
75 {
76 enum{ bytes = 4 };
77 unsigned char rgbBlue;
78 unsigned char rgbGreen;
79 unsigned char rgbRed;
80 unsigned char rgbReserved;
81 } _MIST_PACKED;
82
83 struct _bitmapinfoheader_
84 {
85 enum{ bytes = 40 };
86 unsigned int biSize;
87 signed int biWidth;
88 signed int biHeight;
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;
97 } _MIST_PACKED;
98
99 struct _bitmapfileheader_
100 {
101 enum{ bytes = 14 };
102 unsigned short bfType;
103 unsigned int bfSize;
104 unsigned short bfReserved1;
105 unsigned short bfReserved2;
106 unsigned int bfOffBits;
107 } _MIST_PACKED;
108
109 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
110 #pragma pack( pop, bmp_align )
111 #endif
112 // 構造体内のアライメントを1バイトに設定し，パディングを禁止する 〜 ここまで 〜
113
114 template < class T, class Allocator >
115 struct bmp_controller
116 {
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;
120
121 static bool is_supported( size_type bmp_bits )
122 {
123 bool ret = false;
124 switch( bmp_bits )
125 {
126 case 1:
127 case 4:
128 case 8:
129 // case 16:
130 case 24:
131 case 32:
132 ret = true;
133 break;
134
135 default:
136 break;
137 }
138 return( ret );
139 }
140
141 static size_type get_bmp_line_bytes( size_type width, size_type bmp_bits )
142 {
143 switch( bmp_bits )
144 {
145 case 1:
146 {
147 size_type tmp = width / 8;
148 width = width == tmp * 8 ? tmp : tmp + 1;
149 }
150 break;
151
152 case 4:
153 {
154 size_type tmp = width / 2;
155 width = width == tmp * 2 ? tmp : tmp + 1;
156 }
157 break;
158
159 case 8:
160 break;
161
162 case 16:
163 width *= 2;
164 break;
165
166 case 24:
167 width *= 3;
168 break;
169
170 case 32:
171 width *= 4;
172 break;
173
174 default:
175 width = 0;
176 break;
177 }
178 return( width );
179 }
180
181 static size_type get_bmp_palette_num( size_type bmp_bits )
182 {
183 size_type color_num;
184 switch( bmp_bits )
185 {
186 case 1:
187 color_num = 2;
188 break;
189
190 case 4:
191 color_num = 16;
192 break;
193
194 case 8:
195 color_num = 256;
196 break;
197
198 default:
199 color_num = 0;
200 break;
201 }
202 return( color_num );
203 }
204
205 static size_type get_bmp_line_strip( size_type width, size_type bmp_bits )
206 {
207 size_type line_bytes = get_bmp_line_bytes( width, bmp_bits );
208 size_type rest = line_bytes % 4;
209 if( rest == 0 )
210 {
211 return( line_bytes );
212 }
213 else
214 {
215 return( line_bytes + 4 - rest );
216 }
217 }
218
219 static size_type get_bmp_bytes( const array2< T, Allocator > &image, size_type bmp_bits )
220 {
221 return( _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes + _rgbquad_::bytes * get_bmp_palette_num( bmp_bits ) + image.height( ) * get_bmp_line_strip( image.width( ), bmp_bits ) );
222 }
223
224
225 class __PALETTE__
226 {
227 public:
228 unsigned char red;
229 unsigned char green;
230 unsigned char blue;
231 unsigned long value;
232
233 const __PALETTE__ &operator =( const __PALETTE__ &c )
234 {
235 if( this == &c ) return( *this );
236 red = c.red;
237 green = c.green;
238 blue = c.blue;
239 value = c.value;
240 return( *this );
241 }
242 bool operator ==( const __PALETTE__ &c ) const { return( red == c.red && green == c.green && blue == c.blue ); }
243 bool operator <( const __PALETTE__ &c ) const
244 {
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 );
248 return( false );
249 }
250 static bool compare_value( const __PALETTE__ &c1, const __PALETTE__ &c2 ){ return( c1.value > c2.value ); }
251
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 ){ }
253 };
254
255 static double distance( const __PALETTE__ &c1, const __PALETTE__ &c2 )
256 {
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 ) );
258 }
259
260 // 最も基本となる256色のパレットを作成する
261 static void create_default_palette( std::deque< __PALETTE__ > &palette )
262 {
263 int i, j, k;
264
265 palette.clear( );
266
267 for( i = 0 ; i < 6 ; i++ ) /* カラーテーブル作成 */
268 {
269 for( j = 0 ; j < 6 ; j++ )
270 {
271 for( k = 0 ; k < 6 ; k++ )
272 {
273 palette.push_back( __PALETTE__( k * 51, j * 51, i * 51 ) );
274 }
275 }
276 }
277 for( i = 1 ; i < 32 ; i++ )
278 {
279 palette.push_back( __PALETTE__( i * 8, i * 8, i * 8 ) );
280 }
281 palette.push_back( __PALETTE__( 255, 255, 255 ) );
282 }
283
284 static void eliminate_palette( std::deque< __PALETTE__ > &palette, size_type palette_num )
285 {
286 if( palette.size( ) == palette_num ) return;
287 if( palette.size( ) < palette_num )
288 {
289 size_type num = palette_num - palette.size( );
290 for( size_type i = 0 ; i < num ; i++ ) palette.push_back( __PALETTE__( ) );
291 return;
292 }
293
294 // 使用回数の多い順に並べる
295 std::sort( palette.begin( ), palette.end( ), __PALETTE__::compare_value );
296
297 // 先頭から palette_num までのパレットを残す
298 palette.erase( palette.begin( ) + palette_num, palette.end( ) );
299 }
300
301 // カラーパレットを作成
302 static void create_adaptive_palette( const array2< T, Allocator > &image, _rgbquad_ *palette, size_type palette_num )
303 {
304 size_type width = image.width( );
305 size_type height = image.height( );
306
307 std::deque< __PALETTE__ > adaptive_palette;
308 std::map< __PALETTE__, __PALETTE__ > palette_table;
309
310 unsigned char r, g, b;
311 size_type i;
312
313 // 使用されている色を全て列挙する
314 for( i = 0 ; i < width * height ; i++ )
315 {
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 );
320
321 if( palette_table.find( __PALETTE__( r, g, b ) ) != palette_table.end( ) )
322 {
323 palette_table[ __PALETTE__( r, g, b ) ].value += 1;
324 }
325 else
326 {
327 palette_table[ __PALETTE__( r, g, b ) ] = __PALETTE__( r, g, b, 0 );
328 }
329 }
330
331 typename std::map< __PALETTE__, __PALETTE__ >::iterator ite = palette_table.begin( );
332 for( ; ite != palette_table.end( ) ; ++ite )
333 {
334 adaptive_palette.push_back( ite->second );
335 }
336
337 eliminate_palette( adaptive_palette, palette_num );
338
339 // パレットを書き出す
340 for( i = 0 ; i < palette_num ; i++ )
341 {
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;
346 }
347
348 adaptive_palette.clear( );
349 palette_table.clear( );
350 }
351
352 static size_type find_palette_index( const T &pixel, _rgbquad_ *palette, size_type palette_num )
353 {
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 );
359
360 double minimum, distance;
361 size_type k, index = 0;
362 /* 最も近い色を検索 */
363 pr = palette[0].rgbRed;
364 pg = palette[0].rgbGreen;
365 pb = palette[0].rgbBlue;
366
367 /* ピクセルとカラーテーブル要素の距離計算 */
368 minimum = ( r - pr ) * ( r - pr ) + ( g - pg ) * ( g - pg ) + ( b - pb ) * ( b - pb );
369
370 for( k = 1 ; k < palette_num ; k++ )
371 {
372 /* 最も近い色を検索 */
373 pr = palette[k].rgbRed;
374 pg = palette[k].rgbGreen;
375 pb = palette[k].rgbBlue;
376
377 /* ピクセルとカラーテーブル要素の距離計算 */
378 distance = ( r - pr ) * ( r - pr ) + ( g - pg ) * ( g - pg ) + ( b - pb ) * ( b - pb );
379
380 /* 色空間内の距離が最小の色を保存 */
381 if( minimum > distance )
382 {
383 /* これまでで距離最小の色 */
384 minimum = distance; /* 最小値保存 */
385 index = k; /* カラーテーブル番号保存 */
386 }
387 }
388 return( index );
389 }
390
391 static bool convert_from_bmp_data( unsigned char *bmp, size_type num_bytes, array2< T, Allocator > &image )
392 {
393 // ビットマップ用のヘッダの位置を指定する
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 );
397
398 _bitmapfileheader_ &filehead = *pfilehead;
399 _bitmapinfoheader_ &infohead = *pinfohead;
400
401 if( filehead.bfType != 'M' * 256 + 'B' && filehead.bfType != 'm' * 256 + 'b' )
402 {
403 // ビットマップではありません
404 std::cerr << "This is not a bitmap format!" << std::endl;
405 return( false );
406 }
407
408 size_type bmp_bits = infohead.biBitCount;
409 size_type width = infohead.biWidth;
410 size_type height = infohead.biHeight;
411
412 if( infohead.biCompression != 0 )
413 {
414 // 圧縮のかかったビットマップは未サポート
415 std::cerr << "Compressed bitmap format is not supported." << std::endl;
416 return( false );
417 }
418
419 if( !is_supported( bmp_bits ) )
420 {
421 // 未サポートのビットマップ
422 std::cerr << "This format is not supported currently!" << std::endl;
423 return( false );
424 }
425
426 image.resize( width, height );
427
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 );
430
431 if( line_bytes * height > num_bytes - static_cast< size_type >( filehead.bfOffBits ) )
432 {
433 // 不正なビットマップヘッダ
434 // 規定のデータバイト分だけ存在していない
435 std::cerr << "This bitmap has incorrect BMP header." << std::endl;
436 return( false );
437 }
438
439 for( jj = 0 ; jj < height ; jj++ )
440 {
441 j = height - jj - 1;
442 switch( bmp_bits )
443 {
444 case 1:
445 {
446 size_type rest = width % 8;
447 size_type w = ( width - rest ) / 8;
448 size_type index, k;
449 unsigned int pix;
450 for( i = 0 ; i < w ; i++ )
451 {
452 pix = pixel[ i ];
453 for( k = 0 ; k < 8 ; k++ )
454 {
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 );
457 pix <<= 1;
458 }
459 }
460 if( rest > 0 )
461 {
462 pix = pixel[ w ];
463 for( i = 0 ; i < rest ; i++ )
464 {
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 );
467 pix <<= 1;
468 }
469 }
470 }
471 break;
472
473 case 4:
474 {
475 size_type rest = width % 2;
476 size_type w = ( width - rest ) / 2;
477 size_type index;
478 for( i = 0 ; i < w ; i++ )
479 {
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 );
484 }
485 if( rest == 1 )
486 {
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 );
489 }
490 }
491 break;
492
493 case 8:
494 for( i = 0 ; i < width ; i++ )
495 {
496 image( i, j ) = pixel_converter::convert_to( palette[ pixel[ i ] ].rgbRed, palette[ pixel[ i ] ].rgbGreen, palette[ pixel[ i ] ].rgbBlue );
497 }
498 break;
499
500 case 16:
501 break;
502
503 case 24:
504 for( i = 0 ; i < width ; i++ )
505 {
506 image( i, j ) = pixel_converter::convert_to( pixel[ i * 3 + 2 ], pixel[ i * 3 + 1 ], pixel[ i * 3 + 0 ] );
507 }
508 break;
509
510 case 32:
511 for( i = 0 ; i < width ; i++ )
512 {
513 image( i, j ) = pixel_converter::convert_to( pixel[ i * 4 + 2 ], pixel[ i * 4 + 1 ], pixel[ i * 4 + 0 ] );
514 }
515 break;
516
517 default:
518 break;
519 }
520 pixel += line_bytes;
521 }
522
523 return( true );
524 }
525
526 static bool convert_to_bmp_data( const array2< T, Allocator > &image, unsigned char *bmp, size_type bmp_bits )
527 {
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( );
532
533 // 全てのバッファをクリアする
534 memset( bmp, 0, sizeof( unsigned char ) * num_bytes );
535
536 // ビットマップ用のヘッダの位置を指定する
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 );
540
541 _bitmapfileheader_ &filehead = *pfilehead;
542 _bitmapinfoheader_ &infohead = *pinfohead;
543
544 // BITMAPFILEHEADERの情報を設定
545 filehead.bfType = 0x4d42; //'M'*256+'B';
546 filehead.bfSize = static_cast< unsigned int >( num_bytes );
547 filehead.bfOffBits = static_cast< unsigned int >( _bitmapfileheader_::bytes + _bitmapinfoheader_::bytes + _rgbquad_::bytes * color_num );
548
549 // BITMAPINFOHEADER情報をセット
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;
556
557 switch( bmp_bits )
558 {
559 case 1:
560 case 4:
561 case 8:
562 create_adaptive_palette( image, palette, color_num );
563 break;
564 default:
565 break;
566 }
567
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++ )
571 {
572 j = height - jj - 1;
573 switch( bmp_bits )
574 {
575 case 1:
576 {
577 size_type rest = width % 8;
578 size_type w = ( width - rest ) / 8;
579 for( i = 0 ; i < w ; i++ )
580 {
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 );
589 }
590 unsigned char pix = 0;
591 for( i = 0 ; i < rest ; i++ )
592 {
593 pix |= ( static_cast< unsigned char >( find_palette_index( image( w * 8 + i, j ), palette, color_num ) ) & 0x01 ) << ( 7 - i );
594 }
595 pixel[ w ] = pix;
596 }
597 break;
598
599 case 4:
600 {
601 size_type rest = width % 2;
602 size_type w = ( width - rest ) / 2;
603 for( i = 0 ; i < w ; i++ )
604 {
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 ) );
607 }
608 if( rest == 1 )
609 {
610 pixel[ w ] = static_cast< unsigned char >( find_palette_index( image( w * 2 + i, j ), palette, color_num ) ) << 4;
611 }
612 }
613 break;
614
615 case 8:
616 for( i = 0 ; i < width ; i++ )
617 {
618 pixel[ i ] = static_cast< unsigned char >( find_palette_index( image( i, j ), palette, color_num ) );
619 }
620 break;
621
622 case 16:
623 break;
624
625 case 24:
626 for( i = 0 ; i < width ; i++ )
627 {
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 );
632 }
633 break;
634
635 case 32:
636 for( i = 0 ; i < width ; i++ )
637 {
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 );
642 }
643 break;
644
645 default:
646 break;
647 }
648 pixel += line_bytes;
649 }
650
651 return( true );
652 }
653
654 static bool read( array2< T, Allocator > &image, const std::string &filename )
655 {
656 typedef typename array2< T, Allocator >::size_type size_type;
657
658 size_type filesize;
659 FILE *fp;
660 if( ( fp = fopen( filename.c_str( ), "rb" ) ) == NULL ) return( false );
661 // ファイルサイズを取得
662 fseek( fp, 0, SEEK_END );
663 filesize = ftell( fp );
664 fseek( fp, 0, SEEK_SET );
665
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 )
670 {
671 read_size = fread( pointer, sizeof( unsigned char ), 1024, fp );
672 if( read_size < 1024 )
673 {
674 break;
675 }
676 pointer += read_size;
677 }
678 fclose( fp );
679
680 bool ret = convert_from_bmp_data( buff, filesize, image );
681 delete [] buff;
682 return( ret );
683 }
684
685 static bool write( const array2< T, Allocator > &image, const std::string &filename, size_type bmp_bits )
686 {
687 typedef typename array2< T, Allocator >::size_type size_type;
688
689 if( image.width( ) == 0 )
690 {
691 std::cerr << "Image width is zero!" << std::endl;
692 return( false );
693 }
694 else if( image.height( ) == 0 )
695 {
696 std::cerr << "Image height is zero!" << std::endl;
697 return( false );
698 }
699 else if( !is_supported( bmp_bits ) )
700 {
701 std::cerr << "This format is not supported currently!" << std::endl;
702 return( false );
703 }
704
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 );
708
709 if( !ret )
710 {
711 delete [] buff;
712 return( false );
713 }
714
715 FILE *fp;
716 if( ( fp = fopen( filename.c_str( ), "wb" ) ) == NULL )
717 {
718 delete [] buff;
719 return( false );
720 }
721
722
723 // ファイルへ書き出し
724 unsigned char *pointer = buff;
725 size_type write_size = 0, writed_size = 0;
726 while( size > 0 )
727 {
728 write_size = size < 1024 ? size : 1024;
729
730 writed_size = fwrite( pointer, sizeof( unsigned char ), write_size, fp );
731 pointer += writed_size;
732 size -= writed_size;
733 if( write_size != writed_size )
734 {
735 fclose( fp );
736 delete [] buff;
737 return( false );
738 }
739 }
740 fclose( fp );
741
742 delete [] buff;
743 return( true );
744 }
745 };
746 }
747
750
763
764
775 template < class T, class Allocator >
776 bool read_bmp( array2< T, Allocator > &image, const std::string &filename )
777 {
778 return( __bmp_controller__::bmp_controller< T, Allocator >::read( image, filename ) );
779 }
780
781
792 template < class T, class Allocator >
793 bool read_bmp( array2< T, Allocator > &image, const std::wstring &filename )
794 {
795 return( read_bmp( image, wstr2str( filename ) ) );
796 }
797
798
814 template < class T, class Allocator >
815 bool write_bmp( const array2< T, Allocator > &image, const std::string &filename, typename array2< T, Allocator >::size_type bmp_bits = 24 )
816 {
817 return( __bmp_controller__::bmp_controller< T, Allocator >::write( image, filename, bmp_bits ) );
818 }
819
820
836 template < class T, class Allocator >
837 bool write_bmp( const array2< T, Allocator > &image, const std::wstring &filename, typename array2< T, Allocator >::size_type bmp_bits = 24 )
838 {
839 return( write_bmp( image, wstr2str( filename ), bmp_bits ) );
840 }
841
843 // BMP 画像入出力グループの終わり
844
846 // 画像入出力グループの終わり
847
848
849 // mist名前空間の終わり
850 _MIST_END
851
852
853 #endif // __INCLUDE_MIST_BMP__
854