CLAW Library (a C++ Library Absolutely Wonderful) 1.5.5
|
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-2010 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@yahoo.fr 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()