Claw  1.7.0
gif_reader.cpp
Go to the documentation of this file.
00001 /*
00002   CLAW - a C++ Library Absolutely Wonderful
00003 
00004   CLAW is a free library without any particular aim but being useful to 
00005   anyone.
00006 
00007   Copyright (C) 2005-2011 Julien Jorge
00008 
00009   This library is free software; you can redistribute it and/or
00010   modify it under the terms of the GNU Lesser General Public
00011   License as published by the Free Software Foundation; either
00012   version 2.1 of the License, or (at your option) any later version.
00013 
00014   This library is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   Lesser General Public License for more details.
00018 
00019   You should have received a copy of the GNU Lesser General Public
00020   License along with this library; if not, write to the Free Software
00021   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00022 
00023   contact: julien.jorge@gamned.org
00024 */
00030 #include <claw/gif.hpp>
00031 
00032 #include <algorithm>
00033 #include <climits>
00034 #include <limits>
00035 #include <claw/functional.hpp>
00036 #include <claw/exception.hpp>
00037 #include <claw/it_index.hpp>
00038 
00039 /*----------------------------------------------------------------------------*/
00045 claw::graphic::gif::reader::input_buffer::input_buffer
00046 ( std::istream& is, u_int_8 code_size )
00047   : m_val(0), m_input(is), m_pending(0), m_pending_bits(0), m_pending_end(0),
00048     m_initial_code_size(code_size), m_code_size(m_initial_code_size+1),
00049     m_code_limit(1 << m_code_size)
00050 {
00051   m_input.read
00052     ( reinterpret_cast<char*>(&m_next_data_length),
00053       sizeof(m_next_data_length) );
00054 } // gif::reader::input_buffer::input_buffer()
00055 
00056 /*----------------------------------------------------------------------------*/
00061 bool claw::graphic::gif::reader::input_buffer::end_of_data() const
00062 {
00063   return (m_val == (unsigned int)(1 << m_initial_code_size))
00064     || end_of_information();
00065 } // gif::reader::input_buffer::end_of_data()
00066 
00067 /*----------------------------------------------------------------------------*/
00071 bool claw::graphic::gif::reader::input_buffer::end_of_information() const
00072 {
00073   return !m_input || (m_val == (unsigned int)(1 << m_initial_code_size)+1)
00074     || ( (m_next_data_length == 0)             // no more data in the stream
00075          && (m_pending == m_pending_end)       // no more data in the buffer
00076          && (m_pending_bits < m_code_size) );
00077 } // gif::reader::input_buffer::end_of_information()
00078 
00079 /*----------------------------------------------------------------------------*/
00083 unsigned int claw::graphic::gif::reader::input_buffer::symbols_count() const
00084 {
00085   return (1 << m_initial_code_size) + 2;
00086 } // gif::reader::input_buffer::symbols_count()
00087 
00088 /*----------------------------------------------------------------------------*/
00092 unsigned int claw::graphic::gif::reader::input_buffer::get_next()
00093 {
00094   if ( m_pending == m_pending_end )
00095     fill_buffer();
00096   else if ( m_pending_bits + (m_pending_end - m_pending - 1) * CHAR_BIT
00097             < m_code_size )
00098     fill_buffer();
00099 
00100   m_val = 0;
00101 
00102   std::size_t n(m_code_size);
00103   unsigned int cur_size = 0;
00104   char* buf = reinterpret_cast<char*>(&m_val);
00105 
00106   while ( (n != 0) && m_input )
00107     {
00108       while( (m_pending_bits != 0) && (n!=0) && m_input )
00109         {
00110           unsigned int bits = std::min((std::size_t)m_pending_bits, n);
00111 
00112           if ( CHAR_BIT - cur_size < bits )
00113             bits = CHAR_BIT - cur_size;
00114 
00115           unsigned int mask = (1 << bits) - 1;
00116 
00117           *buf |= (m_buffer[m_pending] & mask) << cur_size;
00118           cur_size += bits;
00119           m_pending_bits -= bits;
00120           m_buffer[m_pending] >>= bits;
00121           n -= bits;
00122 
00123           if ( cur_size == CHAR_BIT )
00124             {
00125               ++buf;
00126               cur_size = 0;
00127             }
00128         }
00129 
00130       if ( m_pending_bits == 0 )
00131         {
00132           ++m_pending;
00133 
00134           if ( (m_pending == m_pending_end) && (n!=0) )
00135             fill_buffer();
00136           
00137           if ( m_pending == m_pending_end )
00138             n = 0;
00139           else
00140             m_pending_bits = CHAR_BIT;
00141         }
00142     }
00143 
00144   return m_val;
00145 } // gif::reader::input_buffer::get_next()
00146 
00147 /*----------------------------------------------------------------------------*/
00151 void claw::graphic::gif::reader::input_buffer::reset()
00152 {
00153   m_val = 0;
00154   m_code_size = m_initial_code_size+1;
00155   m_code_limit = 1 << m_code_size;
00156 } // gif::reader::input_buffer::reset()
00157 
00158 /*----------------------------------------------------------------------------*/
00164 void claw::graphic::gif::reader::input_buffer::new_code( unsigned int code )
00165 {
00166   if ( (code == m_code_limit) && (m_code_size != 12) )
00167     {
00168       ++m_code_size;
00169       m_code_limit = 1 << m_code_size;
00170     }
00171 } // gif::reader::input_buffer::new_code()
00172 
00173 /*----------------------------------------------------------------------------*/
00177 void claw::graphic::gif::reader::input_buffer::fill_buffer()
00178 {
00179   // move available data at the begining of the buffer
00180   std::copy( m_buffer + m_pending, m_buffer + m_pending_end, m_buffer );
00181   m_pending_end = m_pending_end - m_pending;
00182   m_pending = 0;
00183 
00184   if (m_next_data_length != 0)
00185     {
00186       assert( m_pending_end + m_next_data_length <= sizeof(m_buffer) );
00187 
00188       m_input.read( m_buffer + m_pending_end, m_next_data_length );
00189       m_pending_end += m_next_data_length;
00190 
00191       if ( (m_pending_bits == 0) && (m_pending != m_pending_end) )
00192         m_pending_bits = CHAR_BIT;
00193 
00194       m_input.read
00195         ( reinterpret_cast<char*>(&m_next_data_length),
00196           sizeof(m_next_data_length) );
00197     }
00198 } // gif::reader::input_buffer::fill_buffer()
00199 
00200 
00201 
00202 
00203 /*----------------------------------------------------------------------------*/
00211 claw::graphic::gif::reader::output_buffer::output_buffer
00212 ( const palette_type& p, const image_descriptor& id,
00213   int transparent_color_index, image& output )
00214   : m_palette(p), m_id(id), m_transparent_color_index(transparent_color_index),
00215     m_output(output), m_x(0), m_y(0), m_interlace_pass(0),
00216     m_interlace_step(8)
00217 {
00218 
00219 } // gif::reader::output_buffer::output_buffer()
00220 
00221 /*----------------------------------------------------------------------------*/
00226 void claw::graphic::gif::reader::output_buffer::write( unsigned int code )
00227 {
00228   assert(code < m_palette.size());
00229   assert(m_x < m_id.width);
00230   assert(m_y < m_id.height);
00231 
00232   m_output[m_y + m_id.top][m_x + m_id.left] = m_palette[code];
00233 
00234   if ( m_transparent_color_index != -1 )
00235     if ( code == (unsigned int)m_transparent_color_index )
00236       m_output[m_y + m_id.top][m_x + m_id.left].components.alpha = 0;
00237 
00238   ++m_x;
00239 
00240   if (m_x == m_id.width)
00241     {
00242       m_x = 0;
00243 
00244       if ( !m_id.is_interlaced() )
00245         ++m_y;
00246       else
00247         {
00248           m_y += m_interlace_step;
00249 
00250           while ( (m_y >= m_id.height) && (m_interlace_pass!=3) )
00251             {
00252               ++m_interlace_pass;
00253               switch (m_interlace_pass)
00254                 {
00255                 case 1: m_y = 4; m_interlace_step = 8; break;
00256                 case 2: m_y = 2; m_interlace_step = 4; break;
00257                 case 3: m_y = 1; m_interlace_step = 2; break;
00258                 }
00259             }
00260         }
00261     }
00262 } // gif::reader::output_buffer::write()
00263 
00264 
00265 
00266 
00267 /*----------------------------------------------------------------------------*/
00272 claw::graphic::gif::reader::reader( image& img )
00273   : m_image(&img)
00274 {
00275 
00276 } // gif::reader::reader()
00277 
00278 /*----------------------------------------------------------------------------*/
00287 claw::graphic::gif::reader::reader( image& img, std::istream& f )
00288   : m_image(&img)
00289 {
00290   load( f );
00291 } // gif::reader::reader()
00292 
00293 /*----------------------------------------------------------------------------*/
00299 claw::graphic::gif::reader::reader
00300 ( frame_list& frames, std::istream& f )
00301   : m_image(NULL) 
00302 {
00303   load( f );
00304   frames = m_frame;
00305   m_frame.clear();
00306 } // gif::reader::reader()
00307 
00308 /*----------------------------------------------------------------------------*/
00318 claw::graphic::gif::reader::reader
00319 ( image& img, frame_list& frames, std::istream& f )
00320   : m_image(&img) 
00321 {
00322   load( f );
00323   frames = m_frame;
00324   m_frame.clear();
00325 } // gif::reader::reader()
00326 
00327 /*----------------------------------------------------------------------------*/
00331 claw::graphic::gif::reader::~reader()
00332 {
00333   clear();
00334 } // gif::reader::~reader()
00335 
00336 /*----------------------------------------------------------------------------*/
00341 void claw::graphic::gif::reader::load( std::istream& f )
00342 {
00343   clear();
00344 
00345   inside_load(f);
00346 
00347   if ( !m_frame.empty() && (m_image!=NULL) )
00348     *m_image = *m_frame.front();
00349 } // gif::reader::load()
00350 
00351 /*----------------------------------------------------------------------------*/
00355 void claw::graphic::gif::reader::clear()
00356 {
00357   std::for_each
00358     ( m_frame.begin(), m_frame.end(), claw::delete_function<frame*>() );
00359   m_frame.clear();
00360 } // gif::reader::clear()
00361 
00362 /*----------------------------------------------------------------------------*/
00367 void claw::graphic::gif::reader::inside_load( std::istream& f )
00368 {
00369   std::istream::pos_type init_pos = f.tellg();
00370   reader_info info;
00371   info.palette = NULL;
00372 
00373   try
00374     {
00375       check_if_gif(f);
00376 
00377       read_screen_descriptor(f, info);
00378       read_data(f, info);
00379       make_frames(info);
00380 
00381       delete info.palette;
00382     }
00383   catch(...)
00384     {
00385       delete info.palette;
00386 
00387       f.seekg( init_pos, std::ios_base::beg );
00388       throw;
00389     }
00390 } // gif::reader::inside_load()
00391 
00392 /*----------------------------------------------------------------------------*/
00397 void claw::graphic::gif::reader::make_frames( const reader_info& info )
00398 {
00399   it_index<frame_list::const_iterator> it(m_frame.begin());
00400 
00401   frame_list result;
00402   std::size_t cumul_count(0);
00403   frame cumul(info.sd.screen_width, info.sd.screen_height);
00404   frame prev;
00405 
00406   if ( !info.disposal_method.empty() )
00407     {
00408       if ( info.disposal_method[0]
00409            == graphic_control_extension::dispose_background )
00410         fill_background(cumul, info);
00411       else
00412         std::fill(cumul.begin(), cumul.end(), transparent_pixel);
00413     }
00414 
00415   for ( ; it!=m_frame.end(); ++it )
00416     {
00417       if ( info.disposal_method[it]
00418            == graphic_control_extension::dispose_previous )
00419         prev = cumul;
00420 
00421       cumul.merge(**it);
00422       cumul.set_delay( (*it)->get_delay() );
00423       ++cumul_count;
00424 
00425       if ( cumul.get_delay() > 0 )
00426         {
00427           result.push_back( new frame(cumul) );
00428           cumul_count = 0;
00429         }
00430 
00431       switch( info.disposal_method[it] )
00432         {
00433         case graphic_control_extension::dispose_background:
00434           fill_background(cumul, info);
00435           break;
00436         case graphic_control_extension::dispose_previous:
00437           cumul = prev;
00438           break;
00439         default:
00440           { /* nothing to do */ }
00441         }
00442     }
00443 
00444   if ( cumul_count != 0 )
00445      result.push_back( new frame(cumul) );
00446 
00447   clear();
00448   std::swap( m_frame, result );
00449 } // gif::reader::make_frames()
00450 
00451 /*----------------------------------------------------------------------------*/
00457 void claw::graphic::gif::reader::fill_background
00458 ( image& img, const reader_info& info ) const
00459 {
00460   rgba_pixel clr(transparent_pixel);
00461 
00462   if ( info.sd.has_global_color_table() && (info.palette != NULL) )
00463     if (info.sd.background_color < info.palette->size() )
00464       clr = (*info.palette)[info.sd.background_color];
00465 
00466   std::fill( img.begin(), img.end(), clr );
00467 } // gif::reader::fill_background()
00468 
00469 /*----------------------------------------------------------------------------*/
00474 void claw::graphic::gif::reader::check_if_gif( std::istream& f ) const
00475 {
00476   CLAW_PRECOND( !!f );
00477 
00478   header h;
00479   f.read( reinterpret_cast<char*>(&h), sizeof(header) );
00480 
00481   bool valid = false;
00482 
00483   if ( f.rdstate() == std::ios_base::goodbit )
00484     if ( (h.signature[0] == 'G')
00485          && (h.signature[1] == 'I')
00486          && (h.signature[2] == 'F')
00487          && (h.version[0] == '8')
00488          && ( (h.version[1] == '7') || (h.version[1] == '9') )
00489          && (h.version[2] == 'a') )
00490         valid = true;
00491 
00492   if ( !valid )
00493     throw claw::bad_format( "Not a GIF file." );
00494 } // gif::reader::check_if_gif()
00495 
00496 /*----------------------------------------------------------------------------*/
00502 void claw::graphic::gif::reader::read_screen_descriptor
00503 ( std::istream& f, reader_info& info )
00504 {
00505   f.read( reinterpret_cast<char*>(&info.sd), sizeof(screen_descriptor) );
00506 
00507   if ( info.sd.has_global_color_table() )
00508     {
00509       info.palette = new palette_type(info.sd.color_palette_size());
00510       read_palette(f, *info.palette);
00511     }
00512 } // gif::reader::read_screen_descriptor()
00513 
00514 /*----------------------------------------------------------------------------*/
00520 void claw::graphic::gif::reader::read_palette
00521 ( std::istream& f, palette_type& p ) const
00522 {
00523   u_int_8 red, green, blue;
00524 
00525   for (std::size_t i=0; i!=p.size(); ++i)
00526     {
00527       f.read( reinterpret_cast<char*>(&red), sizeof(u_int_8) );
00528       f.read( reinterpret_cast<char*>(&green), sizeof(u_int_8) );
00529       f.read( reinterpret_cast<char*>(&blue), sizeof(u_int_8) );
00530       
00531       p[i].components.red = red;
00532       p[i].components.green = green;
00533       p[i].components.blue = blue;
00534     }
00535 } // gif::reader::read_palette()
00536 
00537 /*----------------------------------------------------------------------------*/
00543 void claw::graphic::gif::reader::read_data
00544 ( std::istream& f, reader_info& info )
00545 {
00546   u_int_8 code;
00547 
00548   do
00549     {
00550       code = 0;
00551       f.read( reinterpret_cast<char*>(&code), sizeof(code) );
00552 
00553       if (f)
00554         switch(code)
00555           {
00556           case extension::block_id:
00557             f.read( reinterpret_cast<char*>(&code), sizeof(code) );
00558 
00559             if (code == graphic_control_extension::block_label)
00560               read_frame_with_gce(f, info);
00561             else
00562               skip_extension(f);
00563 
00564             break;
00565           case image_descriptor::block_id:
00566             read_frame(f, info);
00567             break;
00568           case trailer::block_id:
00569             break;
00570           default:
00571             throw claw::bad_format( "gif::reader: invalid code" );
00572           }
00573     }
00574   while ( f && (code != trailer::block_id) );
00575 } // gif::reader::read_data()
00576 
00577 /*----------------------------------------------------------------------------*/
00583 void claw::graphic::gif::reader::read_frame
00584 ( std::istream& f, reader_info& info )
00585 {
00586   frame* new_frame(NULL);
00587 
00588   try
00589     {
00590       new_frame = new frame;
00591       read_frame_data(f, info, *new_frame);
00592 
00593       info.disposal_method.push_back(graphic_control_extension::dispose_none);
00594       m_frame.push_back(new_frame);
00595     }
00596   catch(...)
00597     {
00598       delete new_frame;
00599       throw;
00600     }
00601 } // gif::reader::read_frame()
00602 
00603 /*----------------------------------------------------------------------------*/
00609 void claw::graphic::gif::reader::read_frame_with_gce
00610 ( std::istream& f, reader_info& info )
00611 {
00612   graphic_control_extension gce;
00613   u_int_8 code;
00614 
00615   f.read( reinterpret_cast<char*>(&gce), sizeof(gce) );
00616   f.read( reinterpret_cast<char*>(&code), sizeof(code) );
00617 
00618   while ( (code == extension::block_id) && f )
00619     {
00620       f.read( reinterpret_cast<char*>(&code), sizeof(code) );
00621 
00622       if (code == graphic_control_extension::block_label)
00623         f.read( reinterpret_cast<char*>(&gce), sizeof(gce) );
00624       else // unknown extension
00625         skip_extension(f);
00626 
00627       // read the code of the following block
00628       f.read( reinterpret_cast<char*>(&code), sizeof(code) );
00629     }
00630 
00631   if (code == image_descriptor::block_id)
00632     {
00633       frame* new_frame = new frame;
00634       new_frame->set_delay(gce.delay);
00635 
00636       info.disposal_method.push_back(gce.get_disposal_method());
00637 
00638       if ( gce.has_transparent_color() )
00639         info.transparent_color_index = gce.transparent_color;
00640       else
00641         info.transparent_color_index = -1;
00642 
00643       read_frame_data(f, info, *new_frame);
00644       m_frame.push_back(new_frame);
00645     }
00646 } // gif::reader::read_frame_with_gce()
00647 
00648 /*----------------------------------------------------------------------------*/
00654 void claw::graphic::gif::reader::skip_extension( std::istream& f ) const
00655 {
00656   u_int_8 block_size(0);
00657 
00658   f.read( reinterpret_cast<char*>(&block_size), sizeof(block_size) );
00659 
00660   while ( f && (block_size!=0) )
00661     {
00662       f.seekg( block_size, std::ios_base::cur );
00663       f.read( reinterpret_cast<char*>(&block_size), sizeof(block_size) );
00664     }
00665 } // gif::reader::skip_extension()
00666 
00667 /*----------------------------------------------------------------------------*/
00676 void claw::graphic::gif::reader::read_frame_data
00677 ( std::istream& f, const reader_info& info, frame& the_frame ) const
00678 {
00679   image_descriptor id;
00680 
00681   f.read( reinterpret_cast<char*>(&id), sizeof(id) );
00682 
00683   the_frame.set_size(info.sd.screen_width, info.sd.screen_height);
00684 
00685   std::fill( the_frame.begin(), the_frame.end(), transparent_pixel );
00686 
00687   palette_type* palette(info.palette);
00688 
00689   if ( id.has_color_table() )
00690     {
00691       palette = new palette_type(id.color_palette_size());
00692       read_palette(f, *palette);
00693     }
00694 
00695   decode_data(f, *palette, id, info.transparent_color_index, the_frame);
00696 
00697   if ( id.has_color_table() )
00698     delete palette;
00699 } // gif::reader::read_frame_data()
00700 
00701 /*----------------------------------------------------------------------------*/
00712 void claw::graphic::gif::reader::decode_data
00713 ( std::istream& f, const palette_type& palette, const image_descriptor& id,
00714   int transparent_color_index, frame& the_frame ) const
00715 {
00716   u_int_8 code_size;
00717 
00718   f.read( reinterpret_cast<char*>(&code_size), sizeof(code_size) );
00719   input_buffer input(f, code_size);
00720   output_buffer output(palette, id, transparent_color_index, the_frame);
00721 
00722   do
00723     {
00724       gif_lzw_decoder decoder;
00725       input.reset();
00726       decoder.decode(input, output);
00727     }
00728   while ( !input.end_of_information() );
00729 } // gif::reader::decode_data()