1 /************************************************************************/ 2 /* */ 3 /* Copyright 2002 by Ullrich Koethe */ 4 /* */ 5 /* This file is part of the VIGRA computer vision library. */ 6 /* The VIGRA Website is */ 7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */ 8 /* Please direct questions, bug reports, and contributions to */ 9 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 10 /* vigra@informatik.uni-hamburg.de */ 11 /* */ 12 /* Permission is hereby granted, free of charge, to any person */ 13 /* obtaining a copy of this software and associated documentation */ 14 /* files (the "Software"), to deal in the Software without */ 15 /* restriction, including without limitation the rights to use, */ 16 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 17 /* sell copies of the Software, and to permit persons to whom the */ 18 /* Software is furnished to do so, subject to the following */ 19 /* conditions: */ 20 /* */ 21 /* The above copyright notice and this permission notice shall be */ 22 /* included in all copies or substantial portions of the */ 23 /* Software. */ 24 /* */ 25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 32 /* OTHER DEALINGS IN THE SOFTWARE. */ 33 /* */ 34 /************************************************************************/ 35 36 #include <fstream> 37 #include <stdexcept> 38 #include <vector> 39 #include <algorithm> 40 #include "vigra/config.hxx" 41 #include "vigra/sized_int.hxx" 42 #include "error.hxx" 43 #include "byteorder.hxx" 44 #include "void_vector.hxx" 45 #include "gif.hxx" 46 47 #define BitSet(byte,bit) (((byte) & (bit)) == (bit)) 48 49 namespace vigra { 50 51 namespace { 52 read_data_block(std::ifstream & stream,void_vector<UInt8> & data)53 int read_data_block(std::ifstream & stream, void_vector<UInt8> & data) 54 { 55 int count; 56 57 count = stream.get(); 58 if(!stream.good()) 59 return -1; 60 if(count == 0) 61 return 0; 62 data.resize(count); 63 stream.read( reinterpret_cast< char * >(data.begin()), count); 64 if(!stream.good()) 65 return -1; 66 return count; 67 } 68 69 struct ColorCluster 70 { 71 UInt8 cmin[3], cmax[3]; 72 std::vector<UInt8 *> entries; 73 mutable int largest_dim, largest_diff; 74 75 typedef UInt8 rgb[3]; 76 77 struct ColorSorter 78 { 79 int dim; 80 ColorSortervigra::__anonce5766b20111::ColorCluster::ColorSorter81 ColorSorter(int d) 82 : dim(d) 83 {} 84 operator ()vigra::__anonce5766b20111::ColorCluster::ColorSorter85 bool operator()(UInt8 * l, UInt8 * r) const 86 { 87 return l[dim] < r[dim]; 88 } 89 }; 90 ColorClustervigra::__anonce5766b20111::ColorCluster91 ColorCluster() 92 : largest_dim(-1) 93 { 94 reset_minmax(); 95 } 96 addvigra::__anonce5766b20111::ColorCluster97 void add(UInt8 * entry) 98 { 99 entries.push_back(entry); 100 101 update_minmax(entry); 102 } 103 reset_minmaxvigra::__anonce5766b20111::ColorCluster104 void reset_minmax() 105 { 106 for(int i=0; i<3; ++i) 107 { 108 cmin[i] = 255; 109 cmax[i] = 0; 110 } 111 112 largest_dim = -1; 113 } 114 update_minmaxvigra::__anonce5766b20111::ColorCluster115 void update_minmax(UInt8 * entry) 116 { 117 for(int i=0; i<3; ++i) 118 { 119 if(entry[i] < cmin[i]) 120 cmin[i] = entry[i]; 121 if(cmax[i] < entry[i]) 122 cmax[i] = entry[i]; 123 } 124 125 largest_dim = -1; 126 } 127 update_largestvigra::__anonce5766b20111::ColorCluster128 void update_largest() const 129 { 130 if(largest_dim >= 0) 131 return; 132 largest_diff = cmax[0] - cmin[0]; 133 largest_dim = 0; 134 135 for(int i=1; i<3; ++i) 136 { 137 if(largest_diff < cmax[i] - cmin[i]) 138 { 139 largest_dim = i; 140 largest_diff = cmax[i] - cmin[i]; 141 } 142 } 143 } 144 operator <vigra::__anonce5766b20111::ColorCluster145 bool operator<(ColorCluster const & o) const 146 { 147 update_largest(); 148 o.update_largest(); 149 return largest_diff < o.largest_diff; 150 } 151 splitvigra::__anonce5766b20111::ColorCluster152 void split(ColorCluster & o) 153 { 154 update_largest(); 155 std::sort(entries.begin(), entries.end(), ColorSorter(largest_dim)); 156 157 std::vector<UInt8 *> old_list; 158 old_list.swap(entries); 159 reset_minmax(); 160 161 UInt32 i = 0; 162 for(; i<old_list.size()/2; ++i) 163 { 164 add(old_list[i]); 165 } 166 for(; i<old_list.size(); ++i) 167 { 168 o.add(old_list[i]); 169 } 170 } 171 averagevigra::__anonce5766b20111::ColorCluster172 void average(UInt8 * color) const 173 { 174 UIntBiggest r = 0, g = 0, b = 0; 175 176 for(size_t i=0; i<entries.size(); ++i) 177 { 178 r += entries[i][0]; 179 g += entries[i][1]; 180 b += entries[i][2]; 181 } 182 183 color[0] = (UInt8)(r / entries.size()); 184 color[1] = (UInt8)(g / entries.size()); 185 color[2] = (UInt8)(b / entries.size()); 186 } 187 sizevigra::__anonce5766b20111::ColorCluster188 size_t size() const 189 { 190 return entries.size(); 191 } 192 }; 193 194 find_color_clusters(void_vector<UInt8> & data,std::vector<ColorCluster> & clusters,void_vector<UInt8> & colors)195 void find_color_clusters(void_vector<UInt8> & data, 196 std::vector<ColorCluster> & clusters, void_vector<UInt8> & colors) 197 { 198 size_t count = clusters.size(); 199 size_t size = data.size() / 3; 200 size_t i, current; 201 for(i=0; i<size; ++i) 202 { 203 clusters[0].add(data.begin()+3*i); 204 } 205 206 for(current = 1; current < count; ++current) 207 { 208 size_t largest_index = 0; 209 for(i=1; i<current; ++i) 210 { 211 if(clusters[largest_index] < clusters[i]) 212 { 213 largest_index = i; 214 } 215 } 216 if(clusters[largest_index].size() == 1) 217 break; 218 clusters[largest_index].split(clusters[current]); 219 } 220 221 for(i=0; i<count; ++i) 222 { 223 if(clusters[i].size() == 0) 224 { 225 colors[3*i] = colors[3*i+1] = colors[3*i+2] = 0; 226 } 227 else 228 { 229 clusters[i].average(colors.begin() + 3*i); 230 } 231 } 232 } 233 find_color_indices(void_vector<UInt8> & data,std::vector<ColorCluster> & clusters,void_vector<UInt8> & indices)234 void find_color_indices(void_vector<UInt8> & data, 235 std::vector<ColorCluster> & clusters, void_vector<UInt8> & indices) 236 { 237 size_t count = clusters.size(); 238 UInt8 * base = data.begin(); 239 240 size_t i; 241 for(i=0; i<count; ++i) 242 { 243 for(size_t j=0; j<clusters[i].size(); ++j) 244 { 245 size_t offset = (clusters[i].entries[j] - base) / 3; 246 indices[offset] = static_cast<UInt8>(i); 247 } 248 } 249 } 250 } // anonymous namespace 251 getCodecDesc() const252 CodecDesc GIFCodecFactory::getCodecDesc() const 253 { 254 CodecDesc desc; 255 256 // init file type 257 desc.fileType = "GIF"; 258 259 // init pixel types 260 desc.pixelTypes.resize(1); 261 desc.pixelTypes[0] = "UINT8"; 262 263 // init compression types 264 desc.compressionTypes.resize(0); 265 266 // init magic strings 267 desc.magicStrings.resize(1); 268 desc.magicStrings[0].resize(4); 269 desc.magicStrings[0][0] = 'G'; 270 desc.magicStrings[0][1] = 'I'; 271 desc.magicStrings[0][2] = 'F'; 272 desc.magicStrings[0][3] = '8'; 273 274 // init file extensions 275 desc.fileExtensions.resize(1); 276 desc.fileExtensions[0] = "gif"; 277 278 desc.bandNumbers.resize(2); 279 desc.bandNumbers[0] = 1; 280 desc.bandNumbers[1] = 3; 281 282 return desc; 283 } 284 getDecoder() const285 VIGRA_UNIQUE_PTR<Decoder> GIFCodecFactory::getDecoder() const 286 { 287 return VIGRA_UNIQUE_PTR<Decoder>( new GIFDecoder() ); 288 } 289 getEncoder() const290 VIGRA_UNIQUE_PTR<Encoder> GIFCodecFactory::getEncoder() const 291 { 292 return VIGRA_UNIQUE_PTR<Encoder>( new GIFEncoder() ); 293 } 294 295 struct GIFHeader 296 { 297 // attributes 298 299 UInt16 width, height, maplength; 300 UInt8 bits_per_pixel; 301 bool global_colormap, interlace; 302 303 // methods 304 305 void global_from_stream( std::ifstream & stream, const byteorder & bo ); 306 bool local_from_stream( std::ifstream & stream, const byteorder & bo ); 307 void global_to_stream( std::ofstream & stream, const byteorder & bo ); 308 void local_to_stream( std::ofstream & stream, const byteorder & bo ); 309 }; 310 global_from_stream(std::ifstream & stream,const byteorder & bo)311 void GIFHeader::global_from_stream( std::ifstream & stream, const byteorder & bo ) 312 { 313 UInt8 flag, c, background; 314 read_field( stream, bo, width ); 315 read_field( stream, bo, height ); 316 read_field( stream, bo, flag ); 317 read_field( stream, bo, background ); 318 read_field( stream, bo, c ); 319 global_colormap = BitSet(flag, 0x80); 320 if(global_colormap) 321 { 322 bits_per_pixel = (flag & 0x07)+1; 323 maplength = 3*( 1 << bits_per_pixel); 324 } 325 } 326 global_to_stream(std::ofstream & stream,const byteorder & bo)327 void GIFHeader::global_to_stream( std::ofstream & stream, const byteorder & bo ) 328 { 329 write_field( stream, bo, width ); 330 write_field( stream, bo, height ); 331 write_field( stream, bo, (UInt8)0xf7 ); 332 write_field( stream, bo, (UInt8)0 ); // background 333 write_field( stream, bo, (UInt8)0 ); // must be zero 334 } 335 local_from_stream(std::ifstream & stream,const byteorder & bo)336 bool GIFHeader::local_from_stream( std::ifstream & stream, const byteorder & bo ) 337 { 338 UInt8 c, flag; 339 for ( ; ; ) 340 { 341 c = stream.get(); 342 if(!stream.good() || c == ';') 343 return false; 344 if(c == '!') 345 { 346 void_vector<UInt8> extensions; 347 348 // read and ignore extension data 349 read_field( stream, bo, c ); 350 while (read_data_block(stream, extensions) > 0) /* empty */; 351 } 352 if(c == ',') 353 break; 354 } 355 356 UInt16 x,y; 357 358 read_field( stream, bo, x ); 359 read_field( stream, bo, y ); 360 read_field( stream, bo, width ); 361 read_field( stream, bo, height ); 362 read_field( stream, bo, flag ); 363 interlace=BitSet(flag,0x40); 364 if(BitSet(flag,0x80)) 365 { 366 global_colormap = false; 367 bits_per_pixel = (flag & 0x07)+1; 368 maplength = 3*( 1 << bits_per_pixel); 369 } 370 return true; 371 } 372 local_to_stream(std::ofstream & stream,const byteorder & bo)373 void GIFHeader::local_to_stream( std::ofstream & stream, const byteorder & bo ) 374 { 375 write_field( stream, bo, ',' ); 376 write_field( stream, bo, (UInt16)0 ); // x 377 write_field( stream, bo, (UInt16)0 ); // y 378 write_field( stream, bo, width ); 379 write_field( stream, bo, height ); 380 write_field( stream, bo, (UInt8)0); // use global colormap, no interlace 381 } 382 383 struct GIFDecoderImpl 384 { 385 // attributes 386 387 GIFHeader header; 388 std::ifstream stream; 389 byteorder bo; 390 void_vector< UInt8 > maps, bands; 391 UInt32 components; 392 UInt8 * scanline; 393 394 // methods 395 396 void decodeGIF(); 397 398 // ctor 399 400 GIFDecoderImpl( const std::string & filename ); 401 }; 402 GIFDecoderImpl(const std::string & filename)403 GIFDecoderImpl::GIFDecoderImpl( const std::string & filename ) 404 #ifdef VIGRA_NEED_BIN_STREAMS 405 : stream( filename.c_str(), std::ios::binary ), 406 #else 407 : stream( filename.c_str() ), 408 #endif 409 bo("little endian"), 410 maps(0), 411 bands(0), 412 scanline(0) 413 { 414 if(!stream.good()) 415 { 416 std::string msg("Unable to open file '"); 417 msg += filename; 418 msg += "'."; 419 vigra_precondition(0, msg.c_str()); 420 } 421 422 // read the magic number 423 char buf[6]; 424 read_array( stream, bo, buf, 6 ); 425 std::string magic(6, (std::string::value_type)0); 426 427 std::copy(buf, buf + 6, magic.begin()); 428 vigra_precondition( magic == "GIF87a" || magic == "GIF89a", 429 "the stored magic number is invalid" ); 430 431 // read the header 432 header.global_from_stream( stream, bo ); 433 434 // read the global color map, if there is one 435 if (header.global_colormap) 436 { 437 // read the maps 438 maps.resize(header.maplength); 439 read_array( stream, bo, maps.data(), header.maplength ); 440 } 441 442 if(!header.local_from_stream( stream, bo )) 443 { 444 std::string msg("Unable to read file '"); 445 msg += filename; 446 msg += "'."; 447 vigra_precondition(0, msg.c_str()); 448 } 449 450 // read the local color map, if there is one 451 if (!header.global_colormap) 452 { 453 // read the maps 454 maps.resize(header.maplength); 455 read_array( stream, bo, maps.data(), header.maplength ); 456 } 457 458 // check if image is Gray or RGB 459 int i=0; 460 components = 1; 461 for(; i < header.maplength/3; ++i) 462 { 463 if(maps[3*i] != maps[3*i+1] || maps[3*i] != maps[3*i+2]) 464 { 465 components = 3; 466 break; 467 } 468 } 469 } 470 decodeGIF()471 void GIFDecoderImpl::decodeGIF() 472 { 473 #define MaxStackSize 4096 474 #define NullCode (-1) 475 476 int 477 available, 478 clear, 479 code_mask, 480 code_size, 481 end_of_information, 482 in_code, 483 old_code; 484 485 int 486 bits, 487 code, 488 count; 489 490 unsigned long 491 datum; 492 493 void_vector<Int16> prefix(MaxStackSize); 494 void_vector<UInt8> suffix(MaxStackSize); 495 void_vector<UInt8> pixel_stack(MaxStackSize+1); 496 void_vector<UInt8> packet(256); 497 void_vector<UInt16> indices(header.width*header.height); 498 499 UInt8 *c; 500 UInt16 *p = indices.begin(); 501 502 UInt8 503 data_size, 504 first, 505 *top_stack; 506 507 /* 508 Initialize GIF data stream decoder. 509 */ 510 data_size = stream.get(); 511 clear=1 << data_size; 512 end_of_information=clear+1; 513 available=clear+2; 514 old_code=NullCode; 515 code_size=data_size+1; 516 code_mask=(1 << code_size)-1; 517 for (code=0; code < clear; code++) 518 { 519 prefix[code]=0; 520 suffix[code]=code; 521 } 522 /* 523 Decode GIF pixel stream. 524 */ 525 datum=0; 526 bits=0; 527 c=0; 528 count=0; 529 first=0; 530 top_stack=pixel_stack.begin(); 531 while (p < indices.end()) 532 { 533 if (top_stack == pixel_stack.begin()) 534 { 535 if (bits < code_size) 536 { 537 /* 538 Load bytes until there is enough bits for a code. 539 */ 540 if (count == 0) 541 { 542 /* 543 Read a new data block. 544 */ 545 count=read_data_block(stream, packet); 546 if (count <= 0) 547 break; 548 c=packet.begin(); 549 } 550 datum+=(*c) << bits; 551 bits+=8; 552 c++; 553 count--; 554 continue; 555 } 556 /* 557 Get the next code. 558 */ 559 code=datum & code_mask; 560 datum>>=code_size; 561 bits-=code_size; 562 /* 563 Interpret the code 564 */ 565 if ((code > available) || (code == end_of_information)) 566 break; 567 if (code == clear) 568 { 569 /* 570 Reset decoder. 571 */ 572 code_size=data_size+1; 573 code_mask=(1 << code_size)-1; 574 available=clear+2; 575 old_code=NullCode; 576 continue; 577 } 578 if (old_code == NullCode) 579 { 580 *top_stack++=suffix[code]; 581 old_code=code; 582 first=code; 583 continue; 584 } 585 in_code=code; 586 if (code == available) 587 { 588 *top_stack++=first; 589 code=old_code; 590 } 591 while (code > clear) 592 { 593 *top_stack++=suffix[code]; 594 code=prefix[code]; 595 } 596 first=suffix[code]; 597 /* 598 Add a new string to the string table, 599 */ 600 if (available >= MaxStackSize) 601 break; 602 *top_stack++=first; 603 prefix[available]=old_code; 604 suffix[available]=first; 605 available++; 606 if (((available & code_mask) == 0) && (available < MaxStackSize)) 607 { 608 code_size++; 609 code_mask+=available; 610 } 611 old_code=in_code; 612 } 613 /* 614 Pop a pixel off the pixel stack. 615 */ 616 top_stack--; 617 *p++ =(UInt16) *top_stack; 618 } 619 620 // decode intelaced image 621 if (header.interlace) 622 { 623 void_vector<UInt16> non_interlaced(header.width*header.height); 624 625 int pass, x, y; 626 627 UInt16 *q; 628 629 static int 630 interlace_rate[4] = { 8, 8, 4, 2 }, 631 interlace_start[4] = { 0, 4, 2, 1 }; 632 633 p=indices.begin(); 634 for (pass=0; pass < 4; pass++) 635 { 636 y=interlace_start[pass]; 637 while (y < header.height) 638 { 639 q=non_interlaced.begin()+(y*header.width); 640 for (x=0; x < header.width; x++) 641 { 642 *q=(*p); 643 p++; 644 q++; 645 } 646 y+=interlace_rate[pass]; 647 } 648 } 649 650 swap_void_vector( indices, non_interlaced ); 651 header.interlace = false; 652 } 653 654 // apply colormap 655 bands.resize(header.width*header.height*components); 656 for(int i=0; i<header.width*header.height; ++i) 657 { 658 if(components == 1) 659 { 660 bands[i] = maps[3*indices[i]]; 661 } 662 else 663 { 664 bands[3*i] = maps[3*indices[i]]; 665 bands[3*i+1] = maps[3*indices[i]+1]; 666 bands[3*i+2] = maps[3*indices[i]+2]; 667 } 668 } 669 } 670 init(const std::string & filename)671 void GIFDecoder::init( const std::string & filename ) 672 { 673 pimpl = new GIFDecoderImpl( filename ); 674 } 675 ~GIFDecoder()676 GIFDecoder::~GIFDecoder() 677 { 678 delete pimpl; 679 } 680 getFileType() const681 std::string GIFDecoder::getFileType() const 682 { 683 return "GIF"; 684 } 685 getWidth() const686 unsigned int GIFDecoder::getWidth() const 687 { 688 return pimpl->header.width; 689 } 690 getHeight() const691 unsigned int GIFDecoder::getHeight() const 692 { 693 return pimpl->header.height; 694 } 695 getNumBands() const696 unsigned int GIFDecoder::getNumBands() const 697 { 698 return pimpl->components; 699 } 700 getPixelType() const701 std::string GIFDecoder::getPixelType() const 702 { 703 return "UINT8"; 704 } 705 getOffset() const706 unsigned int GIFDecoder::getOffset() const 707 { 708 return pimpl->components; 709 } 710 currentScanlineOfBand(unsigned int band) const711 const void * GIFDecoder::currentScanlineOfBand( unsigned int band ) const 712 { 713 return pimpl->scanline + band; 714 } 715 nextScanline()716 void GIFDecoder::nextScanline() 717 { 718 if (pimpl->scanline) 719 pimpl->scanline += getWidth()*getNumBands(); 720 else 721 { 722 pimpl->decodeGIF(); 723 pimpl->scanline = pimpl->bands.begin(); 724 } 725 } 726 close()727 void GIFDecoder::close() {} abort()728 void GIFDecoder::abort() {} 729 730 struct GIFEncoderImpl 731 { 732 // attributes 733 734 GIFHeader header; 735 std::ofstream stream; 736 byteorder bo; 737 void_vector< UInt8 > bands; 738 void_vector< UInt8 > maps; 739 void_vector< UInt8 > indices; 740 UInt32 components; 741 UInt8 *scanline; 742 bool finalized; 743 744 // methods 745 746 void finalize(); 747 void writeHeader(); 748 void writeColormap(); 749 void writeImageData(); 750 void reduceTo256Colors(); 751 void outputEncodedData(void_vector< UInt8 > &); 752 753 // ctor 754 755 GIFEncoderImpl( const std::string & filename ); 756 }; 757 GIFEncoderImpl(const std::string & filename)758 GIFEncoderImpl::GIFEncoderImpl( const std::string & filename ) 759 #ifdef VIGRA_NEED_BIN_STREAMS 760 : stream( filename.c_str(), std::ios::binary ), 761 #else 762 : stream( filename.c_str() ), 763 #endif 764 bo("little endian"), 765 bands(0), 766 maps(0), 767 indices(0), 768 scanline(0), 769 finalized(false) 770 { 771 if(!stream.good()) 772 { 773 std::string msg("Unable to open file '"); 774 msg += filename; 775 msg += "'."; 776 vigra_precondition(0, msg.c_str()); 777 } 778 // write the magic number 779 write_array( stream, bo, "GIF87a", 6 ); 780 } 781 finalize()782 void GIFEncoderImpl::finalize() 783 { 784 // color depth 785 vigra_precondition( components == 1 || components == 3, 786 "number of bands is not supported" ); 787 } 788 writeHeader()789 void GIFEncoderImpl::writeHeader() 790 { 791 // write the header 792 header.global_to_stream( stream, bo ); 793 writeColormap(); 794 header.local_to_stream( stream, bo ); 795 } 796 writeColormap()797 void GIFEncoderImpl::writeColormap() 798 { 799 write_array( stream, bo, maps.data(), header.maplength ); 800 } 801 writeImageData()802 void GIFEncoderImpl::writeImageData() 803 { 804 stream.put(header.bits_per_pixel); // code size 805 if(components == 3) 806 { 807 outputEncodedData(indices); 808 } 809 else 810 { 811 outputEncodedData(bands); 812 } 813 stream.put(0); // end of raster stream 814 stream.put(';'); // GIF terminator 815 } 816 reduceTo256Colors()817 void GIFEncoderImpl::reduceTo256Colors() 818 { 819 header.bits_per_pixel = 8; 820 header.maplength = 3*256; 821 822 maps.resize(header.maplength); 823 if(components == 3) 824 { 825 std::vector<ColorCluster> clusters(256); 826 find_color_clusters(bands, clusters, maps); 827 indices.resize(header.width*header.height); 828 find_color_indices(bands, clusters, indices); 829 } 830 else 831 { 832 for(int i=0; i<256; ++i) 833 { 834 maps[3*i] = maps[3*i+1] = maps[3*i+2] = i; 835 } 836 } 837 } 838 outputEncodedData(void_vector<UInt8> & indices)839 void GIFEncoderImpl::outputEncodedData(void_vector<UInt8> & indices) 840 { 841 #define MaxCode(number_bits) ((1 << (number_bits))-1) 842 #define MaxHashTable 5003 843 #define MaxGIFBits 12 844 #if defined(HasLZW) 845 #define MaxGIFTable (1 << MaxGIFBits) 846 #else 847 #define MaxGIFTable max_code 848 #endif 849 #define GIFOutputCode(code) \ 850 { \ 851 /* \ 852 Emit a code. \ 853 */ \ 854 if (bits > 0) \ 855 datum|=((long) code << bits); \ 856 else \ 857 datum=(long) code; \ 858 bits+=number_bits; \ 859 while (bits >= 8) \ 860 { \ 861 /* \ 862 Add a character to current packet. \ 863 */ \ 864 packet[byte_count++]=(UInt8) (datum & 0xff); \ 865 if (byte_count >= 254) \ 866 { \ 867 stream.put(byte_count); \ 868 stream.write(reinterpret_cast< char * >(packet.begin()),byte_count); \ 869 byte_count=0; \ 870 } \ 871 datum>>=8; \ 872 bits-=8; \ 873 } \ 874 if (free_code > max_code) \ 875 { \ 876 number_bits++; \ 877 if (number_bits == MaxGIFBits) \ 878 max_code=MaxGIFTable; \ 879 else \ 880 max_code=MaxCode(number_bits); \ 881 } \ 882 } 883 884 int 885 bits, 886 byte_count, 887 number_bits, 888 data_size = header.bits_per_pixel; 889 UInt32 i; 890 891 long 892 datum; 893 894 int k; 895 896 UInt8 *p; 897 898 void_vector<Int16> hash_code(MaxHashTable); 899 void_vector<Int16> hash_prefix(MaxHashTable); 900 void_vector<Int16> hash_suffix(MaxHashTable); 901 902 Int16 903 clear_code, 904 end_of_information_code, 905 free_code, 906 index, 907 max_code, 908 waiting_code; 909 910 void_vector<UInt8> packet(256); 911 912 /* 913 Initialize GIF encoder. 914 */ 915 number_bits=data_size+1; 916 max_code=MaxCode(number_bits); 917 clear_code=((Int16) 1 << data_size); 918 end_of_information_code=clear_code+1; 919 free_code=clear_code+2; 920 byte_count=0; 921 datum=0; 922 bits=0; 923 for (i=0; i < MaxHashTable; i++) 924 hash_code[i]=0; 925 GIFOutputCode(clear_code); 926 /* 927 Encode pixels. 928 */ 929 p=indices.begin(); 930 waiting_code=*p; 931 for (i=0; i < indices.size(); i++) 932 { 933 if(i > 0) 934 { 935 /* 936 Probe hash table. 937 */ 938 index=*p & 0xff; 939 k=(int) ((int) index << (MaxGIFBits-8))+waiting_code; 940 if (k >= MaxHashTable) 941 k-=MaxHashTable; 942 GIFOutputCode(waiting_code); 943 if (free_code < MaxGIFTable) 944 { 945 hash_code[k]=free_code++; 946 hash_prefix[k]=waiting_code; 947 hash_suffix[k]=index; 948 } 949 else 950 { 951 /* 952 Fill the hash table with empty entries. 953 */ 954 for (k=0; k < MaxHashTable; k++) 955 hash_code[k]=0; 956 /* 957 Reset compressor and issue a clear code. 958 */ 959 free_code=clear_code+2; 960 GIFOutputCode(clear_code); 961 number_bits=data_size+1; 962 max_code=MaxCode(number_bits); 963 } 964 waiting_code=index; 965 } 966 p++; 967 } 968 /* 969 Flush out the buffered code. 970 */ 971 GIFOutputCode(waiting_code); 972 GIFOutputCode(end_of_information_code); 973 if (bits > 0) 974 { 975 /* 976 Add a character to current packet. 977 */ 978 packet[byte_count++]=(UInt8) (datum & 0xff); 979 if (byte_count >= 254) 980 { 981 stream.put(byte_count); 982 stream.write(reinterpret_cast< char * >(packet.begin()),byte_count); 983 byte_count=0; 984 } 985 } 986 /* 987 Flush accumulated data. 988 */ 989 if (byte_count > 0) 990 { 991 stream.put(byte_count); 992 stream.write(reinterpret_cast< char * >(packet.begin()),byte_count); 993 } 994 } 995 init(const std::string & filename)996 void GIFEncoder::init( const std::string & filename ) 997 { 998 pimpl = new GIFEncoderImpl(filename); 999 } 1000 ~GIFEncoder()1001 GIFEncoder::~GIFEncoder() 1002 { 1003 delete pimpl; 1004 } 1005 getFileType() const1006 std::string GIFEncoder::getFileType() const 1007 { 1008 return "GIF"; 1009 } 1010 setWidth(unsigned int width)1011 void GIFEncoder::setWidth( unsigned int width ) 1012 { 1013 VIGRA_IMPEX_FINALIZED(pimpl->finalized); 1014 pimpl->header.width = width; 1015 } 1016 setHeight(unsigned int height)1017 void GIFEncoder::setHeight( unsigned int height ) 1018 { 1019 VIGRA_IMPEX_FINALIZED(pimpl->finalized); 1020 pimpl->header.height = height; 1021 } 1022 setNumBands(unsigned int numBands)1023 void GIFEncoder::setNumBands( unsigned int numBands ) 1024 { 1025 VIGRA_IMPEX_FINALIZED(pimpl->finalized); 1026 pimpl->components = numBands; 1027 } 1028 setCompressionType(const std::string &,int)1029 void GIFEncoder::setCompressionType( const std::string & /* comp */, int /* quality */) 1030 { 1031 VIGRA_IMPEX_FINALIZED(pimpl->finalized); 1032 } 1033 setPixelType(const std::string & pixeltype)1034 void GIFEncoder::setPixelType( const std::string & pixeltype ) 1035 { 1036 VIGRA_IMPEX_FINALIZED(pimpl->finalized); 1037 vigra_precondition( pixeltype == "UINT8", 1038 "GIFEncoder::setPixelType(): " 1039 "GIF raster supports only the UINT8 pixeltype" ); 1040 } 1041 getOffset() const1042 unsigned int GIFEncoder::getOffset() const 1043 { 1044 return pimpl->components; 1045 } 1046 finalizeSettings()1047 void GIFEncoder::finalizeSettings() 1048 { 1049 pimpl->finalize(); 1050 pimpl->finalized = true; 1051 } 1052 currentScanlineOfBand(unsigned int band)1053 void * GIFEncoder::currentScanlineOfBand( unsigned int band ) 1054 { 1055 if (!pimpl->scanline) 1056 { 1057 pimpl->bands.resize(pimpl->header.width*pimpl->header.height*pimpl->components); 1058 pimpl->scanline = pimpl->bands.begin(); 1059 } 1060 return pimpl->scanline + band; 1061 } 1062 nextScanline()1063 void GIFEncoder::nextScanline() 1064 { 1065 pimpl->scanline += pimpl->header.width*pimpl->components; 1066 } 1067 close()1068 void GIFEncoder::close() 1069 { 1070 pimpl->reduceTo256Colors(); 1071 pimpl->writeHeader(); 1072 pimpl->writeImageData(); 1073 } 1074 abort()1075 void GIFEncoder::abort() {} 1076 } 1077