1 7 8 package com.sun.imageio.plugins.gif; 9 10 import java.awt.Point ; 11 import java.awt.Rectangle ; 12 import java.awt.image.BufferedImage ; 13 import java.awt.image.DataBuffer ; 14 import java.awt.image.WritableRaster ; 15 import java.io.BufferedInputStream ; 16 import java.io.DataInputStream ; 17 import java.io.EOFException ; 18 import java.io.InputStream ; 19 import java.io.IOException ; 20 import java.nio.ByteOrder ; 21 import java.util.ArrayList ; 22 import java.util.Arrays ; 23 import java.util.Iterator ; 24 import java.util.List ; 25 import javax.imageio.IIOException ; 26 import javax.imageio.ImageReader ; 27 import javax.imageio.ImageReadParam ; 28 import javax.imageio.ImageTypeSpecifier ; 29 import javax.imageio.metadata.IIOMetadata ; 30 import javax.imageio.spi.ImageReaderSpi ; 31 import javax.imageio.stream.ImageInputStream ; 32 33 36 public class GIFImageReader extends ImageReader { 37 38 ImageInputStream stream = null; 40 41 43 boolean gotHeader = false; 45 46 GIFStreamMetadata streamMetadata = null; 48 49 int currIndex = -1; 51 52 GIFImageMetadata imageMetadata = null; 54 55 List imageStartPosition = new ArrayList (); 59 60 int imageMetadataLength; 63 64 int numImages = -1; 66 67 byte[] block = new byte[255]; 69 int blockLength = 0; 70 int bitPos = 0; 71 int nextByte = 0; 72 int initCodeSize; 73 int clearCode; 74 int eofCode; 75 76 int next32Bits = 0; 78 79 boolean lastBlockFound = false; 82 83 BufferedImage theImage = null; 85 86 WritableRaster theTile = null; 88 89 int width = -1, height = -1; 91 92 int streamX = -1, streamY = -1; 94 95 int rowsDone = 0; 97 98 int interlacePass = 0; 100 101 103 static final int[] interlaceIncrement = { 8, 8, 4, 2, -1 }; 105 static final int[] interlaceOffset = { 0, 4, 2, 1, -1 }; 106 107 public GIFImageReader(ImageReaderSpi originatingProvider) { 108 super(originatingProvider); 109 } 110 111 public void setInput(Object input, 113 boolean seekForwardOnly, 114 boolean ignoreMetadata) { 115 super.setInput(input, seekForwardOnly, ignoreMetadata); 116 if (input != null) { 117 if (!(input instanceof ImageInputStream )) { 118 throw new IllegalArgumentException 119 ("input not an ImageInputStream!"); 120 } 121 this.stream = (ImageInputStream )input; 122 } else { 123 this.stream = null; 124 } 125 126 resetStreamSettings(); 128 } 129 130 public int getNumImages(boolean allowSearch) throws IIOException { 131 if (stream == null) { 132 throw new IllegalStateException ("Input not set!"); 133 } 134 if (seekForwardOnly && allowSearch) { 135 throw new IllegalStateException 136 ("seekForwardOnly and allowSearch can't both be true!"); 137 } 138 139 if (numImages > 0) { 140 return numImages; 141 } 142 if (allowSearch) { 143 this.numImages = locateImage(Integer.MAX_VALUE) + 1; 144 } 145 return numImages; 146 } 147 148 private void checkIndex(int imageIndex) { 151 if (imageIndex < minIndex) { 152 throw new IndexOutOfBoundsException ("imageIndex < minIndex!"); 153 } 154 if (seekForwardOnly) { 155 minIndex = imageIndex; 156 } 157 } 158 159 public int getWidth(int imageIndex) throws IIOException { 160 checkIndex(imageIndex); 161 162 int index = locateImage(imageIndex); 163 if (index != imageIndex) { 164 throw new IndexOutOfBoundsException (); 165 } 166 readMetadata(); 167 return imageMetadata.imageWidth; 168 } 169 170 public int getHeight(int imageIndex) throws IIOException { 171 checkIndex(imageIndex); 172 173 int index = locateImage(imageIndex); 174 if (index != imageIndex) { 175 throw new IndexOutOfBoundsException (); 176 } 177 readMetadata(); 178 return imageMetadata.imageHeight; 179 } 180 181 public Iterator getImageTypes(int imageIndex) throws IIOException { 182 checkIndex(imageIndex); 183 184 int index = locateImage(imageIndex); 185 if (index != imageIndex) { 186 throw new IndexOutOfBoundsException (); 187 } 188 readMetadata(); 189 190 List l = new ArrayList (1); 191 192 byte[] colorTable; 193 if (imageMetadata.localColorTable != null) { 194 colorTable = imageMetadata.localColorTable; 195 } else { 196 colorTable = streamMetadata.globalColorTable; 197 } 198 199 int length = colorTable.length/3; 201 int bits; 202 if (length == 2) { 203 bits = 1; 204 } else if (length == 4) { 205 bits = 2; 206 } else if (length == 8 || length == 16) { 207 bits = 4; 209 } else { 210 bits = 8; 212 } 213 int lutLength = 1 << bits; 214 byte[] r = new byte[lutLength]; 215 byte[] g = new byte[lutLength]; 216 byte[] b = new byte[lutLength]; 217 218 int rgbIndex = 0; 220 for (int i = 0; i < length; i++) { 221 r[i] = colorTable[rgbIndex++]; 222 g[i] = colorTable[rgbIndex++]; 223 b[i] = colorTable[rgbIndex++]; 224 } 225 226 byte[] a = null; 227 if (imageMetadata.transparentColorFlag) { 228 a = new byte[lutLength]; 229 Arrays.fill(a, (byte)255); 230 231 int idx = Math.min(imageMetadata.transparentColorIndex, 234 lutLength - 1); 235 a[idx] = (byte)0; 236 } 237 238 int[] bitsPerSample = new int[1]; 239 bitsPerSample[0] = bits; 240 l.add(ImageTypeSpecifier.createIndexed(r, g, b, a, bits, 241 DataBuffer.TYPE_BYTE)); 242 return l.iterator(); 243 } 244 245 public ImageReadParam getDefaultReadParam() { 246 return new ImageReadParam (); 247 } 248 249 public IIOMetadata getStreamMetadata() throws IIOException { 250 readHeader(); 251 return streamMetadata; 252 } 253 254 public IIOMetadata getImageMetadata(int imageIndex) throws IIOException { 255 checkIndex(imageIndex); 256 257 int index = locateImage(imageIndex); 258 if (index != imageIndex) { 259 throw new IndexOutOfBoundsException ("Bad image index!"); 260 } 261 readMetadata(); 262 return imageMetadata; 263 } 264 265 267 private void initNext32Bits() { 268 next32Bits = block[0] & 0xff; 269 next32Bits |= (block[1] & 0xff) << 8; 270 next32Bits |= (block[2] & 0xff) << 16; 271 next32Bits |= block[3] << 24; 272 nextByte = 4; 273 } 274 275 private int getCode(int codeSize, int codeMask) throws IOException { 282 if (bitPos + codeSize > 32) { 283 return eofCode; } 285 286 int code = (next32Bits >> bitPos) & codeMask; 287 bitPos += codeSize; 288 289 while (bitPos >= 8 && !lastBlockFound) { 291 next32Bits >>>= 8; 292 bitPos -= 8; 293 294 if (nextByte >= blockLength) { 296 blockLength = stream.readUnsignedByte(); 298 if (blockLength == 0) { 299 lastBlockFound = true; 300 return code; 301 } else { 302 int left = blockLength; 303 int off = 0; 304 while (left > 0) { 305 int nbytes = stream.read(block, off, left); 306 off += nbytes; 307 left -= nbytes; 308 } 309 nextByte = 0; 310 } 311 } 312 313 next32Bits |= block[nextByte++] << 24; 314 } 315 316 return code; 317 } 318 319 public void initializeStringTable(int[] prefix, 320 byte[] suffix, 321 byte[] initial, 322 int[] length) { 323 int numEntries = 1 << initCodeSize; 324 for (int i = 0; i < numEntries; i++) { 325 prefix[i] = -1; 326 suffix[i] = (byte)i; 327 initial[i] = (byte)i; 328 length[i] = 1; 329 } 330 331 for (int i = numEntries; i < 4096; i++) { 334 prefix[i] = -1; 335 length[i] = 1; 336 } 337 338 } 342 343 Rectangle sourceRegion; 344 int sourceXSubsampling; 345 int sourceYSubsampling; 346 int sourceMinProgressivePass; 347 int sourceMaxProgressivePass; 348 349 Point destinationOffset; 350 Rectangle destinationRegion; 351 352 int updateMinY; 354 int updateYStep; 355 356 boolean decodeThisRow = true; 357 int destY = 0; 358 359 byte[] rowBuf; 360 361 private void outputRow() { 362 int width = Math.min(sourceRegion.width, 364 destinationRegion.width*sourceXSubsampling); 365 int destX = destinationRegion.x; 366 367 if (sourceXSubsampling == 1) { 368 theTile.setDataElements(destX, destY, width, 1, rowBuf); 369 } else { 370 for (int x = 0; x < width; x += sourceXSubsampling, destX++) { 371 theTile.setSample(destX, destY, 0, rowBuf[x] & 0xff); 372 } 373 } 374 375 if (updateListeners != null) { 377 int[] bands = { 0 }; 378 processImageUpdate(theImage, 381 destX, destY, 382 width, 1, 1, updateYStep, 383 bands); 384 } 385 } 386 387 private void computeDecodeThisRow() { 388 this.decodeThisRow = 389 (destY < destinationRegion.y + destinationRegion.height) && 390 (streamY >= sourceRegion.y) && 391 (streamY < sourceRegion.y + sourceRegion.height) && 392 (((streamY - sourceRegion.y) % sourceYSubsampling) == 0); 393 } 394 395 private void outputPixels(byte[] string, int len) { 396 if (interlacePass < sourceMinProgressivePass || 397 interlacePass > sourceMaxProgressivePass) { 398 return; 399 } 400 401 for (int i = 0; i < len; i++) { 402 if (streamX >= sourceRegion.x) { 403 rowBuf[streamX - sourceRegion.x] = string[i]; 404 } 405 406 ++streamX; 408 if (streamX == width) { 409 ++rowsDone; 411 processImageProgress(100.0F*rowsDone/height); 412 413 if (decodeThisRow) { 414 outputRow(); 415 } 416 417 streamX = 0; 418 if (imageMetadata.interlaceFlag) { 419 streamY += interlaceIncrement[interlacePass]; 420 if (streamY >= height) { 421 if (updateListeners != null) { 423 processPassComplete(theImage); 424 } 425 426 ++interlacePass; 427 if (interlacePass > sourceMaxProgressivePass) { 428 return; 429 } 430 streamY = interlaceOffset[interlacePass]; 431 startPass(interlacePass); 432 } 433 } else { 434 ++streamY; 435 } 436 437 this.destY = destinationRegion.y + 440 (streamY - sourceRegion.y)/sourceYSubsampling; 441 computeDecodeThisRow(); 442 } 443 } 444 } 445 446 448 private void readHeader() throws IIOException { 449 if (gotHeader) { 450 return; 451 } 452 if (stream == null) { 453 throw new IllegalStateException ("Input not set!"); 454 } 455 456 this.streamMetadata = new GIFStreamMetadata(); 458 459 try { 460 stream.setByteOrder(ByteOrder.LITTLE_ENDIAN); 461 462 byte[] signature = new byte[6]; 463 stream.readFully(signature); 464 465 StringBuffer version = new StringBuffer (3); 466 version.append((char)signature[3]); 467 version.append((char)signature[4]); 468 version.append((char)signature[5]); 469 streamMetadata.version = version.toString(); 470 471 streamMetadata.logicalScreenWidth = stream.readUnsignedShort(); 472 streamMetadata.logicalScreenHeight = stream.readUnsignedShort(); 473 474 int packedFields = stream.readUnsignedByte(); 475 boolean globalColorTableFlag = (packedFields & 0x80) != 0; 476 streamMetadata.colorResolution = ((packedFields >> 4) & 0x7) + 1; 477 streamMetadata.sortFlag = (packedFields & 0x8) != 0; 478 int numGCTEntries = 1 << ((packedFields & 0x7) + 1); 479 480 streamMetadata.backgroundColorIndex = stream.readUnsignedByte(); 481 streamMetadata.pixelAspectRatio = stream.readUnsignedByte(); 482 483 if (globalColorTableFlag) { 484 streamMetadata.globalColorTable = new byte[3*numGCTEntries]; 485 stream.readFully(streamMetadata.globalColorTable); 486 } else { 487 streamMetadata.globalColorTable = null; 488 } 489 490 imageStartPosition.add(new Long (stream.getStreamPosition())); 492 } catch (IOException e) { 493 throw new IIOException ("I/O error reading header!", e); 494 } 495 496 gotHeader = true; 497 } 498 499 private boolean skipImage() throws IIOException { 500 503 try { 504 while (true) { 505 int blockType = stream.readUnsignedByte(); 506 507 if (blockType == 0x2c) { 508 stream.skipBytes(8); 509 510 int packedFields = stream.readUnsignedByte(); 511 if ((packedFields & 0x80) != 0) { 512 int bits = (packedFields & 0x7) + 1; 514 stream.skipBytes(3*(1 << bits)); 515 } 516 517 stream.skipBytes(1); 518 519 int length = 0; 520 do { 521 length = stream.readUnsignedByte(); 522 stream.skipBytes(length); 523 } while (length > 0); 524 525 return true; 526 } else if (blockType == 0x3b) { 527 return false; 528 } else if (blockType == 0x21) { 529 int label = stream.readUnsignedByte(); 530 531 int length = 0; 532 do { 533 length = stream.readUnsignedByte(); 534 stream.skipBytes(length); 535 } while (length > 0); 536 } else if (blockType == 0x0) { 537 return false; 539 } else { 540 int length = 0; 541 do { 542 length = stream.readUnsignedByte(); 543 stream.skipBytes(length); 544 } while (length > 0); 545 } 546 } 547 } catch (EOFException e) { 548 return false; 549 } catch (IOException e) { 550 throw new IIOException ("I/O error locating image!", e); 551 } 552 } 553 554 private int locateImage(int imageIndex) throws IIOException { 555 readHeader(); 556 557 try { 558 int index = Math.min(imageIndex, imageStartPosition.size() - 1); 560 561 Long l = (Long )imageStartPosition.get(index); 563 stream.seek(l.longValue()); 564 565 while (index < imageIndex) { 567 if (!skipImage()) { 568 --index; 569 return index; 570 } 571 572 Long l1 = new Long (stream.getStreamPosition()); 573 imageStartPosition.add(l1); 574 ++index; 575 } 576 } catch (IOException e) { 577 throw new IIOException ("Couldn't seek!", e); 578 } 579 580 if (currIndex != imageIndex) { 581 imageMetadata = null; 582 } 583 currIndex = imageIndex; 584 return imageIndex; 585 } 586 587 private byte[] concatenateBlocks() throws IOException { 589 byte[] data = new byte[0]; 590 while (true) { 591 int length = stream.readUnsignedByte(); 592 if (length == 0) { 593 break; 594 } 595 byte[] newData = new byte[data.length + length]; 596 System.arraycopy(data, 0, newData, 0, data.length); 597 stream.readFully(newData, data.length, length); 598 data = newData; 599 } 600 601 return data; 602 } 603 604 private void readMetadata() throws IIOException { 606 if (stream == null) { 607 throw new IllegalStateException ("Input not set!"); 608 } 609 610 try { 611 this.imageMetadata = new GIFImageMetadata(); 613 614 long startPosition = stream.getStreamPosition(); 615 while (true) { 616 int blockType = stream.readUnsignedByte(); 617 if (blockType == 0x2c) { imageMetadata.imageLeftPosition = 619 stream.readUnsignedShort(); 620 imageMetadata.imageTopPosition = 621 stream.readUnsignedShort(); 622 imageMetadata.imageWidth = stream.readUnsignedShort(); 623 imageMetadata.imageHeight = stream.readUnsignedShort(); 624 625 int idPackedFields = stream.readUnsignedByte(); 626 boolean localColorTableFlag = 627 (idPackedFields & 0x80) != 0; 628 imageMetadata.interlaceFlag = (idPackedFields & 0x40) != 0; 629 imageMetadata.sortFlag = (idPackedFields & 0x20) != 0; 630 int numLCTEntries = 1 << ((idPackedFields & 0x7) + 1); 631 632 if (localColorTableFlag) { 633 imageMetadata.localColorTable = 635 new byte[3*numLCTEntries]; 636 stream.readFully(imageMetadata.localColorTable); 637 } else { 638 imageMetadata.localColorTable = null; 639 } 640 641 this.imageMetadataLength = 643 (int)(stream.getStreamPosition() - startPosition); 644 645 return; 647 } else if (blockType == 0x21) { int label = stream.readUnsignedByte(); 649 650 if (label == 0xf9) { int gceLength = stream.readUnsignedByte(); int gcePackedFields = stream.readUnsignedByte(); 653 imageMetadata.disposalMethod = 654 (gcePackedFields >> 2) & 0x3; 655 imageMetadata.userInputFlag = 656 (gcePackedFields & 0x2) != 0; 657 imageMetadata.transparentColorFlag = 658 (gcePackedFields & 0x1) != 0; 659 660 imageMetadata.delayTime = stream.readUnsignedShort(); 661 imageMetadata.transparentColorIndex 662 = stream.readUnsignedByte(); 663 664 int terminator = stream.readUnsignedByte(); 665 } else if (label == 0x1) { int length = stream.readUnsignedByte(); 667 imageMetadata.hasPlainTextExtension = true; 668 imageMetadata.textGridLeft = 669 stream.readUnsignedShort(); 670 imageMetadata.textGridTop = 671 stream.readUnsignedShort(); 672 imageMetadata.textGridWidth = 673 stream.readUnsignedShort(); 674 imageMetadata.textGridHeight = 675 stream.readUnsignedShort(); 676 imageMetadata.characterCellWidth = 677 stream.readUnsignedByte(); 678 imageMetadata.characterCellHeight = 679 stream.readUnsignedByte(); 680 imageMetadata.textForegroundColor = 681 stream.readUnsignedByte(); 682 imageMetadata.textBackgroundColor = 683 stream.readUnsignedByte(); 684 imageMetadata.text = concatenateBlocks(); 685 } else if (label == 0xfe) { byte[] comment = concatenateBlocks(); 687 if (imageMetadata.comments == null) { 688 imageMetadata.comments = new ArrayList (); 689 } 690 imageMetadata.comments.add(comment); 691 } else if (label == 0xff) { int blockSize = stream.readUnsignedByte(); 693 byte[] applicationID = new byte[8]; 694 stream.readFully(applicationID); 695 byte[] authCode = new byte[3]; 696 stream.readFully(authCode); 697 byte[] applicationData = concatenateBlocks(); 698 699 if (imageMetadata.applicationIDs == null) { 701 imageMetadata.applicationIDs = new ArrayList (); 702 imageMetadata.authenticationCodes = 703 new ArrayList (); 704 imageMetadata.applicationData = new ArrayList (); 705 } 706 imageMetadata.applicationIDs.add(applicationID); 707 imageMetadata.authenticationCodes.add(authCode); 708 imageMetadata.applicationData.add(applicationData); 709 } else { 710 int length = 0; 712 do { 713 length = stream.readUnsignedByte(); 714 stream.skipBytes(length); 715 } while (length > 0); 716 } 717 } else if (blockType == 0x3b) { throw new IndexOutOfBoundsException 719 ("Attempt to read past end of image sequence!"); 720 } else { 721 throw new IIOException ("Unexpected block type " + 722 blockType + "!"); 723 } 724 } 725 } catch (IIOException iioe) { 726 throw iioe; 727 } catch (IOException ioe) { 728 throw new IIOException ("I/O error reading image metadata!", ioe); 729 } 730 } 731 732 private static void computeUpdatedPixels(int sourceOffset, 734 int sourceExtent, 735 int destinationOffset, 736 int dstMin, 737 int dstMax, 738 int sourceSubsampling, 739 int passStart, 740 int passExtent, 741 int passPeriod, 742 int[] vals, 743 int offset) { 744 745 774 boolean gotPixel = false; 775 int firstDst = -1; 776 int secondDst = -1; 777 int lastDst = -1; 778 779 for (int i = 0; i < passExtent; i++) { 780 int src = passStart + i*passPeriod; 781 if (src < sourceOffset) { 782 continue; 783 } 784 if ((src - sourceOffset) % sourceSubsampling != 0) { 785 continue; 786 } 787 if (src >= sourceOffset + sourceExtent) { 788 break; 789 } 790 791 int dst = destinationOffset + 792 (src - sourceOffset)/sourceSubsampling; 793 if (dst < dstMin) { 794 continue; 795 } 796 if (dst > dstMax) { 797 break; 798 } 799 800 if (!gotPixel) { 801 firstDst = dst; gotPixel = true; 803 } else if (secondDst == -1) { 804 secondDst = dst; } 806 lastDst = dst; } 808 809 vals[offset] = firstDst; 810 811 if (!gotPixel) { 813 vals[offset + 2] = 0; 814 } else { 815 vals[offset + 2] = lastDst - firstDst + 1; 816 } 817 818 vals[offset + 4] = Math.max(secondDst - firstDst, 1); 820 } 821 822 865 private static int[] computeUpdatedPixels(Rectangle sourceRegion, 866 Point destinationOffset, 867 int dstMinX, 868 int dstMinY, 869 int dstMaxX, 870 int dstMaxY, 871 int sourceXSubsampling, 872 int sourceYSubsampling, 873 int passXStart, 874 int passYStart, 875 int passWidth, 876 int passHeight, 877 int passPeriodX, 878 int passPeriodY) { 879 int[] vals = new int[6]; 880 computeUpdatedPixels(sourceRegion.x, sourceRegion.width, 881 destinationOffset.x, 882 dstMinX, dstMaxX, sourceXSubsampling, 883 passXStart, passWidth, passPeriodX, 884 vals, 0); 885 computeUpdatedPixels(sourceRegion.y, sourceRegion.height, 886 destinationOffset.y, 887 dstMinY, dstMaxY, sourceYSubsampling, 888 passYStart, passHeight, passPeriodY, 889 vals, 1); 890 return vals; 891 } 892 893 private void startPass(int pass) { 894 if (updateListeners == null) { 895 return; 896 } 897 898 int y = 0; 899 int yStep = 1; 900 if (imageMetadata.interlaceFlag) { 901 y = interlaceOffset[interlacePass]; 902 yStep = interlaceIncrement[interlacePass]; 903 } 904 905 int[] vals = 906 computeUpdatedPixels(sourceRegion, 907 destinationOffset, 908 destinationRegion.x, 909 destinationRegion.y, 910 destinationRegion.x + 911 destinationRegion.width - 1, 912 destinationRegion.y + 913 destinationRegion.height - 1, 914 sourceXSubsampling, 915 sourceYSubsampling, 916 0, 917 y, 918 destinationRegion.width, 919 (destinationRegion.height + yStep - 1)/yStep, 920 1, 921 yStep); 922 923 this.updateMinY = vals[1]; 925 this.updateYStep = vals[5]; 926 927 int[] bands = { 0 }; 929 930 processPassStarted(theImage, 931 interlacePass, 932 sourceMinProgressivePass, 933 sourceMaxProgressivePass, 934 0, 935 updateMinY, 936 1, 937 updateYStep, 938 bands); 939 } 940 941 public BufferedImage read(int imageIndex, ImageReadParam param) 942 throws IIOException { 943 if (stream == null) { 944 throw new IllegalStateException ("Input not set!"); 945 } 946 checkIndex(imageIndex); 947 948 int index = locateImage(imageIndex); 949 if (index != imageIndex) { 950 throw new IndexOutOfBoundsException ("imageIndex out of bounds!"); 951 } 952 953 clearAbortRequest(); 954 readMetadata(); 955 956 if (param == null) { 958 param = getDefaultReadParam(); 959 } 960 961 Iterator imageTypes = getImageTypes(imageIndex); 963 this.theImage = getDestination(param, 964 imageTypes, 965 imageMetadata.imageWidth, 966 imageMetadata.imageHeight); 967 this.theTile = theImage.getWritableTile(0, 0); 968 this.width = imageMetadata.imageWidth; 969 this.height = imageMetadata.imageHeight; 970 this.streamX = 0; 971 this.streamY = 0; 972 this.rowsDone = 0; 973 this.interlacePass = 0; 974 975 978 this.sourceRegion = new Rectangle (0, 0, 0, 0); 979 this.destinationRegion = new Rectangle (0, 0, 0, 0); 980 computeRegions(param, width, height, theImage, 981 sourceRegion, destinationRegion); 982 this.destinationOffset = new Point (destinationRegion.x, 983 destinationRegion.y); 984 985 this.sourceXSubsampling = param.getSourceXSubsampling(); 986 this.sourceYSubsampling = param.getSourceYSubsampling(); 987 this.sourceMinProgressivePass = 988 Math.max(param.getSourceMinProgressivePass(), 0); 989 this.sourceMaxProgressivePass = 990 Math.min(param.getSourceMaxProgressivePass(), 3); 991 992 this.destY = destinationRegion.y + 993 (streamY - sourceRegion.y)/sourceYSubsampling; 994 computeDecodeThisRow(); 995 996 processImageStarted(imageIndex); 998 startPass(0); 999 1000 this.rowBuf = new byte[width]; 1001 1002 try { 1003 this.initCodeSize = stream.readUnsignedByte(); 1005 1006 this.blockLength = stream.readUnsignedByte(); 1008 int left = blockLength; 1009 int off = 0; 1010 while (left > 0) { 1011 int nbytes = stream.read(block, off, left); 1012 left -= nbytes; 1013 off += nbytes; 1014 } 1015 1016 this.bitPos = 0; 1017 this.nextByte = 0; 1018 this.lastBlockFound = false; 1019 this.interlacePass = 0; 1020 1021 initNext32Bits(); 1023 1024 this.clearCode = 1 << initCodeSize; 1025 this.eofCode = clearCode + 1; 1026 1027 int code, oldCode = 0; 1028 1029 int[] prefix = new int[4096]; 1030 byte[] suffix = new byte[4096]; 1031 byte[] initial = new byte[4096]; 1032 int[] length = new int[4096]; 1033 byte[] string = new byte[4096]; 1034 1035 initializeStringTable(prefix, suffix, initial, length); 1036 int tableIndex = (1 << initCodeSize) + 2; 1037 int codeSize = initCodeSize + 1; 1038 int codeMask = (1 << codeSize) - 1; 1039 1040 while (!abortRequested()) { 1041 code = getCode(codeSize, codeMask); 1042 1043 if (code == clearCode) { 1044 initializeStringTable(prefix, suffix, initial, length); 1045 tableIndex = (1 << initCodeSize) + 2; 1046 codeSize = initCodeSize + 1; 1047 codeMask = (1 << codeSize) - 1; 1048 1049 code = getCode(codeSize, codeMask); 1050 if (code == eofCode) { 1051 processImageComplete(); 1053 return theImage; 1054 } 1055 } else if (code == eofCode) { 1056 processImageComplete(); 1058 return theImage; 1059 } else { 1060 int newSuffixIndex; 1061 if (code < tableIndex) { 1062 newSuffixIndex = code; 1063 } else { newSuffixIndex = oldCode; 1065 if (code != tableIndex) { 1066 processWarningOccurred("Out-of-sequence code!"); 1069 } 1070 } 1071 1072 int ti = tableIndex; 1073 int oc = oldCode; 1074 1075 prefix[ti] = oc; 1076 suffix[ti] = initial[newSuffixIndex]; 1077 initial[ti] = initial[oc]; 1078 length[ti] = length[oc] + 1; 1079 1080 ++tableIndex; 1081 if ((tableIndex == (1 << codeSize)) && 1082 (tableIndex < 4096)) { 1083 ++codeSize; 1084 codeMask = (1 << codeSize) - 1; 1085 } 1086 } 1087 1088 int c = code; 1090 int len = length[c]; 1091 for (int i = len - 1; i >= 0; i--) { 1092 string[i] = suffix[c]; 1093 c = prefix[c]; 1094 } 1095 1096 outputPixels(string, len); 1097 oldCode = code; 1098 } 1099 1100 processReadAborted(); 1101 return theImage; 1102 } catch (IOException e) { 1103 e.printStackTrace(); 1104 throw new IIOException ("I/O error reading image!", e); 1105 } 1106 } 1107 1108 1112 public void reset() { 1113 super.reset(); 1114 resetStreamSettings(); 1115 } 1116 1117 1120 private void resetStreamSettings() { 1121 gotHeader = false; 1122 streamMetadata = null; 1123 currIndex = -1; 1124 imageMetadata = null; 1125 imageStartPosition = new ArrayList (); 1126 numImages = -1; 1127 1128 blockLength = 0; 1130 bitPos = 0; 1131 nextByte = 0; 1132 1133 next32Bits = 0; 1134 lastBlockFound = false; 1135 1136 theImage = null; 1137 theTile = null; 1138 width = -1; 1139 height = -1; 1140 streamX = -1; 1141 streamY = -1; 1142 rowsDone = 0; 1143 interlacePass = 0; 1144 } 1145} 1146 | Popular Tags |