Claw  1.7.3
gif_reader.cpp
Go to the documentation of this file.
1 /*
2  CLAW - a C++ Library Absolutely Wonderful
3 
4  CLAW is a free library without any particular aim but being useful to
5  anyone.
6 
7  Copyright (C) 2005-2011 Julien Jorge
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23  contact: julien.jorge@gamned.org
24 */
30 #include <claw/gif.hpp>
31 
32 #include <algorithm>
33 #include <climits>
34 #include <limits>
35 #include <claw/functional.hpp>
36 #include <claw/exception.hpp>
37 #include <claw/it_index.hpp>
38 
39 /*----------------------------------------------------------------------------*/
45 claw::graphic::gif::reader::input_buffer::input_buffer
46 ( std::istream& is, u_int_8 code_size )
47  : m_val(0), m_input(is), m_pending(0), m_pending_bits(0), m_pending_end(0),
48  m_initial_code_size(code_size), m_code_size(m_initial_code_size+1),
49  m_code_limit(1 << m_code_size)
50 {
51  m_input.read
52  ( reinterpret_cast<char*>(&m_next_data_length),
53  sizeof(m_next_data_length) );
54 } // gif::reader::input_buffer::input_buffer()
55 
56 /*----------------------------------------------------------------------------*/
61 bool claw::graphic::gif::reader::input_buffer::end_of_data() const
62 {
63  return (m_val == (unsigned int)(1 << m_initial_code_size))
64  || end_of_information();
65 } // gif::reader::input_buffer::end_of_data()
66 
67 /*----------------------------------------------------------------------------*/
71 bool claw::graphic::gif::reader::input_buffer::end_of_information() const
72 {
73  return !m_input || (m_val == (unsigned int)(1 << m_initial_code_size)+1)
74  || ( (m_next_data_length == 0) // no more data in the stream
75  && (m_pending == m_pending_end) // no more data in the buffer
76  && (m_pending_bits < m_code_size) );
77 } // gif::reader::input_buffer::end_of_information()
78 
79 /*----------------------------------------------------------------------------*/
83 unsigned int claw::graphic::gif::reader::input_buffer::symbols_count() const
84 {
85  return (1 << m_initial_code_size) + 2;
86 } // gif::reader::input_buffer::symbols_count()
87 
88 /*----------------------------------------------------------------------------*/
92 unsigned int claw::graphic::gif::reader::input_buffer::get_next()
93 {
94  if ( m_pending == m_pending_end )
95  fill_buffer();
96  else if ( m_pending_bits + (m_pending_end - m_pending - 1) * CHAR_BIT
97  < m_code_size )
98  fill_buffer();
99 
100  m_val = 0;
101 
102  std::size_t n(m_code_size);
103  unsigned int cur_size = 0;
104  char* buf = reinterpret_cast<char*>(&m_val);
105 
106  while ( (n != 0) && m_input )
107  {
108  while( (m_pending_bits != 0) && (n!=0) && m_input )
109  {
110  unsigned int bits = std::min((std::size_t)m_pending_bits, n);
111 
112  if ( CHAR_BIT - cur_size < bits )
113  bits = CHAR_BIT - cur_size;
114 
115  unsigned int mask = (1 << bits) - 1;
116 
117  *buf |= (m_buffer[m_pending] & mask) << cur_size;
118  cur_size += bits;
119  m_pending_bits -= bits;
120  m_buffer[m_pending] >>= bits;
121  n -= bits;
122 
123  if ( cur_size == CHAR_BIT )
124  {
125  ++buf;
126  cur_size = 0;
127  }
128  }
129 
130  if ( m_pending_bits == 0 )
131  {
132  ++m_pending;
133 
134  if ( (m_pending == m_pending_end) && (n!=0) )
135  fill_buffer();
136 
137  if ( m_pending == m_pending_end )
138  n = 0;
139  else
140  m_pending_bits = CHAR_BIT;
141  }
142  }
143 
144  return m_val;
145 } // gif::reader::input_buffer::get_next()
146 
147 /*----------------------------------------------------------------------------*/
151 void claw::graphic::gif::reader::input_buffer::reset()
152 {
153  m_val = 0;
154  m_code_size = m_initial_code_size+1;
155  m_code_limit = 1 << m_code_size;
156 } // gif::reader::input_buffer::reset()
157 
158 /*----------------------------------------------------------------------------*/
164 void claw::graphic::gif::reader::input_buffer::new_code( unsigned int code )
165 {
166  if ( (code == m_code_limit) && (m_code_size != 12) )
167  {
168  ++m_code_size;
169  m_code_limit = 1 << m_code_size;
170  }
171 } // gif::reader::input_buffer::new_code()
172 
173 /*----------------------------------------------------------------------------*/
177 void claw::graphic::gif::reader::input_buffer::fill_buffer()
178 {
179  // move available data at the begining of the buffer
180  std::copy( m_buffer + m_pending, m_buffer + m_pending_end, m_buffer );
181  m_pending_end = m_pending_end - m_pending;
182  m_pending = 0;
183 
184  if (m_next_data_length != 0)
185  {
186  assert( m_pending_end + m_next_data_length <= sizeof(m_buffer) );
187 
188  m_input.read( m_buffer + m_pending_end, m_next_data_length );
189  m_pending_end += m_next_data_length;
190 
191  if ( (m_pending_bits == 0) && (m_pending != m_pending_end) )
192  m_pending_bits = CHAR_BIT;
193 
194  m_input.read
195  ( reinterpret_cast<char*>(&m_next_data_length),
196  sizeof(m_next_data_length) );
197  }
198 } // gif::reader::input_buffer::fill_buffer()
199 
200 
201 
202 
203 /*----------------------------------------------------------------------------*/
211 claw::graphic::gif::reader::output_buffer::output_buffer
212 ( const palette_type& p, const image_descriptor& id,
213  int transparent_color_index, image& output )
214  : m_palette(p), m_id(id), m_transparent_color_index(transparent_color_index),
215  m_output(output), m_x(0), m_y(0), m_interlace_pass(0),
216  m_interlace_step(8)
217 {
218 
219 } // gif::reader::output_buffer::output_buffer()
220 
221 /*----------------------------------------------------------------------------*/
226 void claw::graphic::gif::reader::output_buffer::write( unsigned int code )
227 {
228  assert(code < m_palette.size());
229  assert(m_x < m_id.width);
230  assert(m_y < m_id.height);
231 
232  m_output[m_y + m_id.top][m_x + m_id.left] = m_palette[code];
233 
234  if ( m_transparent_color_index != -1 )
235  if ( code == (unsigned int)m_transparent_color_index )
236  m_output[m_y + m_id.top][m_x + m_id.left].components.alpha = 0;
237 
238  ++m_x;
239 
240  if (m_x == m_id.width)
241  {
242  m_x = 0;
243 
244  if ( !m_id.is_interlaced() )
245  ++m_y;
246  else
247  {
248  m_y += m_interlace_step;
249 
250  while ( (m_y >= m_id.height) && (m_interlace_pass!=3) )
251  {
252  ++m_interlace_pass;
253  switch (m_interlace_pass)
254  {
255  case 1: m_y = 4; m_interlace_step = 8; break;
256  case 2: m_y = 2; m_interlace_step = 4; break;
257  case 3: m_y = 1; m_interlace_step = 2; break;
258  }
259  }
260  }
261  }
262 } // gif::reader::output_buffer::write()
263 
264 
265 
266 
267 /*----------------------------------------------------------------------------*/
273  : m_image(&img)
274 {
275 
276 } // gif::reader::reader()
277 
278 /*----------------------------------------------------------------------------*/
288  : m_image(&img)
289 {
290  load( f );
291 } // gif::reader::reader()
292 
293 /*----------------------------------------------------------------------------*/
300 ( frame_list& frames, std::istream& f )
301  : m_image(NULL)
302 {
303  load( f );
304  frames = m_frame;
305  m_frame.clear();
306 } // gif::reader::reader()
307 
308 /*----------------------------------------------------------------------------*/
319 ( image& img, frame_list& frames, std::istream& f )
320  : m_image(&img)
321 {
322  load( f );
323  frames = m_frame;
324  m_frame.clear();
325 } // gif::reader::reader()
326 
327 /*----------------------------------------------------------------------------*/
332 {
333  clear();
334 } // gif::reader::~reader()
335 
336 /*----------------------------------------------------------------------------*/
341 void claw::graphic::gif::reader::load( std::istream& f )
342 {
343  clear();
344 
345  inside_load(f);
346 
347  if ( !m_frame.empty() && (m_image!=NULL) )
348  *m_image = *m_frame.front();
349 } // gif::reader::load()
350 
351 /*----------------------------------------------------------------------------*/
355 void claw::graphic::gif::reader::clear()
356 {
357  std::for_each
358  ( m_frame.begin(), m_frame.end(), claw::delete_function<frame*>() );
359  m_frame.clear();
360 } // gif::reader::clear()
361 
362 /*----------------------------------------------------------------------------*/
367 void claw::graphic::gif::reader::inside_load( std::istream& f )
368 {
369  std::istream::pos_type init_pos = f.tellg();
370  reader_info info;
371  info.palette = NULL;
372 
373  try
374  {
375  check_if_gif(f);
376 
377  read_screen_descriptor(f, info);
378  read_data(f, info);
379  make_frames(info);
380 
381  delete info.palette;
382  }
383  catch(...)
384  {
385  delete info.palette;
386 
387  f.seekg( init_pos, std::ios_base::beg );
388  throw;
389  }
390 } // gif::reader::inside_load()
391 
392 /*----------------------------------------------------------------------------*/
397 void claw::graphic::gif::reader::make_frames( const reader_info& info )
398 {
399  it_index<frame_list::const_iterator> it(m_frame.begin());
400 
401  frame_list result;
402  std::size_t cumul_count(0);
403  frame cumul(info.sd.screen_width, info.sd.screen_height);
404  frame prev;
405 
406  if ( !info.disposal_method.empty() )
407  {
408  if ( info.disposal_method[0]
409  == graphic_control_extension::dispose_background )
410  fill_background(cumul, info);
411  else
412  std::fill(cumul.begin(), cumul.end(), transparent_pixel);
413  }
414 
415  for ( ; it!=m_frame.end(); ++it )
416  {
417  if ( info.disposal_method[it]
418  == graphic_control_extension::dispose_previous )
419  prev = cumul;
420 
421  cumul.merge(**it);
422  cumul.set_delay( (*it)->get_delay() );
423  ++cumul_count;
424 
425  if ( cumul.get_delay() > 0 )
426  {
427  result.push_back( new frame(cumul) );
428  cumul_count = 0;
429  }
430 
431  switch( info.disposal_method[it] )
432  {
433  case graphic_control_extension::dispose_background:
434  fill_background(cumul, info);
435  break;
436  case graphic_control_extension::dispose_previous:
437  cumul = prev;
438  break;
439  default:
440  { /* nothing to do */ }
441  }
442  }
443 
444  if ( cumul_count != 0 )
445  result.push_back( new frame(cumul) );
446 
447  clear();
448  std::swap( m_frame, result );
449 } // gif::reader::make_frames()
450 
451 /*----------------------------------------------------------------------------*/
457 void claw::graphic::gif::reader::fill_background
458 ( image& img, const reader_info& info ) const
459 {
460  rgba_pixel clr(transparent_pixel);
461 
462  if ( info.sd.has_global_color_table() && (info.palette != NULL) )
463  if (info.sd.background_color < info.palette->size() )
464  clr = (*info.palette)[info.sd.background_color];
465 
466  std::fill( img.begin(), img.end(), clr );
467 } // gif::reader::fill_background()
468 
469 /*----------------------------------------------------------------------------*/
474 void claw::graphic::gif::reader::check_if_gif( std::istream& f ) const
475 {
476  CLAW_PRECOND( !!f );
477 
478  header h;
479  f.read( reinterpret_cast<char*>(&h), sizeof(header) );
480 
481  bool valid = false;
482 
483  if ( f.rdstate() == std::ios_base::goodbit )
484  if ( (h.signature[0] == 'G')
485  && (h.signature[1] == 'I')
486  && (h.signature[2] == 'F')
487  && (h.version[0] == '8')
488  && ( (h.version[1] == '7') || (h.version[1] == '9') )
489  && (h.version[2] == 'a') )
490  valid = true;
491 
492  if ( !valid )
493  throw claw::bad_format( "Not a GIF file." );
494 } // gif::reader::check_if_gif()
495 
496 /*----------------------------------------------------------------------------*/
502 void claw::graphic::gif::reader::read_screen_descriptor
503 ( std::istream& f, reader_info& info )
504 {
505  f.read( reinterpret_cast<char*>(&info.sd), sizeof(screen_descriptor) );
506 
507  if ( info.sd.has_global_color_table() )
508  {
509  info.palette = new palette_type(info.sd.color_palette_size());
510  read_palette(f, *info.palette);
511  }
512 } // gif::reader::read_screen_descriptor()
513 
514 /*----------------------------------------------------------------------------*/
520 void claw::graphic::gif::reader::read_palette
521 ( std::istream& f, palette_type& p ) const
522 {
523  u_int_8 red, green, blue;
524 
525  for (std::size_t i=0; i!=p.size(); ++i)
526  {
527  f.read( reinterpret_cast<char*>(&red), sizeof(u_int_8) );
528  f.read( reinterpret_cast<char*>(&green), sizeof(u_int_8) );
529  f.read( reinterpret_cast<char*>(&blue), sizeof(u_int_8) );
530 
531  p[i].components.red = red;
532  p[i].components.green = green;
533  p[i].components.blue = blue;
534  }
535 } // gif::reader::read_palette()
536 
537 /*----------------------------------------------------------------------------*/
543 void claw::graphic::gif::reader::read_data
544 ( std::istream& f, reader_info& info )
545 {
546  u_int_8 code;
547 
548  do
549  {
550  code = 0;
551  f.read( reinterpret_cast<char*>(&code), sizeof(code) );
552 
553  if (f)
554  switch(code)
555  {
556  case extension::block_id:
557  f.read( reinterpret_cast<char*>(&code), sizeof(code) );
558 
559  if (code == graphic_control_extension::block_label)
560  read_frame_with_gce(f, info);
561  else
562  skip_extension(f);
563 
564  break;
565  case image_descriptor::block_id:
566  read_frame(f, info);
567  break;
568  case trailer::block_id:
569  break;
570  default:
571  throw claw::bad_format( "gif::reader: invalid code" );
572  }
573  }
574  while ( f && (code != trailer::block_id) );
575 } // gif::reader::read_data()
576 
577 /*----------------------------------------------------------------------------*/
583 void claw::graphic::gif::reader::read_frame
584 ( std::istream& f, reader_info& info )
585 {
586  frame* new_frame(NULL);
587 
588  try
589  {
590  new_frame = new frame;
591  read_frame_data(f, info, *new_frame);
592 
593  info.disposal_method.push_back(graphic_control_extension::dispose_none);
594  m_frame.push_back(new_frame);
595  }
596  catch(...)
597  {
598  delete new_frame;
599  throw;
600  }
601 } // gif::reader::read_frame()
602 
603 /*----------------------------------------------------------------------------*/
609 void claw::graphic::gif::reader::read_frame_with_gce
610 ( std::istream& f, reader_info& info )
611 {
612  graphic_control_extension gce;
613  u_int_8 code;
614 
615  f.read( reinterpret_cast<char*>(&gce), sizeof(gce) );
616  f.read( reinterpret_cast<char*>(&code), sizeof(code) );
617 
618  while ( (code == extension::block_id) && f )
619  {
620  f.read( reinterpret_cast<char*>(&code), sizeof(code) );
621 
622  if (code == graphic_control_extension::block_label)
623  f.read( reinterpret_cast<char*>(&gce), sizeof(gce) );
624  else // unknown extension
625  skip_extension(f);
626 
627  // read the code of the following block
628  f.read( reinterpret_cast<char*>(&code), sizeof(code) );
629  }
630 
631  if (code == image_descriptor::block_id)
632  {
633  frame* new_frame = new frame;
634  new_frame->set_delay(gce.delay);
635 
636  info.disposal_method.push_back(gce.get_disposal_method());
637 
638  if ( gce.has_transparent_color() )
639  info.transparent_color_index = gce.transparent_color;
640  else
641  info.transparent_color_index = -1;
642 
643  read_frame_data(f, info, *new_frame);
644  m_frame.push_back(new_frame);
645  }
646 } // gif::reader::read_frame_with_gce()
647 
648 /*----------------------------------------------------------------------------*/
654 void claw::graphic::gif::reader::skip_extension( std::istream& f ) const
655 {
656  u_int_8 block_size(0);
657 
658  f.read( reinterpret_cast<char*>(&block_size), sizeof(block_size) );
659 
660  while ( f && (block_size!=0) )
661  {
662  f.seekg( block_size, std::ios_base::cur );
663  f.read( reinterpret_cast<char*>(&block_size), sizeof(block_size) );
664  }
665 } // gif::reader::skip_extension()
666 
667 /*----------------------------------------------------------------------------*/
676 void claw::graphic::gif::reader::read_frame_data
677 ( std::istream& f, const reader_info& info, frame& the_frame ) const
678 {
679  image_descriptor id;
680 
681  f.read( reinterpret_cast<char*>(&id), sizeof(id) );
682 
683  the_frame.set_size(info.sd.screen_width, info.sd.screen_height);
684 
685  std::fill( the_frame.begin(), the_frame.end(), transparent_pixel );
686 
687  palette_type* palette(info.palette);
688 
689  if ( id.has_color_table() )
690  {
691  palette = new palette_type(id.color_palette_size());
692  read_palette(f, *palette);
693  }
694 
695  decode_data(f, *palette, id, info.transparent_color_index, the_frame);
696 
697  if ( id.has_color_table() )
698  delete palette;
699 } // gif::reader::read_frame_data()
700 
701 /*----------------------------------------------------------------------------*/
712 void claw::graphic::gif::reader::decode_data
713 ( std::istream& f, const palette_type& palette, const image_descriptor& id,
714  int transparent_color_index, frame& the_frame ) const
715 {
716  u_int_8 code_size;
717 
718  f.read( reinterpret_cast<char*>(&code_size), sizeof(code_size) );
719  input_buffer input(f, code_size);
720  output_buffer output(palette, id, transparent_color_index, the_frame);
721 
722  do
723  {
724  gif_lzw_decoder decoder;
725  input.reset();
726  decoder.decode(input, output);
727  }
728  while ( !input.end_of_information() );
729 } // gif::reader::decode_data()