00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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 }
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 }
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)
00075 && (m_pending == m_pending_end)
00076 && (m_pending_bits < m_code_size) );
00077 }
00078
00079
00083 unsigned int claw::graphic::gif::reader::input_buffer::symbols_count() const
00084 {
00085 return (1 << m_initial_code_size) + 2;
00086 }
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 }
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 }
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 }
00172
00173
00177 void claw::graphic::gif::reader::input_buffer::fill_buffer()
00178 {
00179
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 }
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 }
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 }
00263
00264
00265
00266
00267
00272 claw::graphic::gif::reader::reader( image& img )
00273 : m_image(&img)
00274 {
00275
00276 }
00277
00278
00287 claw::graphic::gif::reader::reader( image& img, std::istream& f )
00288 : m_image(&img)
00289 {
00290 load( f );
00291 }
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 }
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 }
00326
00327
00331 claw::graphic::gif::reader::~reader()
00332 {
00333 clear();
00334 }
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 }
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 }
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 }
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 { }
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 }
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 }
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 }
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 }
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 }
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 }
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 }
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
00625 skip_extension(f);
00626
00627
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 }
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 }
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 }
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 }