1 50 51 package org.openlaszlo.iv.flash.util; 52 53 import java.io.*; 54 import java.util.zip.Deflater ; 55 import org.openlaszlo.iv.flash.parser.DataMarker; 56 57 109 110 public class GIFHelper 111 { 112 113 private byte bytePixels []; private int width; private int height; private int bitMask; private int colorMapSize; 119 private InputStream input; private byte data[]; 122 123 128 129 public int getColorTableSize() { 130 return bitMask; 131 } 132 133 public int getWidth() { 134 return width; 135 } 136 137 public int getHeight() { 138 return height; 139 } 140 141 public DataMarker getZlibData() throws IOException { 142 int deflatedSize = deflate(); return new DataMarker(data,0,deflatedSize); 144 } 145 146 public boolean isAlpha() { 147 return (transparentIndex > -1); 148 } 149 150 156 public void doRead( byte[] buffer ) throws IOException { 157 doRead( new ByteArrayInputStream(buffer, 0, buffer.length) ); 158 } 159 160 public void doRead( FlashBuffer fob ) throws IOException { 161 doRead( fob.getInputStream() ); 162 } 163 164 public void doRead( InputStream input ) throws IOException { 165 this.input = input; 166 try { 167 loadGIF(input); 168 } finally { 169 try { 170 input.close(); 171 } catch (IOException ioe) {} 172 } 173 } 174 175 184 private int deflate() throws IOException { 185 int retour = 0; 186 int plus = 0; 187 if (transparentIndex > -1) 188 plus++; 189 int maxpixels = bytePixels.length; 190 int falsewidth = width; 191 int added = 0; 192 if (width % 4 > 0) 193 { 194 while (falsewidth % 4 > 0) 195 { 196 falsewidth++; 197 added++; 198 } 199 maxpixels = falsewidth * height; 200 } 201 byte[] map = new byte[colorMapSize*(3+plus) + maxpixels]; 202 for (int i = 0; i < colorMapSize; i++) 203 { 204 if (transparentIndex > -1) 205 { 206 if (transparentIndex == i) 207 { 208 map[i*(3+plus)] = 0; 209 map[(i*(3+plus))+1] = 0; 210 map[(i*(3+plus))+2] = 0; 211 map[(i*(3+plus))+3] = 0; 212 } 213 else 214 { 215 map[i*(3+plus)] = r[i]; 216 map[(i*(3+plus))+1] = g[i]; 217 map[(i*(3+plus))+2] = b[i]; 218 map[(i*(3+plus))+3] = (byte) 255; 219 } 220 } 221 else 222 { 223 map[i*(3+plus)] = r[i]; 224 map[(i*(3+plus))+1] = g[i]; 225 map[(i*(3+plus))+2] = b[i]; 226 } 227 } 228 if (width % 4 > 0) 229 { 230 byte[] tempPixels = new byte[maxpixels]; 231 int idTemp = 0; 232 int idByte = 0; 233 for (int h = 0; h < height; h++) 234 { 235 for (int w = 0; w < width; w++) 236 tempPixels[idTemp++] = bytePixels[idByte++]; 237 for (int i = 0; i < added; i++) 238 tempPixels[idTemp++] = 0x00; 239 } 240 bytePixels = tempPixels; 241 } 242 System.arraycopy(bytePixels,0,map,(colorMapSize*(3+plus)),bytePixels.length); 243 Deflater def = new Deflater (); 244 def.setInput(map); 245 data = new byte[(colorMapSize*(3+plus))+bytePixels.length]; 246 def.finish(); 247 retour = def.deflate(data); 248 return retour; 249 } 250 251 255 256 258 private int bitOffset = 0; private int XC = 0; private int YC = 0; private int pass = 0; private int ptr = 0; private int oldYC = -1; 265 private byte r [] = new byte [256]; private byte g [] = new byte [256]; private byte b [] = new byte [256]; private int transparentIndex = -1; 270 273 277 private final static String id87 = "GIF87a"; 278 private final static String id89 = "GIF89a"; 279 280 private final static short EGA_PALETTE [][] = { 281 {0,0,0}, {0,0,128}, {0,128,0}, {0,128,128}, 282 {128,0,0}, {128,0,128}, {128,128,0}, {200,200,200}, 283 {100,100,100}, {100,100,255}, {100,255,100}, {100,255,255}, 284 {255,100,100}, {255,100,255}, {255,255,100}, {255,255,255} }; 285 286 private final static byte EXTENSION = 0x21; 287 private final static byte IMAGESEP = 0x2c; 288 private final static byte TRAILER = 0x3b; 289 private final static byte INTERLACEMASK = 0x40; 290 private final static byte COLORMAPMASK = (byte)0x80; 291 292 private void loadGIF (InputStream input) throws IOException 293 { 294 if (!(input instanceof BufferedInputStream)) 295 input = new BufferedInputStream (input); 296 297 DataInputStream dataInput = new DataInputStream (input); 299 300 bitOffset = XC = YC = pass = 0; 302 boolean gotimage = false; 303 boolean gif89 = false; 304 305 byte [] idBytes = new byte [6]; 306 for (int i = 0; i < 6; i++) 307 idBytes [i] = dataInput.readByte (); 308 309 String id = new String (idBytes); 310 if (id.equals (id87)) 311 gif89 = false; 312 else if (id.equals (id89)) 313 gif89 = true; 314 else 315 warning (input, "not a GIF file"); 316 317 byte aByte = dataInput.readByte (); 319 int screenWidth = ((int)aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); aByte = dataInput.readByte (); 321 int screenHeight = ((int)aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); 322 323 aByte = dataInput.readByte (); 324 boolean hasColormap = (aByte & COLORMAPMASK) != 0; 325 326 int bitsPerPixel = (aByte & 7) + 1; 328 colorMapSize = 1 << bitsPerPixel; 330 bitMask = colorMapSize - 1; 332 333 int background = dataInput.readByte () & 0xFF; 335 int aspect = dataInput.readByte () & 0xFF; 336 if (aspect != 0) 337 if (!gif89) 338 warning (input, "corrupt GIF file (screen descriptor)"); 339 340 if (hasColormap) 342 for (int i = 0; i < colorMapSize; i++) 343 { 344 r [i] = dataInput.readByte (); 345 g [i] = dataInput.readByte (); 346 b [i] = dataInput.readByte (); 347 } 348 else 349 { 350 colorMapSize = 256; 351 bitMask = 255; 352 for (int i = 0; i < 256; i++) 356 { 357 r [i] = (byte)EGA_PALETTE [i & 15][0]; 358 g [i] = (byte)EGA_PALETTE [i & 15][1]; 359 b [i] = (byte)EGA_PALETTE [i & 15][2]; 360 } 361 } 362 363 for (int block = 0; 364 (block = dataInput.readByte () & 0xFF) != TRAILER; ) 365 if (block == EXTENSION) 366 { 367 374 int fn, blocksize, aspnum, aspden; 376 377 fn = dataInput.readByte () & 0xFF; 379 380 if (fn == 'R') 381 { 382 int blockSize; 384 385 blocksize = dataInput.readByte () & 0xFF; 386 if (blocksize == 2) 387 { 388 aspnum = dataInput.readByte (); 389 aspden = dataInput.readByte (); 390 if (aspden <= 0 || aspnum <= 0) 391 { 392 aspnum = 393 aspden = 1; 394 } 395 } 396 else 397 dataInput.skipBytes (blocksize); 398 399 while ((blockSize = dataInput.readByte () & 0xFF) > 0) 400 dataInput.skipBytes (blockSize); 402 } 403 else if (fn == 0xFE) 404 { 405 int blockSize; 408 while ((blockSize = dataInput.readByte () & 0xFF) > 0) 409 dataInput.skipBytes (blockSize); 410 411 425 } 426 else if (fn == 0x01) 427 { 428 int blockSize = dataInput.readByte () & 0xFF; 430 int tgLeft = dataInput.readByte () & 0xFF; 431 tgLeft += (dataInput.readByte () & 0xFF) << 8; 432 int tgTop = dataInput.readByte () & 0xFF; 433 tgTop += (dataInput.readByte () & 0xFF) << 8; 434 int tgWidth = dataInput.readByte () & 0xFF; 435 tgWidth += (dataInput.readByte () & 0xFF) << 8; 436 int tgHeight = dataInput.readByte () & 0xFF; 437 tgHeight += (dataInput.readByte () & 0xFF) << 8; 438 int cWidth = dataInput.readByte () & 0xFF; 439 int cHeight = dataInput.readByte () & 0xFF; 440 int fg = dataInput.readByte () & 0xFF; 441 int bg = dataInput.readByte () & 0xFF; 442 443 dataInput.skipBytes (blockSize - 12); 445 while ((blockSize = dataInput.readByte () & 0xFF) != 0) 447 dataInput.skipBytes (blockSize); 448 } 449 else if (fn == 0xF9) 450 { 451 for (int blockSize = 0; 453 (blockSize = dataInput.readByte () & 0xFF) != 0; ) 454 if (blockSize == 4) 456 { 457 int ext1 = (dataInput.readByte () & 0xFF); 458 int ext2 = (dataInput.readByte () & 0xFF); 459 int ext3 = (dataInput.readByte () & 0xFF); 460 int ext4 = (dataInput.readByte () & 0xFF); 461 462 if ((ext1 & 0x01) != 0) 464 transparentIndex = ext4; 465 } 466 else 467 dataInput.skipBytes (blockSize); 468 } 469 else if (fn == 0xFF) 470 { 471 for (int blockSize = 0; 474 (blockSize = dataInput.readByte () & 0xFF) != 0; ) 475 dataInput.skipBytes (blockSize); 476 } 477 else 478 { 479 for (int blockSize = 0; 482 (blockSize = dataInput.readByte () & 0xFF) != 0; ) 483 dataInput.skipBytes (blockSize); 484 } 485 } 486 else if (block == IMAGESEP) 487 { 488 if (gotimage) 489 { 490 dataInput.skipBytes (8); int misc = dataInput.readByte () & 0xFF; 497 if ((misc & 0x80) != 0) 498 for (int i = 0; i < 1 << ((misc & 7) + 1); i++) 500 dataInput.skipBytes (3); 501 502 dataInput.skipBytes (1); 504 for (int blockSize = 0; 506 (blockSize = dataInput.readByte () & 0xFF) != 0; ) 507 dataInput.skipBytes (blockSize); 508 } 509 else 510 { 511 readImage (dataInput, bitsPerPixel, bitMask, hasColormap, gif89); 512 gotimage = true; 513 } 514 } 515 else 516 { 517 String str = "Unknown block type (0x" + Integer.toString (block, 16) + ")"; 520 warning (input, str); 521 break; 522 } 523 524 if (!gotimage) 525 warning (input, "no image data found in GIF file"); 526 } 527 528 private void readImage (DataInputStream dataInput, 529 int bitsPerPixel, 530 int bitMask, 531 boolean hasColormap, 532 boolean gif89) throws IOException 533 { 534 int npixels = 0; 535 int maxpixels = 0; 536 537 byte aByte = dataInput.readByte (); 539 int leftOffset = (aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); 540 aByte = dataInput.readByte (); 541 int topOffset = (aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); 542 aByte = dataInput.readByte (); 543 width = (aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); 544 aByte = dataInput.readByte (); 545 height = (aByte & 0xFF) + 0x100 * (dataInput.readByte () & 0xFF); 546 547 int misc = dataInput.readByte (); boolean interlace = (misc & INTERLACEMASK) != 0; 549 550 if ((misc & 0x80) != 0) 551 for (int i = 0; i < 1 << ((misc & 7) + 1); i++) 552 { 553 r [i] = dataInput.readByte (); 554 g [i] = dataInput.readByte (); 555 b [i] = dataInput.readByte (); 556 } 557 558 559 if (!hasColormap && (misc & 0x80) == 0) 560 { 561 } 563 564 567 int codeSize = dataInput.readByte () & 0xFF; 569 570 int clearCode = (1 << codeSize); int EOFCode = clearCode + 1; int firstFree = clearCode + 2; int freeCode = firstFree; 575 codeSize++; 580 int initCodeSize = codeSize; int maxCode = (1 << codeSize); int readMask = maxCode - 1; 584 ByteArrayOutputStream bos = new ByteArrayOutputStream(10000); 589 byte [] raster = null; 590 for (int blockSize = 0; (blockSize = dataInput.readByte () & 0xFF) != 0; ) 591 { 592 while (blockSize-- > 0) { 593 bos.write(dataInput.readByte()); 594 } 595 } 596 raster = bos.toByteArray(); 597 598 maxpixels = width * height; 600 bytePixels = new byte [maxpixels]; 601 int picptr = 0; 602 603 int prefix [] = new int [4096]; 605 int suffix [] = new int [4096]; 606 int outCode [] = new int [4097]; 608 int outCount = 0; 610 int currentCode; int oldCode = 0; 612 int inCode; 613 int finChar = 0; 614 int code = readCode (dataInput, raster, codeSize, readMask); 617 while (code != EOFCode) 618 { 619 if (code == clearCode) 622 { 623 codeSize = initCodeSize; 624 maxCode = (1 << codeSize); 625 readMask = maxCode - 1; 626 freeCode = firstFree; 627 code = readCode (dataInput, raster, codeSize, readMask); 628 currentCode = oldCode = code; 629 finChar = currentCode & bitMask; 630 if (!interlace) 631 bytePixels [picptr++] = (byte)finChar; 632 else 633 doInterlace (finChar); 634 npixels++; 635 } 636 else 637 { 638 640 if (freeCode >= 4096) 642 break; 643 644 currentCode = inCode = code; 645 646 if (currentCode >= freeCode) 649 { 650 currentCode = oldCode; 651 if (outCount > 4096) 652 break; 653 outCode [outCount++] = finChar; 654 } 655 656 while (currentCode > bitMask) 660 { 661 if (outCount > 4096) 662 break; outCode [outCount++] = suffix [currentCode]; 664 currentCode = prefix[currentCode]; 665 } 666 667 if (outCount > 4096) 668 break; 669 670 finChar = currentCode & bitMask; 672 outCode [outCount++] = finChar; 673 674 677 if (npixels + outCount > maxpixels) 679 outCount = maxpixels - npixels; 680 681 npixels += outCount; 682 if (!interlace) 683 for (int i = outCount - 1; i >= 0; i--) 684 bytePixels [picptr++] = (byte)outCode [i]; 685 else 686 for (int i = outCount - 1; i >= 0; i--) 687 doInterlace (outCode [i]); 688 outCount = 0; 689 690 prefix [freeCode] = oldCode; 692 suffix [freeCode] = finChar; 693 oldCode = inCode; 694 695 699 freeCode++; 700 if (freeCode >= maxCode) 701 { 702 if (codeSize < 12) 703 { 704 codeSize++; 705 maxCode *= 2; 706 readMask = (1 << codeSize) - 1; 707 } 708 } 709 } 710 711 code = readCode (dataInput, raster, codeSize, readMask); 712 if (npixels >= maxpixels) 713 break; 714 } 715 716 if (npixels != maxpixels) 717 { 718 if (!interlace) for (int i = 0; i < maxpixels - npixels; i++) 720 bytePixels [npixels + i] = 0; 721 } 722 723 737 738 746 747 } 749 750 758 private int readCode (DataInputStream input, byte raster [], int codeSize, int readMask) throws IOException 759 { 760 int byteOffset = bitOffset / 8; 761 int inWordOffset = bitOffset % 8; 762 int rawCode = (raster [byteOffset] & 0xFF); 766 if (byteOffset + 1 < raster.length) 767 rawCode += ((raster [byteOffset + 1] & 0xFF) << 8); 768 else if (codeSize + inWordOffset > 8) 769 warning (input, "short raster ? raster.length = " + raster.length 770 + ", codeSize = " + codeSize 771 + ", readMask = " + readMask); 772 774 if ( codeSize >= 8 && byteOffset + 2 < raster.length) 775 rawCode += (raster [byteOffset + 2] & 0xFF) << 16; 776 rawCode >>= (bitOffset % 8); 777 bitOffset += codeSize; 778 return rawCode & readMask; 779 } 780 781 private void doInterlace (int index) 782 { 783 if (oldYC != YC) 784 { 785 ptr = YC * width; 786 oldYC = YC; 787 } 788 789 if (YC < height) 790 bytePixels [ptr++] = (byte)index; 791 792 if (++XC == width) 794 { 795 XC = 0; 799 800 switch (pass) 801 { 802 case 0: 803 YC += 8; 804 if (YC >= height) 805 { 806 pass++; 807 YC = 4; 808 } 809 break; 810 811 case 1: 812 YC += 8; 813 if (YC >= height) 814 { 815 pass++; 816 YC = 2; 817 } 818 break; 819 820 case 2: 821 YC += 4; 822 if (YC >= height) 823 { 824 pass++; 825 YC = 1; 826 } 827 break; 828 829 case 3: 830 YC += 2; 831 break; 832 833 default: 834 break; 835 } 836 } 837 } 838 839 private void warning (InputStream input, String st) throws IOException 840 { 841 throw new IOException ("Warning ! " + input + " : " + st); 842 } 843 } 844 | Popular Tags |