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名前空間の始まり
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 

Generated on Wed Nov 12 2014 19:44:15 for MIST by doxygen 1.8.1.2