1 7 8 package com.sun.imageio.plugins.jpeg; 9 10 import javax.imageio.IIOException ; 11 import javax.imageio.ImageReader ; 12 import javax.imageio.ImageReadParam ; 13 import javax.imageio.ImageTypeSpecifier ; 14 import javax.imageio.metadata.IIOMetadata ; 15 import javax.imageio.spi.ImageReaderSpi ; 16 import javax.imageio.stream.ImageInputStream ; 17 import javax.imageio.plugins.jpeg.JPEGImageReadParam ; 18 import javax.imageio.plugins.jpeg.JPEGQTable ; 19 import javax.imageio.plugins.jpeg.JPEGHuffmanTable ; 20 21 import java.awt.Point ; 22 import java.awt.Rectangle ; 23 import java.awt.color.ColorSpace ; 24 import java.awt.color.ICC_Profile ; 25 import java.awt.color.ICC_ColorSpace ; 26 import java.awt.image.BufferedImage ; 27 import java.awt.image.Raster ; 28 import java.awt.image.WritableRaster ; 29 import java.awt.image.DataBuffer ; 30 import java.awt.image.DataBufferByte ; 31 import java.awt.image.ColorModel ; 32 import java.awt.image.IndexColorModel ; 33 import java.awt.image.ColorConvertOp ; 34 import java.io.IOException ; 35 import java.util.List ; 36 import java.util.Iterator ; 37 import java.util.ArrayList ; 38 39 import sun.java2d.Disposer; 40 import sun.java2d.DisposerRecord; 41 42 public class JPEGImageReader extends ImageReader { 43 44 private boolean debug = false; 45 46 52 private long structPointer = 0; 53 54 55 private ImageInputStream iis = null; 56 57 61 private List imagePositions = null; 62 63 66 private int numImages = 0; 67 68 static { 69 java.security.AccessController.doPrivileged( 70 new sun.security.action.LoadLibraryAction("jpeg")); 71 initReaderIDs(ImageInputStream .class, 72 JPEGQTable .class, 73 JPEGHuffmanTable .class); 74 } 75 76 80 86 protected static final int WARNING_NO_EOI = 0; 87 88 93 protected static final int WARNING_NO_JFIF_IN_THUMB = 1; 94 95 private static final int MAX_WARNING = WARNING_NO_JFIF_IN_THUMB; 96 97 101 private int currentImage = -1; 102 103 107 108 private int width; 109 110 private int height; 111 115 private int colorSpaceCode; 116 120 private int outColorSpaceCode; 121 122 private int numComponents; 123 124 private ColorSpace iccCS = null; 125 126 127 128 private ColorConvertOp convert = null; 129 130 131 private BufferedImage image = null; 132 133 134 private WritableRaster raster = null; 135 136 137 private WritableRaster target = null; 138 139 140 private DataBufferByte buffer = null; 141 142 143 private Rectangle destROI = null; 144 145 146 private int [] destinationBands = null; 147 148 149 private JPEGMetadata streamMetadata = null; 150 151 152 private JPEGMetadata imageMetadata = null; 153 private int imageMetadataIndex = -1; 154 155 159 private boolean haveSeeked = false; 160 161 165 private JPEGQTable [] abbrevQTables = null; 166 private JPEGHuffmanTable [] abbrevDCHuffmanTables = null; 167 private JPEGHuffmanTable [] abbrevACHuffmanTables = null; 168 169 private int minProgressivePass = 0; 170 private int maxProgressivePass = Integer.MAX_VALUE; 171 172 175 private static final int UNKNOWN = -1; private static final int MIN_ESTIMATED_PASSES = 10; private int knownPassCount = UNKNOWN; 178 private int pass = 0; 179 private float percentToDate = 0.0F; 180 private float previousPassPercentage = 0.0F; 181 private int progInterval = 0; 182 183 186 private boolean tablesOnlyChecked = false; 187 188 189 private Object disposerReferent = new Object (); 190 191 192 private DisposerRecord disposerRecord; 193 194 198 private static final ImageTypeSpecifier [] defaultTypes = 199 new ImageTypeSpecifier [JPEG.NUM_JCS_CODES]; 200 201 static { 202 defaultTypes[JPEG.JCS_GRAYSCALE] = 203 ImageTypeSpecifier.createFromBufferedImageType 204 (BufferedImage.TYPE_BYTE_GRAY); 205 defaultTypes[JPEG.JCS_RGB] = 206 ImageTypeSpecifier.createInterleaved 207 (JPEG.sRGB, 208 JPEG.bOffsRGB, 209 DataBuffer.TYPE_BYTE, 210 false, 211 false); 212 defaultTypes[JPEG.JCS_RGBA] = 213 ImageTypeSpecifier.createPacked 214 (JPEG.sRGB, 215 0xff000000, 216 0x00ff0000, 217 0x0000ff00, 218 0x000000ff, 219 DataBuffer.TYPE_INT, 220 false); 221 if (JPEG.YCC != null) { 222 defaultTypes[JPEG.JCS_YCC] = 223 ImageTypeSpecifier.createInterleaved 224 (JPEG.YCC, 225 JPEG.bandOffsets[2], 226 DataBuffer.TYPE_BYTE, 227 false, 228 false); 229 defaultTypes[JPEG.JCS_YCCA] = 230 ImageTypeSpecifier.createInterleaved 231 (JPEG.YCC, 232 JPEG.bandOffsets[3], 233 DataBuffer.TYPE_BYTE, 234 true, 235 false); 236 } 237 } 238 239 240 private static native void initReaderIDs(Class iisClass, 241 Class qTableClass, 242 Class huffClass); 243 244 public JPEGImageReader(ImageReaderSpi originator) { 245 super(originator); 246 structPointer = initJPEGImageReader(); 247 disposerRecord = new JPEGReaderDisposerRecord(structPointer); 248 Disposer.addRecord(disposerReferent, disposerRecord); 249 } 250 251 252 private native long initJPEGImageReader(); 253 254 259 protected void warningOccurred(int code) { 260 if ((code < 0) || (code > MAX_WARNING)){ 261 throw new InternalError ("Invalid warning index"); 262 } 263 processWarningOccurred 264 ("com.sun.imageio.plugins.jpeg.JPEGImageReaderResources", 265 Integer.toString(code)); 266 } 267 268 281 protected void warningWithMessage(String msg) { 282 processWarningOccurred(msg); 283 } 284 285 public void setInput(Object input, 286 boolean seekForwardOnly, 287 boolean ignoreMetadata) 288 { 289 super.setInput(input, seekForwardOnly, ignoreMetadata); 290 this.ignoreMetadata = ignoreMetadata; 291 resetInternalState(); 292 iis = (ImageInputStream ) input; setSource(structPointer, iis); 294 } 295 296 private native void setSource(long structPointer, 297 ImageInputStream source); 298 299 private void checkTablesOnly() throws IOException { 300 if (debug) { 301 System.out.println("Checking for tables-only image"); 302 } 303 long savePos = iis.getStreamPosition(); 304 if (debug) { 305 System.out.println("saved pos is " + savePos); 306 System.out.println("length is " + iis.length()); 307 } 308 boolean tablesOnly = readNativeHeader(true); 310 if (tablesOnly) { 311 if (debug) { 312 System.out.println("tables-only image found"); 313 long pos = iis.getStreamPosition(); 314 System.out.println("pos after return from native is " + pos); 315 } 316 if (ignoreMetadata == false) { 319 iis.seek(savePos); 320 haveSeeked = true; 321 streamMetadata = new JPEGMetadata(true, false, 322 iis, this); 323 long pos = iis.getStreamPosition(); 324 if (debug) { 325 System.out.println 326 ("pos after constructing stream metadata is " + pos); 327 } 328 } 329 if (hasNextImage()) { 332 imagePositions.add(new Long (iis.getStreamPosition())); 333 } 334 } else { imagePositions.add(new Long (savePos)); 336 currentImage = 0; 338 } 339 if (seekForwardOnly) { 340 Long pos = (Long ) imagePositions.get(imagePositions.size()-1); 341 iis.flushBefore(pos.longValue()); 342 } 343 tablesOnlyChecked = true; 344 } 345 346 public int getNumImages(boolean allowSearch) throws IOException { 347 if (numImages != 0) { 348 return numImages; 349 } 350 if (iis == null) { 351 throw new IllegalStateException ("Input not set"); 352 } 353 if (allowSearch == true) { 354 if (seekForwardOnly) { 355 throw new IllegalStateException ( 356 "seekForwardOnly and allowSearch can't both be true!"); 357 } 358 360 if (!tablesOnlyChecked) { 361 checkTablesOnly(); 362 } 363 364 iis.mark(); 365 366 gotoImage(0); 367 368 JPEGBuffer buffer = new JPEGBuffer(iis); 369 buffer.loadBuf(0); 370 371 boolean done = false; 372 while (!done) { 373 done = buffer.scanForFF(this); 374 switch (buffer.buf[buffer.bufPtr] & 0xff) { 375 case JPEG.SOI: 376 numImages++; 377 case 0: case JPEG.RST0: 381 case JPEG.RST1: 382 case JPEG.RST2: 383 case JPEG.RST3: 384 case JPEG.RST4: 385 case JPEG.RST5: 386 case JPEG.RST6: 387 case JPEG.RST7: 388 case JPEG.EOI: 389 buffer.bufAvail--; 390 buffer.bufPtr++; 391 break; 392 default: 394 buffer.bufAvail--; 395 buffer.bufPtr++; 396 buffer.loadBuf(2); 397 int length = ((buffer.buf[buffer.bufPtr++] & 0xff) << 8) | 398 (buffer.buf[buffer.bufPtr++] & 0xff); 399 buffer.bufAvail -= 2; 400 length -= 2; buffer.skipData(length); 402 } 403 } 404 405 406 iis.reset(); 407 408 return numImages; 409 } 410 411 return -1; } 413 414 423 private void gotoImage(int imageIndex) throws IOException { 424 if (iis == null) { 425 throw new IllegalStateException ("Input not set"); 426 } 427 if (imageIndex < minIndex) { 428 throw new IndexOutOfBoundsException (); 429 } 430 if (!tablesOnlyChecked) { 431 checkTablesOnly(); 432 } 433 if (imageIndex < imagePositions.size()) { 434 iis.seek(((Long )(imagePositions.get(imageIndex))).longValue()); 435 } else { 436 Long pos = (Long ) imagePositions.get(imagePositions.size()-1); 440 iis.seek(pos.longValue()); 441 skipImage(); 442 for (int index = imagePositions.size(); 444 index <= imageIndex; 445 index++) { 446 if (!hasNextImage()) { 448 throw new IndexOutOfBoundsException (); 449 } 450 pos = new Long (iis.getStreamPosition()); 451 imagePositions.add(pos); 452 if (seekForwardOnly) { 453 iis.flushBefore(pos.longValue()); 454 } 455 if (index < imageIndex) { 456 skipImage(); 457 } } 459 } 460 461 if (seekForwardOnly) { 462 minIndex = imageIndex; 463 } 464 465 haveSeeked = true; } 467 468 476 private void skipImage() throws IOException { 477 if (debug) { 478 System.out.println("skipImage called"); 479 } 480 boolean foundFF = false; 481 for (int byteval = iis.read(); 482 byteval != -1; 483 byteval = iis.read()) { 484 485 if (foundFF == true) { 486 if (byteval == JPEG.EOI) { 487 return; 488 } 489 } 490 foundFF = (byteval == 0xff) ? true : false; 491 } 492 throw new IndexOutOfBoundsException (); 493 } 494 495 500 private boolean hasNextImage() throws IOException { 501 if (debug) { 502 System.out.print("hasNextImage called; returning "); 503 } 504 iis.mark(); 505 boolean foundFF = false; 506 for (int byteval = iis.read(); 507 byteval != -1; 508 byteval = iis.read()) { 509 510 if (foundFF == true) { 511 if (byteval == JPEG.SOI) { 512 iis.reset(); 513 if (debug) { 514 System.out.println("true"); 515 } 516 return true; 517 } 518 } 519 foundFF = (byteval == 0xff) ? true : false; 520 } 521 iis.reset(); 523 if (debug) { 524 System.out.println("false"); 525 } 526 return false; 527 } 528 529 534 private void pushBack(int num) throws IOException { 535 if (debug) { 536 System.out.println("pushing back " + num + " bytes"); 537 } 538 iis.seek(iis.getStreamPosition()-num); 539 } 541 542 545 private void readHeader(int imageIndex, boolean reset) 546 throws IOException { 547 gotoImage(imageIndex); 548 readNativeHeader(reset); currentImage = imageIndex; 550 } 551 552 private boolean readNativeHeader(boolean reset) throws IOException { 553 boolean retval = false; 554 retval = readImageHeader(structPointer, haveSeeked, reset); 555 haveSeeked = false; 556 return retval; 557 } 558 559 572 private native boolean readImageHeader(long structPointer, 573 boolean clearBuffer, 574 boolean reset) 575 throws IOException ; 576 577 583 private void setImageData(int width, 584 int height, 585 int colorSpaceCode, 586 int outColorSpaceCode, 587 int numComponents, 588 byte [] iccData) { 589 this.width = width; 590 this.height = height; 591 this.colorSpaceCode = colorSpaceCode; 592 this.outColorSpaceCode = outColorSpaceCode; 593 this.numComponents = numComponents; 594 iccCS = null; 595 if (iccData != null) { 596 iccCS = new ICC_ColorSpace (ICC_Profile.getInstance(iccData)); 597 } 598 } 599 600 public int getWidth(int imageIndex) throws IOException { 601 if (currentImage != imageIndex) { 602 readHeader(imageIndex, true); 603 } 604 return width; 605 } 606 607 public int getHeight(int imageIndex) throws IOException { 608 if (currentImage != imageIndex) { 609 readHeader(imageIndex, true); 610 } 611 return height; 612 } 613 614 616 620 private ImageTypeSpecifier getImageType(int code) { 621 ImageTypeSpecifier ret = null; 622 623 if ((code > 0) && (code < JPEG.NUM_JCS_CODES)) { 624 ret = defaultTypes[code]; 625 } 626 return ret; 627 } 628 629 public ImageTypeSpecifier getRawImageType(int imageIndex) 630 throws IOException { 631 if (currentImage != imageIndex) { 632 readHeader(imageIndex, true); 633 } 634 return getImageType(colorSpaceCode); 636 } 637 638 public Iterator getImageTypes(int imageIndex) 639 throws IOException { 640 if (currentImage != imageIndex) { 641 readHeader(imageIndex, true); 642 } 643 644 651 654 ImageTypeSpecifier raw = getImageType(colorSpaceCode); 657 658 662 ArrayList list = new ArrayList (1); 663 664 switch (colorSpaceCode) { 665 case JPEG.JCS_GRAYSCALE: 666 list.add(raw); 667 list.add(getImageType(JPEG.JCS_RGB)); 668 break; 669 case JPEG.JCS_RGB: 670 list.add(raw); 671 list.add(getImageType(JPEG.JCS_GRAYSCALE)); 672 if (JPEG.YCC != null) { 673 list.add(getImageType(JPEG.JCS_YCC)); 674 } 675 break; 676 case JPEG.JCS_RGBA: 677 list.add(raw); 678 break; 679 case JPEG.JCS_YCC: 680 if (raw != null) { list.add(raw); 682 list.add(getImageType(JPEG.JCS_RGB)); 683 } 684 break; 685 case JPEG.JCS_YCCA: 686 if (raw != null) { list.add(raw); 688 } 689 break; 690 case JPEG.JCS_YCbCr: 691 if (iccCS != null) { 695 list.add(ImageTypeSpecifier.createInterleaved 696 (iccCS, 697 JPEG.bOffsRGB, DataBuffer.TYPE_BYTE, 699 false, 700 false)); 701 702 } 703 list.add(getImageType(JPEG.JCS_RGB)); 704 list.add(getImageType(JPEG.JCS_GRAYSCALE)); 705 if (JPEG.YCC != null) { list.add(getImageType(JPEG.JCS_YCC)); 707 } 708 break; 709 case JPEG.JCS_YCbCrA: list.add(getImageType(JPEG.JCS_RGBA)); 713 break; 714 } 715 716 return list.iterator(); 717 } 718 719 729 private void checkColorConversion(BufferedImage image, 730 ImageReadParam param) 731 throws IIOException { 732 733 if (param != null) { 738 if ((param.getSourceBands() != null) || 739 (param.getDestinationBands() != null)) { 740 return; 742 } 743 } 744 745 750 ColorModel cm = image.getColorModel(); 751 752 if (cm instanceof IndexColorModel ) { 753 throw new IIOException ("IndexColorModel not supported"); 754 } 755 756 ColorSpace cs = cm.getColorSpace(); 759 int csType = cs.getType(); 760 convert = null; 761 switch (outColorSpaceCode) { 762 case JPEG.JCS_GRAYSCALE: if (csType == ColorSpace.TYPE_RGB) { setOutColorSpace(structPointer, JPEG.JCS_RGB); 766 } else if (csType != ColorSpace.TYPE_GRAY) { 767 throw new IIOException ("Incompatible color conversion"); 768 } 769 break; 770 case JPEG.JCS_RGB: if (csType == ColorSpace.TYPE_GRAY) { if (colorSpaceCode == JPEG.JCS_YCbCr) { 773 setOutColorSpace(structPointer, JPEG.JCS_GRAYSCALE); 775 } 776 } else if ((iccCS != null) && 777 (cm.getNumComponents() == numComponents) && 778 (cs != iccCS)) { 779 convert = new ColorConvertOp (iccCS, cs, null); 782 } else if ((!cs.isCS_sRGB()) && 784 (cm.getNumComponents() == numComponents)) { 785 convert = new ColorConvertOp (JPEG.sRGB, cs, null); 787 } else if (csType != ColorSpace.TYPE_RGB) { 788 throw new IIOException ("Incompatible color conversion"); 789 } 790 break; 791 case JPEG.JCS_RGBA: 792 if ((csType != ColorSpace.TYPE_RGB) || 794 (cm.getNumComponents() != numComponents)) { 795 throw new IIOException ("Incompatible color conversion"); 796 } 797 break; 798 case JPEG.JCS_YCC: 799 if (JPEG.YCC == null) { throw new IIOException ("Incompatible color conversion"); 801 } 802 if ((cs != JPEG.YCC) && 803 (cm.getNumComponents() == numComponents)) { 804 convert = new ColorConvertOp (JPEG.YCC, cs, null); 805 } 806 break; 807 case JPEG.JCS_YCCA: 808 if ((JPEG.YCC == null) || (cs != JPEG.YCC) || 811 (cm.getNumComponents() != numComponents)) { 812 throw new IIOException ("Incompatible color conversion"); 813 } 814 break; 815 default: 816 throw new IIOException ("Incompatible color conversion"); 818 } 819 } 820 821 825 private native void setOutColorSpace(long structPointer, int id); 826 827 829 public ImageReadParam getDefaultReadParam() { 830 return new JPEGImageReadParam (); 831 } 832 833 public IIOMetadata getStreamMetadata() throws IOException { 834 if (!tablesOnlyChecked) { 835 checkTablesOnly(); 836 } 837 return streamMetadata; 838 } 839 840 public IIOMetadata getImageMetadata(int imageIndex) 841 throws IOException { 842 843 if ((imageMetadataIndex == imageIndex) 847 && (imageMetadata != null)) { 848 return imageMetadata; 849 } 850 851 gotoImage(imageIndex); 852 853 imageMetadata = new JPEGMetadata(false, false, iis, this); 854 855 imageMetadataIndex = imageIndex; 856 857 return imageMetadata; 858 859 } 860 861 public BufferedImage read(int imageIndex, ImageReadParam param) 862 throws IOException { 863 try { 864 readInternal(imageIndex, param, false); 865 } catch (RuntimeException e) { 866 resetLibraryState(structPointer); 867 throw e; 868 } catch (IOException e) { 869 resetLibraryState(structPointer); 870 throw e; 871 } 872 BufferedImage ret = image; 873 image = null; return ret; 875 } 876 877 private Raster readInternal(int imageIndex, 878 ImageReadParam param, 879 boolean wantRaster) throws IOException { 880 readHeader(imageIndex, false); 881 882 WritableRaster imRas = null; 883 int numImageBands = 0; 884 885 if (!wantRaster){ 886 Iterator imageTypes = getImageTypes(imageIndex); 888 if (imageTypes.hasNext() == false) { 889 throw new IIOException ("Unsupported Image Type"); 890 } 891 892 image = getDestination(param, imageTypes, width, height); 893 imRas = image.getRaster(); 894 895 897 numImageBands = image.getSampleModel().getNumBands(); 898 899 901 checkColorConversion(image, param); 905 906 checkReadParamBandSettings(param, numComponents, numImageBands); 908 } else { 909 setOutColorSpace(structPointer, colorSpaceCode); 912 image = null; 913 } 914 915 922 int [] srcBands = JPEG.bandOffsets[numComponents-1]; 923 int numRasterBands = (wantRaster ? numComponents : numImageBands); 924 destinationBands = null; 925 926 Rectangle srcROI = new Rectangle (0, 0, 0, 0); 927 destROI = new Rectangle (0, 0, 0, 0); 928 computeRegions(param, width, height, image, srcROI, destROI); 929 930 int periodX = 1; 931 int periodY = 1; 932 933 minProgressivePass = 0; 934 maxProgressivePass = Integer.MAX_VALUE; 935 936 if (param != null) { 937 periodX = param.getSourceXSubsampling(); 938 periodY = param.getSourceYSubsampling(); 939 940 int[] sBands = param.getSourceBands(); 941 if (sBands != null) { 942 srcBands = sBands; 943 numRasterBands = srcBands.length; 944 } 945 if (!wantRaster) { destinationBands = param.getDestinationBands(); 947 } 948 949 minProgressivePass = param.getSourceMinProgressivePass(); 950 maxProgressivePass = param.getSourceMaxProgressivePass(); 951 952 if (param instanceof JPEGImageReadParam ) { 953 JPEGImageReadParam jparam = (JPEGImageReadParam ) param; 954 if (jparam.areTablesSet()) { 955 abbrevQTables = jparam.getQTables(); 956 abbrevDCHuffmanTables = jparam.getDCHuffmanTables(); 957 abbrevACHuffmanTables = jparam.getACHuffmanTables(); 958 } 959 } 960 } 961 962 int lineSize = destROI.width*numRasterBands; 963 964 buffer = new DataBufferByte (lineSize); 965 966 int [] bandOffs = JPEG.bandOffsets[numRasterBands-1]; 967 968 raster = Raster.createInterleavedRaster(buffer, 969 destROI.width, 1, 970 lineSize, 971 numRasterBands, 972 bandOffs, 973 null); 974 975 if (wantRaster) { 978 target = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 979 destROI.width, 980 destROI.height, 981 lineSize, 982 numRasterBands, 983 bandOffs, 984 null); 985 } else { 986 target = imRas; 987 } 988 int [] bandSizes = target.getSampleModel().getSampleSize(); 989 990 995 996 boolean callbackUpdates = ((updateListeners != null) 998 || (progressListeners != null)); 999 1000 initProgressData(); 1002 if (imageIndex == imageMetadataIndex) { knownPassCount = 0; 1006 for (Iterator iter = imageMetadata.markerSequence.iterator(); 1007 iter.hasNext();) { 1008 if (iter.next() instanceof SOSMarkerSegment) { 1009 knownPassCount++; 1010 } 1011 } 1012 } 1013 progInterval = Math.max((target.getHeight()-1) / 20, 1); 1014 if (knownPassCount > 0) { 1015 progInterval *= knownPassCount; 1016 } else if (maxProgressivePass != Integer.MAX_VALUE) { 1017 progInterval *= (maxProgressivePass - minProgressivePass + 1); 1018 } 1019 1020 if (debug) { 1021 System.out.println("**** Read Data *****"); 1022 System.out.println("numRasterBands is " + numRasterBands); 1023 System.out.print("srcBands:"); 1024 for (int i = 0; i<srcBands.length;i++) 1025 System.out.print(" " + srcBands[i]); 1026 System.out.println(); 1027 System.out.println("destination bands is " + destinationBands); 1028 if (destinationBands != null) { 1029 for (int i = 0; i < destinationBands.length; i++) { 1030 System.out.print(" " + destinationBands[i]); 1031 } 1032 System.out.println(); 1033 } 1034 System.out.println("sourceROI is " + srcROI); 1035 System.out.println("destROI is " + destROI); 1036 System.out.println("periodX is " + periodX); 1037 System.out.println("periodY is " + periodY); 1038 System.out.println("minProgressivePass is " + minProgressivePass); 1039 System.out.println("maxProgressivePass is " + maxProgressivePass); 1040 System.out.println("callbackUpdates is " + callbackUpdates); 1041 } 1042 1043 1045 processImageStarted(currentImage); 1046 1047 boolean aborted = false; 1048 1049 aborted = readImage(structPointer, 1050 buffer.getData(), 1051 numRasterBands, 1052 srcBands, 1053 bandSizes, 1054 srcROI.x, srcROI.y, 1055 srcROI.width, srcROI.height, 1056 periodX, periodY, 1057 abbrevQTables, 1058 abbrevDCHuffmanTables, 1059 abbrevACHuffmanTables, 1060 minProgressivePass, maxProgressivePass, 1061 callbackUpdates); 1062 1063 if (aborted) { 1064 processReadAborted(); 1065 } else { 1066 processImageComplete(); 1067 } 1068 1069 return target; 1070 1071 } 1072 1073 1079 private void acceptPixels(int y, boolean progressive) { 1080 if (convert != null) { 1081 convert.filter(raster, raster); 1082 } 1083 target.setRect(destROI.x, destROI.y + y, raster); 1084 1085 processImageUpdate(image, 1086 destROI.x, destROI.y+y, 1087 raster.getWidth(), 1, 1088 1, 1, 1089 destinationBands); 1090 if ((y > 0) && (y%progInterval == 0)) { 1091 int height = target.getHeight()-1; 1092 float percentOfPass = ((float)y)/height; 1093 if (progressive) { 1094 if (knownPassCount != UNKNOWN) { 1095 processImageProgress((pass + percentOfPass)*100.0F 1096 / knownPassCount); 1097 } else if (maxProgressivePass != Integer.MAX_VALUE) { 1098 processImageProgress((pass + percentOfPass)*100.0F 1100 / (maxProgressivePass - minProgressivePass + 1)); 1101 } else { 1102 int remainingPasses = Math.max(2, MIN_ESTIMATED_PASSES-pass); 1112 int totalPasses = pass + remainingPasses-1; 1113 progInterval = Math.max(height/20*totalPasses, 1114 totalPasses); 1115 if (y%progInterval == 0) { 1116 percentToDate = previousPassPercentage + 1117 (1.0F - previousPassPercentage) 1118 * (percentOfPass)/remainingPasses; 1119 if (debug) { 1120 System.out.print("pass= " + pass); 1121 System.out.print(", y= " + y); 1122 System.out.print(", progInt= " + progInterval); 1123 System.out.print(", % of pass: " + percentOfPass); 1124 System.out.print(", rem. passes: " 1125 + remainingPasses); 1126 System.out.print(", prev%: " 1127 + previousPassPercentage); 1128 System.out.print(", %ToDate: " + percentToDate); 1129 System.out.print(" "); 1130 } 1131 processImageProgress(percentToDate*100.0F); 1132 } 1133 } 1134 } else { 1135 processImageProgress(percentOfPass * 100.0F); 1136 } 1137 } 1138 } 1139 1140 private void initProgressData() { 1141 knownPassCount = UNKNOWN; 1142 pass = 0; 1143 percentToDate = 0.0F; 1144 previousPassPercentage = 0.0F; 1145 progInterval = 0; 1146 } 1147 1148 private void passStarted (int pass) { 1149 this.pass = pass; 1150 previousPassPercentage = percentToDate; 1151 processPassStarted(image, 1152 pass, 1153 minProgressivePass, 1154 maxProgressivePass, 1155 0, 0, 1156 1,1, 1157 destinationBands); 1158 } 1159 1160 private void passComplete () { 1161 processPassComplete(image); 1162 } 1163 1164 void thumbnailStarted(int thumbnailIndex) { 1165 processThumbnailStarted(currentImage, thumbnailIndex); 1166 } 1167 1168 void thumbnailProgress(float percentageDone) { 1170 processThumbnailProgress(percentageDone); 1171 } 1172 1173 void thumbnailComplete() { 1175 processThumbnailComplete(); 1176 } 1177 1178 1181 private native boolean readImage(long structPointer, 1182 byte [] buffer, 1183 int numRasterBands, 1184 int [] srcBands, 1185 int [] bandSizes, 1186 int sourceXOffset, int sourceYOffset, 1187 int sourceWidth, int sourceHeight, 1188 int periodX, int periodY, 1189 JPEGQTable [] abbrevQTables, 1190 JPEGHuffmanTable [] abbrevDCHuffmanTables, 1191 JPEGHuffmanTable [] abbrevACHuffmanTables, 1192 int minProgressivePass, 1193 int maxProgressivePass, 1194 boolean wantUpdates); 1195 1196 public void abort() { 1197 super.abort(); 1198 abortRead(structPointer); 1199 } 1200 1201 1202 private native void abortRead(long structPointer); 1203 1204 1205 private native void resetLibraryState(long structPointer); 1206 1207 public boolean canReadRaster() { 1208 return true; 1209 } 1210 1211 public Raster readRaster(int imageIndex, ImageReadParam param) 1212 throws IOException { 1213 Raster retval = null; 1214 try { 1215 1220 1221 Point saveDestOffset = null; 1225 if (param != null) { 1226 saveDestOffset = param.getDestinationOffset(); 1227 param.setDestinationOffset(new Point (0, 0)); 1228 } 1229 retval = readInternal(imageIndex, param, true); 1230 if (saveDestOffset != null) { 1232 target = target.createWritableTranslatedChild(saveDestOffset.x, 1233 saveDestOffset.y); 1234 } 1235 } catch (RuntimeException e) { 1236 resetLibraryState(structPointer); 1237 throw e; 1238 } catch (IOException e) { 1239 resetLibraryState(structPointer); 1240 throw e; 1241 } 1242 return retval; 1243 } 1244 1245 public boolean readerSupportsThumbnails() { 1246 return true; 1247 } 1248 1249 public int getNumThumbnails(int imageIndex) throws IOException { 1250 getImageMetadata(imageIndex); JFIFMarkerSegment jfif = 1253 (JFIFMarkerSegment) imageMetadata.findMarkerSegment 1254 (JFIFMarkerSegment.class, true); 1255 int retval = 0; 1256 if (jfif != null) { 1257 retval = (jfif.thumb == null) ? 0 : 1; 1258 retval += jfif.extSegments.size(); 1259 } 1260 return retval; 1261 } 1262 1263 public int getThumbnailWidth(int imageIndex, int thumbnailIndex) 1264 throws IOException { 1265 if ((thumbnailIndex < 0) 1266 || (thumbnailIndex >= getNumThumbnails(imageIndex))) { 1267 throw new IndexOutOfBoundsException ("No such thumbnail"); 1268 } 1269 JFIFMarkerSegment jfif = 1271 (JFIFMarkerSegment) imageMetadata.findMarkerSegment 1272 (JFIFMarkerSegment.class, true); 1273 return jfif.getThumbnailWidth(thumbnailIndex); 1274 } 1275 1276 public int getThumbnailHeight(int imageIndex, int thumbnailIndex) 1277 throws IOException { 1278 if ((thumbnailIndex < 0) 1279 || (thumbnailIndex >= getNumThumbnails(imageIndex))) { 1280 throw new IndexOutOfBoundsException ("No such thumbnail"); 1281 } 1282 JFIFMarkerSegment jfif = 1284 (JFIFMarkerSegment) imageMetadata.findMarkerSegment 1285 (JFIFMarkerSegment.class, true); 1286 return jfif.getThumbnailHeight(thumbnailIndex); 1287 } 1288 1289 public BufferedImage readThumbnail(int imageIndex, 1290 int thumbnailIndex) 1291 throws IOException { 1292 if ((thumbnailIndex < 0) 1293 || (thumbnailIndex >= getNumThumbnails(imageIndex))) { 1294 throw new IndexOutOfBoundsException ("No such thumbnail"); 1295 } 1296 JFIFMarkerSegment jfif = 1298 (JFIFMarkerSegment) imageMetadata.findMarkerSegment 1299 (JFIFMarkerSegment.class, true); 1300 return jfif.getThumbnail(iis, thumbnailIndex, this); 1301 } 1302 1303 private void resetInternalState() { 1304 resetReader(structPointer); 1306 1307 numImages = 0; 1309 imagePositions = new ArrayList (); 1310 currentImage = -1; 1311 image = null; 1312 raster = null; 1313 target = null; 1314 buffer = null; 1315 destROI = null; 1316 destinationBands = null; 1317 streamMetadata = null; 1318 imageMetadata = null; 1319 imageMetadataIndex = -1; 1320 haveSeeked = false; 1321 tablesOnlyChecked = false; 1322 iccCS = null; 1323 initProgressData(); 1324 } 1325 1326 1331 1332 private native void resetReader(long structPointer); 1333 1334 public void dispose() { 1335 if (structPointer != 0) { 1336 disposerRecord.dispose(); 1337 structPointer = 0; 1338 } 1339 } 1340 1341 private static native void disposeReader(long structPointer); 1342 1343 private static class JPEGReaderDisposerRecord extends DisposerRecord { 1344 private long pData; 1345 1346 public JPEGReaderDisposerRecord(long pData) { 1347 this.pData = pData; 1348 } 1349 1350 public synchronized void dispose() { 1351 if (pData != 0) { 1352 disposeReader(pData); 1353 pData = 0; 1354 } 1355 } 1356 } 1357} 1358 | Popular Tags |