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

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

gif.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
61
62 #ifndef __INCLUDE_MIST_GIF__
63 #define __INCLUDE_MIST_GIF__
64
65
66 #ifndef __INCLUDE_MIST_H__
67 #include "../mist.h"
68 #endif
69
70 // カラー画像の設定を読み込む
71 #ifndef __INCLUDE_MIST_COLOR_H__
72 #include "../config/color.h"
73 #endif
74
75 #ifndef __INCLUDE_MIST_LIMITS__
76 #include "../limits.h"
77 #endif
78
79
80 #include <string>
81 #include <stack>
82
83
84 // mist名前空間の始まり
85 _MIST_BEGIN
86
87
88 namespace __gif_controller__
89 {
90 // 構造体内のアライメントを1バイトに設定し，パディングを禁止する
91 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
92 #pragma pack( push, gif_align, 1 )
93 #endif
94 struct _gif_header_
95 {
96 enum{ bytes = 13 };
97
98 unsigned char signature[ 3 ];
99 unsigned char version[ 3 ];
100
101 unsigned short image_width;
102 unsigned short image_height;
103 unsigned char image_flags;
104 unsigned char background_color_index;
105 unsigned char pixel_aspect_ratio;
106
107 } _MIST_PACKED;
108
109 struct _image_descriptor_
110 {
111 enum{ bytes = 10 };
112
113 unsigned char code;
114 unsigned short left;
115 unsigned short top;
116 unsigned short image_width;
117 unsigned short image_height;
118 unsigned char image_flags;
119
120 } _MIST_PACKED;
121
122 struct _graphic_control_extension_
123 {
124 enum{ bytes = 7 };
125
126 unsigned char code;
127 unsigned char label;
128 unsigned char block_size;
129 unsigned char flags;
130 unsigned short delay_time;
131 unsigned char transparent_color_index;
132
133 } _MIST_PACKED;
134
135 struct _comment_extension_
136 {
137 enum{ bytes = 2 };
138
139 unsigned char code;
140 unsigned char label;
141
142 } _MIST_PACKED;
143
144 struct _plain_text_extension_
145 {
146 enum{ bytes = 15 };
147
148 unsigned char code;
149 unsigned char label;
150 unsigned char block_size;
151 unsigned short left;
152 unsigned short top;
153 unsigned short grid_width;
154 unsigned short grid_height;
155 unsigned char cell_width;
156 unsigned char cell_height;
157 unsigned char text_foreground_color_index;
158 unsigned char text_background_color_index;
159
160 } _MIST_PACKED;
161
162 struct _application_extension_
163 {
164 enum{ bytes = 14 };
165
166 unsigned char code;
167 unsigned char label;
168 unsigned char block_size;
169 unsigned char application_identifier[ 8 ];
170 unsigned char authentication_code[ 3 ];
171
172 } _MIST_PACKED;
173
174
175
176 #if defined(__MIST_MSVC__) || defined(__INTEL_COMPILER)
177 #pragma pack( pop, gif_align )
178 #endif
179 // 構造体内のアライメントを1バイトに設定し，パディングを禁止する 〜 ここまで 〜
180
181 template < class T, class Allocator >
182 struct gif_controller
183 {
184 typedef typename array2< T, Allocator >::size_type size_type;
185 typedef typename array2< T, Allocator >::difference_type difference_type;
186 typedef _pixel_converter_< T > pixel_converter;
187 typedef typename pixel_converter::color_type color_type;
188
189
190 static difference_type decode_LZW( const unsigned char *buff, unsigned char * &out, size_type num_bytes )
191 {
192 difference_type initial_code_size = buff[ 0 ];
193 difference_type clear_code = 1 << initial_code_size;
194 difference_type end_code = clear_code + 1;
195
196 difference_type code_size = initial_code_size + 1;
197 difference_type code_mask = ( 1 << code_size ) - 1;
198 difference_type bits = 0, data = 0, available = 0;
199
200 if( code_size < 3 || 12 < code_size )
201 {
202 // 不適切なLZWの圧縮データである
203 return( -1 );
204 }
205
206 out = new unsigned char[ num_bytes ];
207 memset( out, 0, sizeof( unsigned char ) * num_bytes );
208
209 static difference_type prefix[ 4096 ];
210 static difference_type suffix[ 4096 ];
211 std::stack< difference_type > stack;
212
213 const unsigned char *pointer = buff + 1;
214
215 for( difference_type i = 0 ; i < clear_code ; i++ )
216 {
217 prefix[ i ] = 0;
218 suffix[ i ] = static_cast< unsigned char >( i );
219 }
220
221 difference_type count = 0, code = 0, old_code = -1, first_character = 0;
222 while( pointer < buff + num_bytes )
223 {
224 difference_type num = pointer[ 0 ];
225 pointer++;
226
227 for( difference_type i = 0 ; i < num ; i++ )
228 {
229 difference_type ch = pointer[ i ];
230 data += ch << bits;
231 bits += 8;
232
233 while( bits >= code_size )
234 {
235 code = data & code_mask;
236 data >>= code_size;
237 bits -= code_size;
238
239 if( code == end_code )
240 {
241 // 終了コードが見つかったので，デコード処理を終了する
242 return( pointer - buff + i );
243 }
244
245 if( code == clear_code )
246 {
247 // クリアコードが見つかったので，辞書を初期化する
248 code_size = initial_code_size + 1;
249 code_mask = ( 1 << code_size ) - 1;
250 available = clear_code + 2;
251 old_code = -1;
252 }
253 else if ( old_code == -1 )
254 {
255 out[ count++ ] = static_cast< unsigned char >( suffix[ code ] );
256 first_character = old_code = code;
257 }
258 else if( code > available )
259 {
260 delete [] out;
261 out = NULL;
262 return( -1 );
263 }
264 else
265 {
266 difference_type incode = code;
267 if( code == available )
268 {
269 stack.push( first_character );
270 code = old_code;
271 }
272 while( code > clear_code )
273 {
274 stack.push( suffix[ code ] );
275 code = prefix[ code ];
276 }
277
278 stack.push( first_character = suffix[ code ] );
279 prefix[ available ] = old_code;
280 suffix[ available ] = first_character;
281 available++;
282
283 if( ( ( available & code_mask ) == 0) && ( available < 4096 ) )
284 {
285 code_size++;
286 code_mask += available;
287 }
288
289 old_code = incode;
290 while( !stack.empty( ) )
291 {
292 out[ count++ ] = static_cast< unsigned char >( stack.top( ) );
293 stack.pop( );
294 }
295 }
296 }
297 }
298
299 pointer += num;
300 }
301
302 return( -1 );
303 }
304
305
306 static bool convert_from_gif_data( unsigned char *gif, size_type num_bytes, array2< T, Allocator > &image )
307 {
308 static difference_type _2[ ] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096 };
309
310 // GIF用のヘッダの位置を指定する
311 _gif_header_ *pheader = reinterpret_cast < _gif_header_ * >( gif );
312 _gif_header_ &header = *pheader;
313
314 if( !( header.signature[ 0 ] == 'G' && header.signature[ 1 ] == 'I' && header.signature[ 2 ] == 'F' ) )
315 {
316 // GIFファイルではない
317 return( false );
318 }
319
320 bool global_color_table_flag = ( header.image_flags & 0x80 ) != 0;
321 //difference_type color_resolution = ( header.image_flags & 0x70 ) >> 4;
322 //bool sort_flag = ( header.image_flags & 0x08 ) != 0;
323 difference_type size_of_global_color_table = ( header.image_flags & 0x07 );
324
325 if( size_of_global_color_table < 0 || size_of_global_color_table > 11 )
326 {
327 // GIFファイルではない
328 return( false );
329 }
330
331 difference_type global_color_table_bytes = 3 * _2[ size_of_global_color_table + 1 ];
332
333 difference_type width = header.image_width;
334 difference_type height = header.image_height;
335
336 unsigned char *global_color_map_data = gif + _gif_header_::bytes;
337 unsigned char *pointer = global_color_map_data + ( global_color_table_flag ? global_color_table_bytes : 0 );
338
339 bool ret = true;
340
341 image.resize( width, height );
342
343 bool decode_finished = false;
344 while( pointer < gif + num_bytes && !decode_finished )
345 {
346 switch( pointer[ 0 ] )
347 {
348 case 0x2c:
349 {
350 // 画像を記述している部分を発見
351 _image_descriptor_ *pimage_header = reinterpret_cast < _image_descriptor_ * >( pointer );
352 _image_descriptor_ &image_header = *pimage_header;
353
354 bool local_color_table_flag = ( image_header.image_flags & 0x80 ) != 0;
355 bool interlace_flag = ( image_header.image_flags & 0x40 ) != 0;
356 //bool sort_flag = ( image_header.image_flags & 0x20 ) != 0;
357 //difference_type reserved = ( image_header.image_flags & 0x18 ) >> 3;
358 difference_type size_of_local_color_table = ( image_header.image_flags & 0x07 );
359 difference_type local_color_table_bytes = 3 * _2[ size_of_local_color_table + 1 ];
360
361 difference_type x = image_header.left;
362 difference_type y = image_header.top;
363 difference_type w = image_header.image_width;
364 difference_type h = image_header.image_height;
365
366 if( x + w > width || y + h > height )
367 {
368 // 画像サイズとあっていない！！
369 std::cerr << "Error!!" << std::endl;
370 return( false );
371 }
372
373 unsigned char *local_color_map_data = pointer + _image_descriptor_::bytes;
374 unsigned char *image_data = local_color_map_data + ( local_color_table_flag ? local_color_table_bytes : 0 );
375
376 unsigned char *color_map = local_color_table_flag ? local_color_map_data : global_color_map_data;
377
378 unsigned char *buff = NULL;
379 difference_type num_bytes = decode_LZW( image_data, buff, w * h );
380 unsigned char *p = buff;
381
382 if( num_bytes > 0 )
383 {
384 if( interlace_flag )
385 {
386 // 画像に対して4パスの処理がいるらしい
387 static difference_type interlace_offset[] = { 0, 4, 2, 1 };
388 static difference_type interlace_jump[] = { 8, 8, 4, 2 };
389 for( difference_type k = 0 ; k < 4 ; k++ )
390 {
391 for( difference_type j = y + interlace_offset[ k ] ; j < y + h ; j += interlace_jump[ k ] )
392 {
393 for( difference_type i = x ; i < x + w ; i++ )
394 {
395 difference_type index = *p++;
396 image( i, j ) = pixel_converter::convert_to( color_map[ index * 3 + 0 ], color_map[ index * 3 + 1 ], color_map[ index * 3 + 2 ] );
397 }
398 }
399 }
400 }
401 else
402 {
403 for( difference_type j = y ; j < y + h ; j++ )
404 {
405 for( difference_type i = x ; i < x + w ; i++ )
406 {
407 difference_type index = *p++;
408 image( i, j ) = pixel_converter::convert_to( color_map[ index * 3 + 0 ], color_map[ index * 3 + 1 ], color_map[ index * 3 + 2 ] );
409 }
410 }
411 }
412 }
413 else
414 {
415 std::cerr << "LZW Decode failure." << std::endl;
416 }
417
418 delete [] buff;
419
420 pointer += num_bytes;
421
422 if( x == 0 && y == 0 && w == width && h == height )
423 {
424 // 一番最初のフレームが見つかったので探索を終了する
425 decode_finished = true;
426 break;
427 }
428 }
429 break;
430
431 case 0x21:
432 // エクステンションのコードを識別して，スキップ処理を行う
433 switch( pointer[ 1 ] )
434 {
435 case 0xf9:
436 pointer += _graphic_control_extension_::bytes;
437 break;
438
439 case 0xfe:
440 pointer += _comment_extension_::bytes;
441 break;
442
443 case 0x01:
444 pointer += _plain_text_extension_::bytes;
445 break;
446
447 case 0xff:
448 pointer += _application_extension_::bytes;
449 break;
450
451 default:
452 // 認識不能なエクステンションタグ
453 pointer += 2;
454 break;
455 }
456
457 // ターミネーションブロックの次までスキップする
458 while( *pointer != 0x00 )
459 {
460 pointer++;
461 }
462 pointer++;
463 break;
464
465
466 default:
467 // Data Sub-blocks
468 pointer += pointer[ 0 ] + 1;
469 break;
470 }
471 }
472
473 return( ret );
474 }
475
476 static bool read( array2< T, Allocator > &image, const std::string &filename )
477 {
478 typedef typename array2< T, Allocator >::size_type size_type;
479
480 size_type filesize;
481 FILE *fp;
482 if( ( fp = fopen( filename.c_str( ), "rb" ) ) == NULL ) return( false );
483
484 // ファイルサイズを取得
485 fseek( fp, 0, SEEK_END );
486 filesize = ftell( fp );
487 fseek( fp, 0, SEEK_SET );
488
489 unsigned char *buff = new unsigned char[ filesize + 1 ];
490 unsigned char *pointer = buff;
491 size_type read_size = 0;
492 while( feof( fp ) == 0 )
493 {
494 read_size = fread( pointer, sizeof( unsigned char ), 1024, fp );
495 if( read_size < 1024 )
496 {
497 break;
498 }
499 pointer += read_size;
500 }
501 fclose( fp );
502
503 bool ret = convert_from_gif_data( buff, filesize, image );
504 delete [] buff;
505 return( ret );
506 }
507 };
508 }
509
510
513
521
522
523
535 template < class T, class Allocator >
536 bool read_gif( array2< T, Allocator > &image, const std::string &filename )
537 {
538 return( __gif_controller__::gif_controller< T, Allocator >::read( image, filename ) );
539 }
540
541
553 template < class T, class Allocator >
554 bool read_gif( array2< T, Allocator > &image, const std::wstring &filename )
555 {
556 return( read_gif( image, wstr2str( filename ) ) );
557 }
558
559
561 // GIF 画像入出力グループの終わり
562
564 // 画像入出力グループの終わり
565
566
567 // mist名前空間の終わり
568 _MIST_END
569
570
571 #endif // __INCLUDE_MIST_GIF__
572