< prev index next >

src/java.desktop/share/classes/com/sun/imageio/plugins/tiff/TIFFImageReader.java

Print this page




 119     private int srcXSubsampling;
 120     private int srcYSubsampling;
 121 
 122     private int dstWidth;
 123     private int dstHeight;
 124     private int dstMinX;
 125     private int dstMinY;
 126     private int dstXOffset;
 127     private int dstYOffset;
 128 
 129     private int tilesAcross;
 130     private int tilesDown;
 131 
 132     private int pixelsRead;
 133     private int pixelsToRead;
 134 
 135     public TIFFImageReader(ImageReaderSpi originatingProvider) {
 136         super(originatingProvider);
 137     }
 138 

 139     public void setInput(Object input,
 140             boolean seekForwardOnly,
 141             boolean ignoreMetadata) {
 142         super.setInput(input, seekForwardOnly, ignoreMetadata);
 143 
 144         // Clear all local values based on the previous stream contents.
 145         resetLocal();
 146 
 147         if (input != null) {
 148             if (!(input instanceof ImageInputStream)) {
 149                 throw new IllegalArgumentException("input not an ImageInputStream!");
 150             }
 151             this.stream = (ImageInputStream) input;
 152         } else {
 153             this.stream = null;
 154         }
 155     }
 156 
 157     // Do not seek to the beginning of the stream so as to allow users to
 158     // point us at an IFD within some other file format


 228                 stream.seek(offset);
 229                 imageStartPosition.add(Long.valueOf(offset));
 230                 ++index;
 231             }
 232         } catch (EOFException eofe) {
 233             forwardWarningMessage("Ignored " + eofe);
 234 
 235             // Ran off the end of stream: decrement index
 236             imageIndex = index > 0 ? index - 1 : 0;
 237         } catch (IOException ioe) {
 238             throw new IIOException("Couldn't seek!", ioe);
 239         }
 240 
 241         if (currIndex != imageIndex) {
 242             imageMetadata = null;
 243         }
 244         currIndex = imageIndex;
 245         return imageIndex;
 246     }
 247 

 248     public int getNumImages(boolean allowSearch) throws IOException {
 249         if (stream == null) {
 250             throw new IllegalStateException("Input not set!");
 251         }
 252         if (seekForwardOnly && allowSearch) {
 253             throw new IllegalStateException("seekForwardOnly and allowSearch can't both be true!");
 254         }
 255 
 256         if (numImages > 0) {
 257             return numImages;
 258         }
 259         if (allowSearch) {
 260             this.numImages = locateImage(Integer.MAX_VALUE) + 1;
 261         }
 262         return numImages;
 263     }
 264 

 265     public IIOMetadata getStreamMetadata() throws IIOException {
 266         readHeader();
 267         return streamMetadata;
 268     }
 269 
 270     // Throw an IndexOutOfBoundsException if index < minIndex,
 271     // and bump minIndex if required.
 272     private void checkIndex(int imageIndex) {
 273         if (imageIndex < minIndex) {
 274             throw new IndexOutOfBoundsException("imageIndex < minIndex!");
 275         }
 276         if (seekForwardOnly) {
 277             minIndex = imageIndex;
 278         }
 279     }
 280 
 281     // Verify that imageIndex is in bounds, find the image IFD, read the
 282     // image metadata, initialize instance variables from the metadata.
 283     private void seekToImage(int imageIndex) throws IIOException {
 284         checkIndex(imageIndex);


 470                         = Math.min(tileOrStripByteCount,
 471                                 streamLength - getTileOrStripOffset(tileIndex));
 472             } else {
 473                 processWarningOccurred("Stream length is unknown: cannot clamp estimated strip or tile byte count to EOF.");
 474             }
 475         }
 476 
 477         return tileOrStripByteCount;
 478     }
 479 
 480     private int getCompression() {
 481         TIFFField f
 482                 = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
 483         if (f == null) {
 484             return BaselineTIFFTagSet.COMPRESSION_NONE;
 485         } else {
 486             return f.getAsInt(0);
 487         }
 488     }
 489 

 490     public int getWidth(int imageIndex) throws IOException {
 491         seekToImage(imageIndex);
 492         return getWidth();
 493     }
 494 

 495     public int getHeight(int imageIndex) throws IOException {
 496         seekToImage(imageIndex);
 497         return getHeight();
 498     }
 499 
 500     /**
 501      * Initializes these instance variables from the image metadata:
 502      * <pre>
 503      * compression
 504      * width
 505      * height
 506      * samplesPerPixel
 507      * numBands
 508      * colorMap
 509      * photometricInterpretation
 510      * sampleFormat
 511      * bitsPerSample
 512      * extraSamples
 513      * tileOrStripWidth
 514      * tileOrStripHeight


 682 
 683         for (int i = 0; i < samplesPerPixel; i++) {
 684             // Replicate initial value if not enough values provided
 685             bitsPerSample[i] = replicateFirst ? first : f.getAsInt(i);
 686             if (bitsPerSample[i] > BITS_PER_SAMPLE_MAX) {
 687                 throw new IIOException
 688                     ("Bits per sample (" + bitsPerSample[i]
 689                     + ") greater than allowed maximum ("
 690                     + BITS_PER_SAMPLE_MAX + ")");
 691             }
 692         }
 693 
 694         // ExtraSamples
 695         this.extraSamples = null;
 696         f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
 697         if (f != null) {
 698             extraSamples = f.getAsInts();
 699         }
 700     }
 701 

 702     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IIOException {
 703         List<ImageTypeSpecifier> l; // List of ImageTypeSpecifiers
 704 
 705         Integer imageIndexInteger = Integer.valueOf(imageIndex);
 706         if (imageTypeMap.containsKey(imageIndexInteger)) {
 707             // Return the cached ITS List.
 708             l = imageTypeMap.get(imageIndexInteger);
 709         } else {
 710             // Create a new ITS List.
 711             l = new ArrayList<ImageTypeSpecifier>(1);
 712 
 713             // Create the ITS and cache if for later use so that this method
 714             // always returns an Iterator containing the same ITS objects.
 715             seekToImage(imageIndex);
 716             ImageTypeSpecifier itsRaw
 717                     = TIFFDecompressor.getRawImageTypeSpecifier(photometricInterpretation,
 718                             compression,
 719                             samplesPerPixel,
 720                             bitsPerSample,
 721                             sampleFormat,


 809                             && csRaw.getNumComponents()
 810                             == iccColorSpace.getNumComponents()) {
 811                         l.add(itsRaw);
 812                     }
 813                 } else { // ICCProfile not compatible with SampleModel.
 814                     // Append the raw ITS to the List.
 815                     l.add(itsRaw);
 816                 }
 817             } else { // No ICCProfile field or raw ColorModel not component.
 818                 // Append the raw ITS to the List.
 819                 l.add(itsRaw);
 820             }
 821 
 822             // Cache the ITS List.
 823             imageTypeMap.put(imageIndexInteger, l);
 824         }
 825 
 826         return l.iterator();
 827     }
 828 

 829     public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
 830         seekToImage(imageIndex);
 831         TIFFImageMetadata im
 832                 = new TIFFImageMetadata(imageMetadata.getRootIFD().getTagSetList());
 833         Node root
 834                 = imageMetadata.getAsTree(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME);
 835         im.setFromTree(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME, root);
 836         return im;
 837     }
 838 
 839     public IIOMetadata getStreamMetadata(int imageIndex) throws IIOException {
 840         readHeader();
 841         TIFFStreamMetadata sm = new TIFFStreamMetadata();
 842         Node root = sm.getAsTree(TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME);
 843         sm.setFromTree(TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME, root);
 844         return sm;
 845     }
 846 

 847     public boolean isRandomAccessEasy(int imageIndex) throws IOException {
 848         if (currIndex != -1) {
 849             seekToImage(currIndex);
 850             return getCompression() == BaselineTIFFTagSet.COMPRESSION_NONE;
 851         } else {
 852             return false;
 853         }
 854     }
 855 
 856     // Thumbnails
 857     public boolean readSupportsThumbnails() {
 858         return false;
 859     }
 860 

 861     public boolean hasThumbnails(int imageIndex) {
 862         return false;
 863     }
 864 

 865     public int getNumThumbnails(int imageIndex) throws IOException {
 866         return 0;
 867     }
 868 

 869     public ImageReadParam getDefaultReadParam() {
 870         return new TIFFImageReadParam();
 871     }
 872 

 873     public boolean isImageTiled(int imageIndex) throws IOException {
 874         seekToImage(imageIndex);
 875 
 876         TIFFField f
 877                 = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
 878         return f != null;
 879     }
 880 

 881     public int getTileWidth(int imageIndex) throws IOException {
 882         seekToImage(imageIndex);
 883         return getTileOrStripWidth();
 884     }
 885 

 886     public int getTileHeight(int imageIndex) throws IOException {
 887         seekToImage(imageIndex);
 888         return getTileOrStripHeight();
 889     }
 890 

 891     public BufferedImage readTile(int imageIndex, int tileX, int tileY)
 892             throws IOException {
 893 
 894         int w = getWidth(imageIndex);
 895         int h = getHeight(imageIndex);
 896         int tw = getTileWidth(imageIndex);
 897         int th = getTileHeight(imageIndex);
 898 
 899         int x = tw * tileX;
 900         int y = th * tileY;
 901 
 902         if (tileX < 0 || tileY < 0 || x >= w || y >= h) {
 903             throw new IllegalArgumentException("Tile indices are out of bounds!");
 904         }
 905 
 906         if (x + tw > w) {
 907             tw = w - x;
 908         }
 909 
 910         if (y + th > h) {
 911             th = h - y;
 912         }
 913 
 914         ImageReadParam param = getDefaultReadParam();
 915         Rectangle tileRect = new Rectangle(x, y, tw, th);
 916         param.setSourceRegion(tileRect);
 917 
 918         return read(imageIndex, param);
 919     }
 920 

 921     public boolean canReadRaster() {
 922         return false;
 923     }
 924 

 925     public Raster readRaster(int imageIndex, ImageReadParam param)
 926             throws IOException {
 927         throw new UnsupportedOperationException();
 928     }
 929 
 930     private int[] sourceBands;
 931     private int[] destinationBands;
 932 
 933     private TIFFDecompressor decompressor;
 934 
 935     // floor(num/den)
 936     private static int ifloor(int num, int den) {
 937         if (num < 0) {
 938             num -= den - 1;
 939         }
 940         return num / den;
 941     }
 942 
 943     // ceil(num/den)
 944     private static int iceil(int num, int den) {


 992 
 993         if (sourceBands.length != destinationBands.length) {
 994             throw new IllegalArgumentException(
 995                     "sourceBands.length != destinationBands.length");
 996         }
 997 
 998         for (int i = 0; i < sourceBands.length; i++) {
 999             int sb = sourceBands[i];
1000             if (sb < 0 || sb >= numBands) {
1001                 throw new IllegalArgumentException(
1002                         "Source band out of range!");
1003             }
1004             int db = destinationBands[i];
1005             if (db < 0 || db >= destNumBands) {
1006                 throw new IllegalArgumentException(
1007                         "Destination band out of range!");
1008             }
1009         }
1010     }
1011 

1012     public RenderedImage readAsRenderedImage(int imageIndex,
1013             ImageReadParam param)
1014             throws IOException {
1015         prepareRead(imageIndex, param);
1016         return new TIFFRenderedImage(this, imageIndex, imageReadParam,
1017                 width, height);
1018     }
1019 
1020     private void decodeTile(int ti, int tj, int band) throws IOException {
1021         // Compute the region covered by the strip or tile
1022         Rectangle tileRect = new Rectangle(ti * tileOrStripWidth,
1023                 tj * tileOrStripHeight,
1024                 tileOrStripWidth,
1025                 tileOrStripHeight);
1026 
1027         // Clip against the image bounds if the image is not tiled. If it
1028         // is tiled, the tile may legally extend beyond the image bounds.
1029         if (!isImageTiled(currIndex)) {
1030             tileRect
1031                     = tileRect.intersection(new Rectangle(0, 0, width, height));


1118         decompressor.setOffset(offset);
1119         decompressor.setByteCount((int) byteCount);
1120 
1121         decompressor.beginDecoding();
1122 
1123         stream.mark();
1124         decompressor.decode();
1125         stream.reset();
1126     }
1127 
1128     private void reportProgress() {
1129         // Report image progress/update to listeners after each tile
1130         pixelsRead += dstWidth * dstHeight;
1131         processImageProgress(100.0f * pixelsRead / pixelsToRead);
1132         processImageUpdate(theImage,
1133                 dstMinX, dstMinY, dstWidth, dstHeight,
1134                 1, 1,
1135                 destinationBands);
1136     }
1137 

1138     public BufferedImage read(int imageIndex, ImageReadParam param)
1139             throws IOException {
1140         prepareRead(imageIndex, param);
1141         this.theImage = getDestination(param,
1142                 getImageTypes(imageIndex),
1143                 width, height);
1144 
1145         srcXSubsampling = imageReadParam.getSourceXSubsampling();
1146         srcYSubsampling = imageReadParam.getSourceYSubsampling();
1147 
1148         Point p = imageReadParam.getDestinationOffset();
1149         dstXOffset = p.x;
1150         dstYOffset = p.y;
1151 
1152         // This could probably be made more efficient...
1153         Rectangle srcRegion = new Rectangle(0, 0, 0, 0);
1154         Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1155 
1156         computeRegions(imageReadParam, width, height, theImage,
1157                 srcRegion, destRegion);


1336                     }
1337                 }
1338             }
1339         } else {
1340             for (int tj = minTileY; tj <= maxTileY; tj++) {
1341                 for (int ti = minTileX; ti <= maxTileX; ti++) {
1342                     decodeTile(ti, tj, -1);
1343 
1344                     reportProgress();
1345                     if (abortRequested()) {
1346                         processReadAborted();
1347                         return theImage;
1348                     }
1349                 }
1350             }
1351         }
1352         processImageComplete();
1353         return theImage;
1354     }
1355 

1356     public void reset() {
1357         super.reset();
1358         resetLocal();
1359     }
1360 
1361     protected void resetLocal() {
1362         stream = null;
1363         gotHeader = false;
1364         imageReadParam = getDefaultReadParam();
1365         streamMetadata = null;
1366         currIndex = -1;
1367         imageMetadata = null;
1368         imageStartPosition = new ArrayList<Long>();
1369         numImages = -1;
1370         imageTypeMap = new HashMap<Integer, List<ImageTypeSpecifier>>();
1371         width = -1;
1372         height = -1;
1373         numBands = -1;
1374         tileOrStripWidth = -1;
1375         tileOrStripHeight = -1;


 119     private int srcXSubsampling;
 120     private int srcYSubsampling;
 121 
 122     private int dstWidth;
 123     private int dstHeight;
 124     private int dstMinX;
 125     private int dstMinY;
 126     private int dstXOffset;
 127     private int dstYOffset;
 128 
 129     private int tilesAcross;
 130     private int tilesDown;
 131 
 132     private int pixelsRead;
 133     private int pixelsToRead;
 134 
 135     public TIFFImageReader(ImageReaderSpi originatingProvider) {
 136         super(originatingProvider);
 137     }
 138 
 139     @Override
 140     public void setInput(Object input,
 141             boolean seekForwardOnly,
 142             boolean ignoreMetadata) {
 143         super.setInput(input, seekForwardOnly, ignoreMetadata);
 144 
 145         // Clear all local values based on the previous stream contents.
 146         resetLocal();
 147 
 148         if (input != null) {
 149             if (!(input instanceof ImageInputStream)) {
 150                 throw new IllegalArgumentException("input not an ImageInputStream!");
 151             }
 152             this.stream = (ImageInputStream) input;
 153         } else {
 154             this.stream = null;
 155         }
 156     }
 157 
 158     // Do not seek to the beginning of the stream so as to allow users to
 159     // point us at an IFD within some other file format


 229                 stream.seek(offset);
 230                 imageStartPosition.add(Long.valueOf(offset));
 231                 ++index;
 232             }
 233         } catch (EOFException eofe) {
 234             forwardWarningMessage("Ignored " + eofe);
 235 
 236             // Ran off the end of stream: decrement index
 237             imageIndex = index > 0 ? index - 1 : 0;
 238         } catch (IOException ioe) {
 239             throw new IIOException("Couldn't seek!", ioe);
 240         }
 241 
 242         if (currIndex != imageIndex) {
 243             imageMetadata = null;
 244         }
 245         currIndex = imageIndex;
 246         return imageIndex;
 247     }
 248 
 249     @Override
 250     public int getNumImages(boolean allowSearch) throws IOException {
 251         if (stream == null) {
 252             throw new IllegalStateException("Input not set!");
 253         }
 254         if (seekForwardOnly && allowSearch) {
 255             throw new IllegalStateException("seekForwardOnly and allowSearch can't both be true!");
 256         }
 257 
 258         if (numImages > 0) {
 259             return numImages;
 260         }
 261         if (allowSearch) {
 262             this.numImages = locateImage(Integer.MAX_VALUE) + 1;
 263         }
 264         return numImages;
 265     }
 266 
 267     @Override
 268     public IIOMetadata getStreamMetadata() throws IIOException {
 269         readHeader();
 270         return streamMetadata;
 271     }
 272 
 273     // Throw an IndexOutOfBoundsException if index < minIndex,
 274     // and bump minIndex if required.
 275     private void checkIndex(int imageIndex) {
 276         if (imageIndex < minIndex) {
 277             throw new IndexOutOfBoundsException("imageIndex < minIndex!");
 278         }
 279         if (seekForwardOnly) {
 280             minIndex = imageIndex;
 281         }
 282     }
 283 
 284     // Verify that imageIndex is in bounds, find the image IFD, read the
 285     // image metadata, initialize instance variables from the metadata.
 286     private void seekToImage(int imageIndex) throws IIOException {
 287         checkIndex(imageIndex);


 473                         = Math.min(tileOrStripByteCount,
 474                                 streamLength - getTileOrStripOffset(tileIndex));
 475             } else {
 476                 processWarningOccurred("Stream length is unknown: cannot clamp estimated strip or tile byte count to EOF.");
 477             }
 478         }
 479 
 480         return tileOrStripByteCount;
 481     }
 482 
 483     private int getCompression() {
 484         TIFFField f
 485                 = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
 486         if (f == null) {
 487             return BaselineTIFFTagSet.COMPRESSION_NONE;
 488         } else {
 489             return f.getAsInt(0);
 490         }
 491     }
 492 
 493     @Override
 494     public int getWidth(int imageIndex) throws IOException {
 495         seekToImage(imageIndex);
 496         return getWidth();
 497     }
 498 
 499     @Override
 500     public int getHeight(int imageIndex) throws IOException {
 501         seekToImage(imageIndex);
 502         return getHeight();
 503     }
 504 
 505     /**
 506      * Initializes these instance variables from the image metadata:
 507      * <pre>
 508      * compression
 509      * width
 510      * height
 511      * samplesPerPixel
 512      * numBands
 513      * colorMap
 514      * photometricInterpretation
 515      * sampleFormat
 516      * bitsPerSample
 517      * extraSamples
 518      * tileOrStripWidth
 519      * tileOrStripHeight


 687 
 688         for (int i = 0; i < samplesPerPixel; i++) {
 689             // Replicate initial value if not enough values provided
 690             bitsPerSample[i] = replicateFirst ? first : f.getAsInt(i);
 691             if (bitsPerSample[i] > BITS_PER_SAMPLE_MAX) {
 692                 throw new IIOException
 693                     ("Bits per sample (" + bitsPerSample[i]
 694                     + ") greater than allowed maximum ("
 695                     + BITS_PER_SAMPLE_MAX + ")");
 696             }
 697         }
 698 
 699         // ExtraSamples
 700         this.extraSamples = null;
 701         f = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
 702         if (f != null) {
 703             extraSamples = f.getAsInts();
 704         }
 705     }
 706 
 707     @Override
 708     public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IIOException {
 709         List<ImageTypeSpecifier> l; // List of ImageTypeSpecifiers
 710 
 711         Integer imageIndexInteger = Integer.valueOf(imageIndex);
 712         if (imageTypeMap.containsKey(imageIndexInteger)) {
 713             // Return the cached ITS List.
 714             l = imageTypeMap.get(imageIndexInteger);
 715         } else {
 716             // Create a new ITS List.
 717             l = new ArrayList<ImageTypeSpecifier>(1);
 718 
 719             // Create the ITS and cache if for later use so that this method
 720             // always returns an Iterator containing the same ITS objects.
 721             seekToImage(imageIndex);
 722             ImageTypeSpecifier itsRaw
 723                     = TIFFDecompressor.getRawImageTypeSpecifier(photometricInterpretation,
 724                             compression,
 725                             samplesPerPixel,
 726                             bitsPerSample,
 727                             sampleFormat,


 815                             && csRaw.getNumComponents()
 816                             == iccColorSpace.getNumComponents()) {
 817                         l.add(itsRaw);
 818                     }
 819                 } else { // ICCProfile not compatible with SampleModel.
 820                     // Append the raw ITS to the List.
 821                     l.add(itsRaw);
 822                 }
 823             } else { // No ICCProfile field or raw ColorModel not component.
 824                 // Append the raw ITS to the List.
 825                 l.add(itsRaw);
 826             }
 827 
 828             // Cache the ITS List.
 829             imageTypeMap.put(imageIndexInteger, l);
 830         }
 831 
 832         return l.iterator();
 833     }
 834 
 835     @Override
 836     public IIOMetadata getImageMetadata(int imageIndex) throws IIOException {
 837         seekToImage(imageIndex);
 838         TIFFImageMetadata im
 839                 = new TIFFImageMetadata(imageMetadata.getRootIFD().getTagSetList());
 840         Node root
 841                 = imageMetadata.getAsTree(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME);
 842         im.setFromTree(TIFFImageMetadata.NATIVE_METADATA_FORMAT_NAME, root);
 843         return im;
 844     }
 845 
 846     public IIOMetadata getStreamMetadata(int imageIndex) throws IIOException {
 847         readHeader();
 848         TIFFStreamMetadata sm = new TIFFStreamMetadata();
 849         Node root = sm.getAsTree(TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME);
 850         sm.setFromTree(TIFFStreamMetadata.NATIVE_METADATA_FORMAT_NAME, root);
 851         return sm;
 852     }
 853 
 854     @Override
 855     public boolean isRandomAccessEasy(int imageIndex) throws IOException {
 856         if (currIndex != -1) {
 857             seekToImage(currIndex);
 858             return getCompression() == BaselineTIFFTagSet.COMPRESSION_NONE;
 859         } else {
 860             return false;
 861         }
 862     }
 863 
 864     // Thumbnails
 865     public boolean readSupportsThumbnails() {
 866         return false;
 867     }
 868 
 869     @Override
 870     public boolean hasThumbnails(int imageIndex) {
 871         return false;
 872     }
 873 
 874     @Override
 875     public int getNumThumbnails(int imageIndex) throws IOException {
 876         return 0;
 877     }
 878 
 879     @Override
 880     public ImageReadParam getDefaultReadParam() {
 881         return new TIFFImageReadParam();
 882     }
 883 
 884     @Override
 885     public boolean isImageTiled(int imageIndex) throws IOException {
 886         seekToImage(imageIndex);
 887 
 888         TIFFField f
 889                 = imageMetadata.getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
 890         return f != null;
 891     }
 892 
 893     @Override
 894     public int getTileWidth(int imageIndex) throws IOException {
 895         seekToImage(imageIndex);
 896         return getTileOrStripWidth();
 897     }
 898 
 899     @Override
 900     public int getTileHeight(int imageIndex) throws IOException {
 901         seekToImage(imageIndex);
 902         return getTileOrStripHeight();
 903     }
 904 
 905     @Override
 906     public BufferedImage readTile(int imageIndex, int tileX, int tileY)
 907             throws IOException {
 908 
 909         int w = getWidth(imageIndex);
 910         int h = getHeight(imageIndex);
 911         int tw = getTileWidth(imageIndex);
 912         int th = getTileHeight(imageIndex);
 913 
 914         int x = tw * tileX;
 915         int y = th * tileY;
 916 
 917         if (tileX < 0 || tileY < 0 || x >= w || y >= h) {
 918             throw new IllegalArgumentException("Tile indices are out of bounds!");
 919         }
 920 
 921         if (x + tw > w) {
 922             tw = w - x;
 923         }
 924 
 925         if (y + th > h) {
 926             th = h - y;
 927         }
 928 
 929         ImageReadParam param = getDefaultReadParam();
 930         Rectangle tileRect = new Rectangle(x, y, tw, th);
 931         param.setSourceRegion(tileRect);
 932 
 933         return read(imageIndex, param);
 934     }
 935 
 936     @Override
 937     public boolean canReadRaster() {
 938         return false;
 939     }
 940 
 941     @Override
 942     public Raster readRaster(int imageIndex, ImageReadParam param)
 943             throws IOException {
 944         throw new UnsupportedOperationException();
 945     }
 946 
 947     private int[] sourceBands;
 948     private int[] destinationBands;
 949 
 950     private TIFFDecompressor decompressor;
 951 
 952     // floor(num/den)
 953     private static int ifloor(int num, int den) {
 954         if (num < 0) {
 955             num -= den - 1;
 956         }
 957         return num / den;
 958     }
 959 
 960     // ceil(num/den)
 961     private static int iceil(int num, int den) {


1009 
1010         if (sourceBands.length != destinationBands.length) {
1011             throw new IllegalArgumentException(
1012                     "sourceBands.length != destinationBands.length");
1013         }
1014 
1015         for (int i = 0; i < sourceBands.length; i++) {
1016             int sb = sourceBands[i];
1017             if (sb < 0 || sb >= numBands) {
1018                 throw new IllegalArgumentException(
1019                         "Source band out of range!");
1020             }
1021             int db = destinationBands[i];
1022             if (db < 0 || db >= destNumBands) {
1023                 throw new IllegalArgumentException(
1024                         "Destination band out of range!");
1025             }
1026         }
1027     }
1028 
1029     @Override
1030     public RenderedImage readAsRenderedImage(int imageIndex,
1031             ImageReadParam param)
1032             throws IOException {
1033         prepareRead(imageIndex, param);
1034         return new TIFFRenderedImage(this, imageIndex, imageReadParam,
1035                 width, height);
1036     }
1037 
1038     private void decodeTile(int ti, int tj, int band) throws IOException {
1039         // Compute the region covered by the strip or tile
1040         Rectangle tileRect = new Rectangle(ti * tileOrStripWidth,
1041                 tj * tileOrStripHeight,
1042                 tileOrStripWidth,
1043                 tileOrStripHeight);
1044 
1045         // Clip against the image bounds if the image is not tiled. If it
1046         // is tiled, the tile may legally extend beyond the image bounds.
1047         if (!isImageTiled(currIndex)) {
1048             tileRect
1049                     = tileRect.intersection(new Rectangle(0, 0, width, height));


1136         decompressor.setOffset(offset);
1137         decompressor.setByteCount((int) byteCount);
1138 
1139         decompressor.beginDecoding();
1140 
1141         stream.mark();
1142         decompressor.decode();
1143         stream.reset();
1144     }
1145 
1146     private void reportProgress() {
1147         // Report image progress/update to listeners after each tile
1148         pixelsRead += dstWidth * dstHeight;
1149         processImageProgress(100.0f * pixelsRead / pixelsToRead);
1150         processImageUpdate(theImage,
1151                 dstMinX, dstMinY, dstWidth, dstHeight,
1152                 1, 1,
1153                 destinationBands);
1154     }
1155 
1156     @Override
1157     public BufferedImage read(int imageIndex, ImageReadParam param)
1158             throws IOException {
1159         prepareRead(imageIndex, param);
1160         this.theImage = getDestination(param,
1161                 getImageTypes(imageIndex),
1162                 width, height);
1163 
1164         srcXSubsampling = imageReadParam.getSourceXSubsampling();
1165         srcYSubsampling = imageReadParam.getSourceYSubsampling();
1166 
1167         Point p = imageReadParam.getDestinationOffset();
1168         dstXOffset = p.x;
1169         dstYOffset = p.y;
1170 
1171         // This could probably be made more efficient...
1172         Rectangle srcRegion = new Rectangle(0, 0, 0, 0);
1173         Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1174 
1175         computeRegions(imageReadParam, width, height, theImage,
1176                 srcRegion, destRegion);


1355                     }
1356                 }
1357             }
1358         } else {
1359             for (int tj = minTileY; tj <= maxTileY; tj++) {
1360                 for (int ti = minTileX; ti <= maxTileX; ti++) {
1361                     decodeTile(ti, tj, -1);
1362 
1363                     reportProgress();
1364                     if (abortRequested()) {
1365                         processReadAborted();
1366                         return theImage;
1367                     }
1368                 }
1369             }
1370         }
1371         processImageComplete();
1372         return theImage;
1373     }
1374 
1375     @Override
1376     public void reset() {
1377         super.reset();
1378         resetLocal();
1379     }
1380 
1381     protected void resetLocal() {
1382         stream = null;
1383         gotHeader = false;
1384         imageReadParam = getDefaultReadParam();
1385         streamMetadata = null;
1386         currIndex = -1;
1387         imageMetadata = null;
1388         imageStartPosition = new ArrayList<Long>();
1389         numImages = -1;
1390         imageTypeMap = new HashMap<Integer, List<ImageTypeSpecifier>>();
1391         width = -1;
1392         height = -1;
1393         numBands = -1;
1394         tileOrStripWidth = -1;
1395         tileOrStripHeight = -1;
< prev index next >