Source Code Cross Referenced for TIFFImageReader.java in  » 6.0-JDK-Modules » Java-Advanced-Imaging » com » sun » media » imageioimpl » plugins » tiff » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » 6.0 JDK Modules » Java Advanced Imaging » com.sun.media.imageioimpl.plugins.tiff 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $RCSfile: TIFFImageReader.java,v $
0003:         *
0004:         * 
0005:         * Copyright (c) 2005 Sun Microsystems, Inc. All  Rights Reserved.
0006:         * 
0007:         * Redistribution and use in source and binary forms, with or without
0008:         * modification, are permitted provided that the following conditions
0009:         * are met: 
0010:         * 
0011:         * - Redistribution of source code must retain the above copyright 
0012:         *   notice, this  list of conditions and the following disclaimer.
0013:         * 
0014:         * - Redistribution in binary form must reproduce the above copyright
0015:         *   notice, this list of conditions and the following disclaimer in 
0016:         *   the documentation and/or other materials provided with the
0017:         *   distribution.
0018:         * 
0019:         * Neither the name of Sun Microsystems, Inc. or the names of 
0020:         * contributors may be used to endorse or promote products derived 
0021:         * from this software without specific prior written permission.
0022:         * 
0023:         * This software is provided "AS IS," without a warranty of any 
0024:         * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND 
0025:         * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, 
0026:         * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0027:         * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL 
0028:         * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF 
0029:         * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0030:         * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR 
0031:         * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0032:         * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0033:         * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0034:         * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0035:         * POSSIBILITY OF SUCH DAMAGES. 
0036:         * 
0037:         * You acknowledge that this software is not designed or intended for 
0038:         * use in the design, construction, operation or maintenance of any 
0039:         * nuclear facility. 
0040:         *
0041:         * $Revision: 1.13 $
0042:         * $Date: 2007/12/19 20:17:02 $
0043:         * $State: Exp $
0044:         */
0045:        package com.sun.media.imageioimpl.plugins.tiff;
0046:
0047:        import java.awt.Point;
0048:        import java.awt.Rectangle;
0049:        import java.awt.color.ColorSpace;
0050:        import java.awt.color.ICC_ColorSpace;
0051:        import java.awt.color.ICC_Profile;
0052:        import java.awt.image.BufferedImage;
0053:        import java.awt.image.ColorModel;
0054:        import java.awt.image.ComponentColorModel;
0055:        import java.awt.image.ComponentSampleModel;
0056:        import java.awt.image.DataBuffer;
0057:        import java.awt.image.DataBufferByte;
0058:        import java.awt.image.MultiPixelPackedSampleModel;
0059:        import java.awt.image.Raster;
0060:        import java.awt.image.RenderedImage;
0061:        import java.awt.image.SampleModel;
0062:        import java.awt.image.SinglePixelPackedSampleModel;
0063:        import java.awt.image.WritableRaster;
0064:        import java.io.ByteArrayInputStream;
0065:        import java.io.IOException;
0066:        import java.io.InputStream;
0067:        import java.nio.ByteOrder;
0068:        import java.util.ArrayList;
0069:        import java.util.Arrays;
0070:        import java.util.HashMap;
0071:        import java.util.Iterator;
0072:        import java.util.List;
0073:        import javax.imageio.IIOException;
0074:        import javax.imageio.ImageIO;
0075:        import javax.imageio.ImageReader;
0076:        import javax.imageio.ImageReadParam;
0077:        import javax.imageio.ImageTypeSpecifier;
0078:        import javax.imageio.metadata.IIOMetadata;
0079:        import javax.imageio.spi.ImageReaderSpi;
0080:        import javax.imageio.stream.ImageInputStream;
0081:        import javax.imageio.stream.MemoryCacheImageInputStream;
0082:        import org.w3c.dom.Node;
0083:        import com.sun.media.imageio.plugins.tiff.BaselineTIFFTagSet;
0084:        import com.sun.media.imageio.plugins.tiff.TIFFColorConverter;
0085:        import com.sun.media.imageio.plugins.tiff.TIFFDecompressor;
0086:        import com.sun.media.imageio.plugins.tiff.TIFFField;
0087:        import com.sun.media.imageio.plugins.tiff.TIFFImageReadParam;
0088:        import com.sun.media.imageio.plugins.tiff.TIFFTag;
0089:        import com.sun.media.imageioimpl.common.ImageUtil;
0090:        import com.sun.media.imageioimpl.common.PackageUtil;
0091:
0092:        public class TIFFImageReader extends ImageReader {
0093:
0094:            private static final boolean DEBUG = false; // XXX 'false' for release!!!
0095:
0096:            // The current ImageInputStream source.
0097:            ImageInputStream stream = null;
0098:
0099:            // True if the file header has been read.
0100:            boolean gotHeader = false;
0101:
0102:            ImageReadParam imageReadParam = getDefaultReadParam();
0103:
0104:            // Stream metadata, or null.
0105:            TIFFStreamMetadata streamMetadata = null;
0106:
0107:            // The current image index.
0108:            int currIndex = -1;
0109:
0110:            // Metadata for image at 'currIndex', or null.
0111:            TIFFImageMetadata imageMetadata = null;
0112:
0113:            // A <code>List</code> of <code>Long</code>s indicating the stream
0114:            // positions of the start of the IFD for each image.  Entries
0115:            // are added as needed.
0116:            List imageStartPosition = new ArrayList();
0117:
0118:            // The number of images in the stream, if known, otherwise -1.
0119:            int numImages = -1;
0120:
0121:            // The ImageTypeSpecifiers of the images in the stream.
0122:            // Contains a map of Integers to Lists.
0123:            HashMap imageTypeMap = new HashMap();
0124:
0125:            BufferedImage theImage = null;
0126:
0127:            int width = -1;
0128:            int height = -1;
0129:            int numBands = -1;
0130:            int tileOrStripWidth = -1, tileOrStripHeight = -1;
0131:
0132:            int planarConfiguration = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0133:
0134:            int rowsDone = 0;
0135:
0136:            int compression;
0137:            int photometricInterpretation;
0138:            int samplesPerPixel;
0139:            int[] sampleFormat;
0140:            int[] bitsPerSample;
0141:            int[] extraSamples;
0142:            char[] colorMap;
0143:
0144:            int sourceXOffset;
0145:            int sourceYOffset;
0146:            int srcXSubsampling;
0147:            int srcYSubsampling;
0148:
0149:            int dstWidth;
0150:            int dstHeight;
0151:            int dstMinX;
0152:            int dstMinY;
0153:            int dstXOffset;
0154:            int dstYOffset;
0155:
0156:            int tilesAcross;
0157:            int tilesDown;
0158:
0159:            int pixelsRead;
0160:            int pixelsToRead;
0161:
0162:            public TIFFImageReader(ImageReaderSpi originatingProvider) {
0163:                super (originatingProvider);
0164:            }
0165:
0166:            public void setInput(Object input, boolean seekForwardOnly,
0167:                    boolean ignoreMetadata) {
0168:                super .setInput(input, seekForwardOnly, ignoreMetadata);
0169:
0170:                // Clear all local values based on the previous stream contents.
0171:                resetLocal();
0172:
0173:                if (input != null) {
0174:                    if (!(input instanceof  ImageInputStream)) {
0175:                        throw new IllegalArgumentException(
0176:                                "input not an ImageInputStream!");
0177:                    }
0178:                    this .stream = (ImageInputStream) input;
0179:                } else {
0180:                    this .stream = null;
0181:                }
0182:            }
0183:
0184:            // Do not seek to the beginning of the stream so as to allow users to
0185:            // point us at an IFD within some other file format
0186:            private void readHeader() throws IIOException {
0187:                if (gotHeader) {
0188:                    return;
0189:                }
0190:                if (stream == null) {
0191:                    throw new IllegalStateException("Input not set!");
0192:                }
0193:
0194:                // Create an object to store the stream metadata
0195:                this .streamMetadata = new TIFFStreamMetadata();
0196:
0197:                try {
0198:                    int byteOrder = stream.readUnsignedShort();
0199:                    if (byteOrder == 0x4d4d) {
0200:                        streamMetadata.byteOrder = ByteOrder.BIG_ENDIAN;
0201:                        stream.setByteOrder(ByteOrder.BIG_ENDIAN);
0202:                    } else if (byteOrder == 0x4949) {
0203:                        streamMetadata.byteOrder = ByteOrder.LITTLE_ENDIAN;
0204:                        stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
0205:                    } else {
0206:                        processWarningOccurred("Bad byte order in header, assuming little-endian");
0207:                        streamMetadata.byteOrder = ByteOrder.LITTLE_ENDIAN;
0208:                        stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
0209:                    }
0210:
0211:                    int magic = stream.readUnsignedShort();
0212:                    if (magic != 42) {
0213:                        processWarningOccurred("Bad magic number in header, continuing");
0214:                    }
0215:
0216:                    // Seek to start of first IFD
0217:                    long offset = stream.readUnsignedInt();
0218:                    imageStartPosition.add(new Long(offset));
0219:                    stream.seek(offset);
0220:                } catch (IOException e) {
0221:                    throw new IIOException("I/O error reading header!", e);
0222:                }
0223:
0224:                gotHeader = true;
0225:            }
0226:
0227:            private int locateImage(int imageIndex) throws IIOException {
0228:                readHeader();
0229:
0230:                try {
0231:                    // Find closest known index
0232:                    int index = Math.min(imageIndex,
0233:                            imageStartPosition.size() - 1);
0234:
0235:                    // Seek to that position
0236:                    Long l = (Long) imageStartPosition.get(index);
0237:                    stream.seek(l.longValue());
0238:
0239:                    // Skip IFDs until at desired index or last image found
0240:                    while (index < imageIndex) {
0241:                        int count = stream.readUnsignedShort();
0242:                        stream.skipBytes(12 * count);
0243:
0244:                        long offset = stream.readUnsignedInt();
0245:                        if (offset == 0) {
0246:                            return index;
0247:                        }
0248:
0249:                        imageStartPosition.add(new Long(offset));
0250:                        stream.seek(offset);
0251:                        ++index;
0252:                    }
0253:                } catch (IOException e) {
0254:                    throw new IIOException("Couldn't seek!", e);
0255:                }
0256:
0257:                if (currIndex != imageIndex) {
0258:                    imageMetadata = null;
0259:                }
0260:                currIndex = imageIndex;
0261:                return imageIndex;
0262:            }
0263:
0264:            public int getNumImages(boolean allowSearch) throws IOException {
0265:                if (stream == null) {
0266:                    throw new IllegalStateException("Input not set!");
0267:                }
0268:                if (seekForwardOnly && allowSearch) {
0269:                    throw new IllegalStateException(
0270:                            "seekForwardOnly and allowSearch can't both be true!");
0271:                }
0272:
0273:                if (numImages > 0) {
0274:                    return numImages;
0275:                }
0276:                if (allowSearch) {
0277:                    this .numImages = locateImage(Integer.MAX_VALUE) + 1;
0278:                }
0279:                return numImages;
0280:            }
0281:
0282:            public IIOMetadata getStreamMetadata() throws IIOException {
0283:                readHeader();
0284:                return streamMetadata;
0285:            }
0286:
0287:            // Throw an IndexOutOfBoundsException if index < minIndex,
0288:            // and bump minIndex if required.
0289:            private void checkIndex(int imageIndex) {
0290:                if (imageIndex < minIndex) {
0291:                    throw new IndexOutOfBoundsException(
0292:                            "imageIndex < minIndex!");
0293:                }
0294:                if (seekForwardOnly) {
0295:                    minIndex = imageIndex;
0296:                }
0297:            }
0298:
0299:            // Verify that imageIndex is in bounds, find the image IFD, read the
0300:            // image metadata, initialize instance variables from the metadata.
0301:            private void seekToImage(int imageIndex) throws IIOException {
0302:                checkIndex(imageIndex);
0303:
0304:                int index = locateImage(imageIndex);
0305:                if (index != imageIndex) {
0306:                    throw new IndexOutOfBoundsException(
0307:                            "imageIndex out of bounds!");
0308:                }
0309:
0310:                readMetadata();
0311:
0312:                initializeFromMetadata();
0313:            }
0314:
0315:            // Stream must be positioned at start of IFD for 'currIndex'
0316:            private void readMetadata() throws IIOException {
0317:                if (stream == null) {
0318:                    throw new IllegalStateException("Input not set!");
0319:                }
0320:
0321:                if (imageMetadata != null) {
0322:                    return;
0323:                }
0324:                try {
0325:                    // Create an object to store the image metadata
0326:                    List tagSets;
0327:                    if (imageReadParam instanceof  TIFFImageReadParam) {
0328:                        tagSets = ((TIFFImageReadParam) imageReadParam)
0329:                                .getAllowedTagSets();
0330:                    } else {
0331:                        tagSets = new ArrayList(1);
0332:                        tagSets.add(BaselineTIFFTagSet.getInstance());
0333:                    }
0334:
0335:                    this .imageMetadata = new TIFFImageMetadata(tagSets);
0336:                    imageMetadata.initializeFromStream(stream, ignoreMetadata);
0337:                } catch (IIOException iioe) {
0338:                    throw iioe;
0339:                } catch (IOException ioe) {
0340:                    throw new IIOException("I/O error reading image metadata!",
0341:                            ioe);
0342:                }
0343:            }
0344:
0345:            private int getWidth() {
0346:                return this .width;
0347:            }
0348:
0349:            private int getHeight() {
0350:                return this .height;
0351:            }
0352:
0353:            private int getNumBands() {
0354:                return this .numBands;
0355:            }
0356:
0357:            // Returns tile width if image is tiled, else image width
0358:            private int getTileOrStripWidth() {
0359:                TIFFField f = imageMetadata
0360:                        .getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
0361:                return (f == null) ? getWidth() : f.getAsInt(0);
0362:            }
0363:
0364:            // Returns tile height if image is tiled, else strip height
0365:            private int getTileOrStripHeight() {
0366:                TIFFField f = imageMetadata
0367:                        .getTIFFField(BaselineTIFFTagSet.TAG_TILE_LENGTH);
0368:                if (f != null) {
0369:                    return f.getAsInt(0);
0370:                }
0371:
0372:                f = imageMetadata
0373:                        .getTIFFField(BaselineTIFFTagSet.TAG_ROWS_PER_STRIP);
0374:                // Default for ROWS_PER_STRIP is 2^32 - 1, i.e., infinity
0375:                int h = (f == null) ? -1 : f.getAsInt(0);
0376:                return (h == -1) ? getHeight() : h;
0377:            }
0378:
0379:            private int getPlanarConfiguration() {
0380:                TIFFField f = imageMetadata
0381:                        .getTIFFField(BaselineTIFFTagSet.TAG_PLANAR_CONFIGURATION);
0382:                if (f != null) {
0383:                    int planarConfigurationValue = f.getAsInt(0);
0384:                    if (planarConfigurationValue == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
0385:                        // Some writers (e.g. Kofax standard Multi-Page TIFF
0386:                        // Storage Filter v2.01.000; cf. bug 4929147) do not
0387:                        // correctly set the value of this field. Attempt to
0388:                        // ascertain whether the value is correctly Planar.
0389:                        if (getCompression() == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG
0390:                                && imageMetadata
0391:                                        .getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT) != null) {
0392:                            // JPEG interchange format cannot have
0393:                            // PlanarConfiguration value Chunky so reset.
0394:                            processWarningOccurred("PlanarConfiguration \"Planar\" value inconsistent with JPEGInterchangeFormat; resetting to \"Chunky\".");
0395:                            planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0396:                        } else {
0397:                            TIFFField offsetField = imageMetadata
0398:                                    .getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
0399:                            if (offsetField == null) {
0400:                                // Tiles
0401:                                offsetField = imageMetadata
0402:                                        .getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
0403:                                int tw = getTileOrStripWidth();
0404:                                int th = getTileOrStripHeight();
0405:                                int tAcross = (getWidth() + tw - 1) / tw;
0406:                                int tDown = (getHeight() + th - 1) / th;
0407:                                int tilesPerImage = tAcross * tDown;
0408:                                long[] offsetArray = offsetField.getAsLongs();
0409:                                if (offsetArray != null
0410:                                        && offsetArray.length == tilesPerImage) {
0411:                                    // Length of offsets array is
0412:                                    // TilesPerImage for Chunky and
0413:                                    // SamplesPerPixel*TilesPerImage for Planar.
0414:                                    processWarningOccurred("PlanarConfiguration \"Planar\" value inconsistent with TileOffsets field value count; resetting to \"Chunky\".");
0415:                                    planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0416:                                }
0417:                            } else {
0418:                                // Strips
0419:                                int rowsPerStrip = getTileOrStripHeight();
0420:                                int stripsPerImage = (getHeight()
0421:                                        + rowsPerStrip - 1)
0422:                                        / rowsPerStrip;
0423:                                long[] offsetArray = offsetField.getAsLongs();
0424:                                if (offsetArray != null
0425:                                        && offsetArray.length == stripsPerImage) {
0426:                                    // Length of offsets array is
0427:                                    // StripsPerImage for Chunky and
0428:                                    // SamplesPerPixel*StripsPerImage for Planar.
0429:                                    processWarningOccurred("PlanarConfiguration \"Planar\" value inconsistent with StripOffsets field value count; resetting to \"Chunky\".");
0430:                                    planarConfigurationValue = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0431:                                }
0432:                            }
0433:                        }
0434:                    }
0435:                    return planarConfigurationValue;
0436:                }
0437:
0438:                return BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
0439:            }
0440:
0441:            private long getTileOrStripOffset(int tileIndex)
0442:                    throws IIOException {
0443:                TIFFField f = imageMetadata
0444:                        .getTIFFField(BaselineTIFFTagSet.TAG_TILE_OFFSETS);
0445:                if (f == null) {
0446:                    f = imageMetadata
0447:                            .getTIFFField(BaselineTIFFTagSet.TAG_STRIP_OFFSETS);
0448:                }
0449:                if (f == null) {
0450:                    f = imageMetadata
0451:                            .getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT);
0452:                }
0453:
0454:                if (f == null) {
0455:                    throw new IIOException(
0456:                            "Missing required strip or tile offsets field.");
0457:                }
0458:
0459:                return f.getAsLong(tileIndex);
0460:            }
0461:
0462:            private long getTileOrStripByteCount(int tileIndex)
0463:                    throws IOException {
0464:                TIFFField f = imageMetadata
0465:                        .getTIFFField(BaselineTIFFTagSet.TAG_TILE_BYTE_COUNTS);
0466:                if (f == null) {
0467:                    f = imageMetadata
0468:                            .getTIFFField(BaselineTIFFTagSet.TAG_STRIP_BYTE_COUNTS);
0469:                }
0470:                if (f == null) {
0471:                    f = imageMetadata
0472:                            .getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT_LENGTH);
0473:                }
0474:
0475:                long tileOrStripByteCount;
0476:                if (f != null) {
0477:                    tileOrStripByteCount = f.getAsLong(tileIndex);
0478:                } else {
0479:                    processWarningOccurred("TIFF directory contains neither StripByteCounts nor TileByteCounts field: attempting to calculate from strip or tile width and height.");
0480:
0481:                    // Initialize to number of bytes per strip or tile assuming
0482:                    // no compression.
0483:                    int bitsPerPixel = bitsPerSample[0];
0484:                    for (int i = 1; i < samplesPerPixel; i++) {
0485:                        bitsPerPixel += bitsPerSample[i];
0486:                    }
0487:                    int bytesPerRow = (getTileOrStripWidth() * bitsPerPixel + 7) / 8;
0488:                    tileOrStripByteCount = bytesPerRow * getTileOrStripHeight();
0489:
0490:                    // Clamp to end of stream if possible.
0491:                    long streamLength = stream.length();
0492:                    if (streamLength != -1) {
0493:                        tileOrStripByteCount = Math.min(tileOrStripByteCount,
0494:                                streamLength - getTileOrStripOffset(tileIndex));
0495:                    } else {
0496:                        processWarningOccurred("Stream length is unknown: cannot clamp estimated strip or tile byte count to EOF.");
0497:                    }
0498:                }
0499:
0500:                return tileOrStripByteCount;
0501:            }
0502:
0503:            private int getCompression() {
0504:                TIFFField f = imageMetadata
0505:                        .getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
0506:                if (f == null) {
0507:                    return BaselineTIFFTagSet.COMPRESSION_NONE;
0508:                } else {
0509:                    return f.getAsInt(0);
0510:                }
0511:            }
0512:
0513:            public int getWidth(int imageIndex) throws IOException {
0514:                seekToImage(imageIndex);
0515:                return getWidth();
0516:            }
0517:
0518:            public int getHeight(int imageIndex) throws IOException {
0519:                seekToImage(imageIndex);
0520:                return getHeight();
0521:            }
0522:
0523:            /**
0524:             * Initializes these instance variables from the image metadata:
0525:             * <pre>
0526:             * compression
0527:             * width
0528:             * height
0529:             * samplesPerPixel
0530:             * numBands
0531:             * colorMap
0532:             * photometricInterpretation
0533:             * sampleFormat
0534:             * bitsPerSample
0535:             * extraSamples
0536:             * tileOrStripWidth
0537:             * tileOrStripHeight
0538:             * </pre>
0539:             */
0540:            private void initializeFromMetadata() {
0541:                TIFFField f;
0542:
0543:                // Compression
0544:                f = imageMetadata
0545:                        .getTIFFField(BaselineTIFFTagSet.TAG_COMPRESSION);
0546:                if (f == null) {
0547:                    processWarningOccurred("Compression field is missing; assuming no compression");
0548:                    compression = BaselineTIFFTagSet.COMPRESSION_NONE;
0549:                } else {
0550:                    compression = f.getAsInt(0);
0551:                }
0552:
0553:                // Whether key dimensional information is absent.
0554:                boolean isMissingDimension = false;
0555:
0556:                // ImageWidth -> width
0557:                f = imageMetadata
0558:                        .getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH);
0559:                if (f != null) {
0560:                    this .width = f.getAsInt(0);
0561:                } else {
0562:                    processWarningOccurred("ImageWidth field is missing.");
0563:                    isMissingDimension = true;
0564:                }
0565:
0566:                // ImageLength -> height
0567:                f = imageMetadata
0568:                        .getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH);
0569:                if (f != null) {
0570:                    this .height = f.getAsInt(0);
0571:                } else {
0572:                    processWarningOccurred("ImageLength field is missing.");
0573:                    isMissingDimension = true;
0574:                }
0575:
0576:                // SamplesPerPixel
0577:                f = imageMetadata
0578:                        .getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL);
0579:                if (f != null) {
0580:                    samplesPerPixel = f.getAsInt(0);
0581:                } else {
0582:                    samplesPerPixel = 1;
0583:                    isMissingDimension = true;
0584:                }
0585:
0586:                // If any dimension is missing and there is a JPEG stream available
0587:                // get the information from it.
0588:                int defaultBitDepth = 1;
0589:                if (isMissingDimension
0590:                        && (f = imageMetadata
0591:                                .getTIFFField(BaselineTIFFTagSet.TAG_JPEG_INTERCHANGE_FORMAT)) != null) {
0592:                    Iterator iter = ImageIO.getImageReadersByFormatName("JPEG");
0593:                    if (iter != null && iter.hasNext()) {
0594:                        ImageReader jreader = (ImageReader) iter.next();
0595:                        try {
0596:                            stream.mark();
0597:                            stream.seek(f.getAsLong(0));
0598:                            jreader.setInput(stream);
0599:                            if (imageMetadata
0600:                                    .getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_WIDTH) == null) {
0601:                                this .width = jreader.getWidth(0);
0602:                            }
0603:                            if (imageMetadata
0604:                                    .getTIFFField(BaselineTIFFTagSet.TAG_IMAGE_LENGTH) == null) {
0605:                                this .height = jreader.getHeight(0);
0606:                            }
0607:                            ImageTypeSpecifier imageType = jreader
0608:                                    .getRawImageType(0);
0609:                            if (imageMetadata
0610:                                    .getTIFFField(BaselineTIFFTagSet.TAG_SAMPLES_PER_PIXEL) == null) {
0611:                                this .samplesPerPixel = imageType
0612:                                        .getSampleModel().getNumBands();
0613:                            }
0614:                            stream.reset();
0615:                            defaultBitDepth = imageType.getColorModel()
0616:                                    .getComponentSize(0);
0617:                        } catch (IOException e) {
0618:                            // Ignore it and proceed: an error will occur later.
0619:                        }
0620:                        jreader.dispose();
0621:                    }
0622:                }
0623:
0624:                if (samplesPerPixel < 1) {
0625:                    processWarningOccurred("Samples per pixel < 1!");
0626:                }
0627:
0628:                // SamplesPerPixel -> numBands
0629:                numBands = samplesPerPixel;
0630:
0631:                // ColorMap
0632:                this .colorMap = null;
0633:                f = imageMetadata
0634:                        .getTIFFField(BaselineTIFFTagSet.TAG_COLOR_MAP);
0635:                if (f != null) {
0636:                    // Grab color map
0637:                    colorMap = f.getAsChars();
0638:                }
0639:
0640:                // PhotometricInterpretation
0641:                f = imageMetadata
0642:                        .getTIFFField(BaselineTIFFTagSet.TAG_PHOTOMETRIC_INTERPRETATION);
0643:                if (f == null) {
0644:                    if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE
0645:                            || compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4
0646:                            || compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) {
0647:                        processWarningOccurred("PhotometricInterpretation field is missing; "
0648:                                + "assuming WhiteIsZero");
0649:                        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_WHITE_IS_ZERO;
0650:                    } else if (this .colorMap != null) {
0651:                        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_PALETTE_COLOR;
0652:                    } else if (samplesPerPixel == 3 || samplesPerPixel == 4) {
0653:                        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_RGB;
0654:                    } else {
0655:                        processWarningOccurred("PhotometricInterpretation field is missing; "
0656:                                + "assuming BlackIsZero");
0657:                        photometricInterpretation = BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_BLACK_IS_ZERO;
0658:                    }
0659:                } else {
0660:                    photometricInterpretation = f.getAsInt(0);
0661:                }
0662:
0663:                // SampleFormat
0664:                boolean replicateFirst = false;
0665:                int first = -1;
0666:
0667:                f = imageMetadata
0668:                        .getTIFFField(BaselineTIFFTagSet.TAG_SAMPLE_FORMAT);
0669:                sampleFormat = new int[samplesPerPixel];
0670:                replicateFirst = false;
0671:                if (f == null) {
0672:                    replicateFirst = true;
0673:                    first = BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED;
0674:                } else if (f.getCount() != samplesPerPixel) {
0675:                    replicateFirst = true;
0676:                    first = f.getAsInt(0);
0677:                }
0678:
0679:                for (int i = 0; i < samplesPerPixel; i++) {
0680:                    sampleFormat[i] = replicateFirst ? first : f.getAsInt(i);
0681:                    if (sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_UNSIGNED_INTEGER
0682:                            && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_SIGNED_INTEGER
0683:                            && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_FLOATING_POINT
0684:                            && sampleFormat[i] != BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED) {
0685:                        processWarningOccurred("Illegal value for SAMPLE_FORMAT, assuming SAMPLE_FORMAT_UNDEFINED");
0686:                        sampleFormat[i] = BaselineTIFFTagSet.SAMPLE_FORMAT_UNDEFINED;
0687:                    }
0688:                }
0689:
0690:                // BitsPerSample
0691:                f = imageMetadata
0692:                        .getTIFFField(BaselineTIFFTagSet.TAG_BITS_PER_SAMPLE);
0693:                this .bitsPerSample = new int[samplesPerPixel];
0694:                replicateFirst = false;
0695:                if (f == null) {
0696:                    replicateFirst = true;
0697:                    first = defaultBitDepth;
0698:                } else if (f.getCount() != samplesPerPixel) {
0699:                    replicateFirst = true;
0700:                    first = f.getAsInt(0);
0701:                }
0702:
0703:                for (int i = 0; i < samplesPerPixel; i++) {
0704:                    // Replicate initial value if not enough values provided
0705:                    bitsPerSample[i] = replicateFirst ? first : f.getAsInt(i);
0706:
0707:                    if (DEBUG) {
0708:                        System.out.println("bitsPerSample[" + i + "] = "
0709:                                + bitsPerSample[i]);
0710:                    }
0711:                }
0712:
0713:                // ExtraSamples
0714:                this .extraSamples = null;
0715:                f = imageMetadata
0716:                        .getTIFFField(BaselineTIFFTagSet.TAG_EXTRA_SAMPLES);
0717:                if (f != null) {
0718:                    extraSamples = f.getAsInts();
0719:                }
0720:
0721:                //         System.out.println("colorMap = " + colorMap);
0722:                //         if (colorMap != null) {
0723:                //             for (int i = 0; i < colorMap.length; i++) {
0724:                //              System.out.println("colorMap[" + i + "] = " + (int)(colorMap[i]));
0725:                //             }
0726:                //         }
0727:
0728:            }
0729:
0730:            public Iterator getImageTypes(int imageIndex) throws IIOException {
0731:                List l; // List of ImageTypeSpecifiers
0732:
0733:                Integer imageIndexInteger = new Integer(imageIndex);
0734:                if (imageTypeMap.containsKey(imageIndexInteger)) {
0735:                    // Return the cached ITS List.
0736:                    l = (List) imageTypeMap.get(imageIndexInteger);
0737:                } else {
0738:                    // Create a new ITS List.
0739:                    l = new ArrayList(1);
0740:
0741:                    // Create the ITS and cache if for later use so that this method
0742:                    // always returns an Iterator containing the same ITS objects.
0743:                    seekToImage(imageIndex);
0744:                    ImageTypeSpecifier itsRaw = TIFFDecompressor
0745:                            .getRawImageTypeSpecifier(
0746:                                    photometricInterpretation, compression,
0747:                                    samplesPerPixel, bitsPerSample,
0748:                                    sampleFormat, extraSamples, colorMap);
0749:
0750:                    // Check for an ICCProfile field.
0751:                    TIFFField iccProfileField = imageMetadata
0752:                            .getTIFFField(BaselineTIFFTagSet.TAG_ICC_PROFILE);
0753:
0754:                    // If an ICCProfile field is present change the ImageTypeSpecifier
0755:                    // to use it if the data layout is component type.
0756:                    if (iccProfileField != null
0757:                            && itsRaw.getColorModel() instanceof  ComponentColorModel) {
0758:                        // Create a ColorSpace from the profile.
0759:                        byte[] iccProfileValue = iccProfileField.getAsBytes();
0760:                        ICC_Profile iccProfile = ICC_Profile
0761:                                .getInstance(iccProfileValue);
0762:                        ICC_ColorSpace iccColorSpace = new ICC_ColorSpace(
0763:                                iccProfile);
0764:
0765:                        // Get the raw sample and color information.
0766:                        ColorModel cmRaw = itsRaw.getColorModel();
0767:                        ColorSpace csRaw = cmRaw.getColorSpace();
0768:                        SampleModel smRaw = itsRaw.getSampleModel();
0769:
0770:                        // Get the number of samples per pixel and the number
0771:                        // of color components.
0772:                        int numBands = smRaw.getNumBands();
0773:                        int numComponents = iccColorSpace.getNumComponents();
0774:
0775:                        // Replace the ColorModel with the ICC ColorModel if the
0776:                        // numbers of samples and color components are amenable.
0777:                        if (numBands == numComponents
0778:                                || numBands == numComponents + 1) {
0779:                            // Set alpha flags.
0780:                            boolean hasAlpha = numComponents != numBands;
0781:                            boolean isAlphaPre = hasAlpha
0782:                                    && cmRaw.isAlphaPremultiplied();
0783:
0784:                            // Create a ColorModel of the same class and with
0785:                            // the same transfer type.
0786:                            ColorModel iccColorModel = new ComponentColorModel(
0787:                                    iccColorSpace, cmRaw.getComponentSize(),
0788:                                    hasAlpha, isAlphaPre, cmRaw
0789:                                            .getTransparency(), cmRaw
0790:                                            .getTransferType());
0791:
0792:                            // Prepend the ICC profile-based ITS to the List. The
0793:                            // ColorModel and SampleModel are guaranteed to be
0794:                            // compatible as the old and new ColorModels are both
0795:                            // ComponentColorModels with the same transfer type
0796:                            // and the same number of components.
0797:                            l.add(new ImageTypeSpecifier(iccColorModel, smRaw));
0798:
0799:                            // Append the raw ITS to the List if and only if its
0800:                            // ColorSpace has the same type and number of components
0801:                            // as the ICC ColorSpace.
0802:                            if (csRaw.getType() == iccColorSpace.getType()
0803:                                    && csRaw.getNumComponents() == iccColorSpace
0804:                                            .getNumComponents()) {
0805:                                l.add(itsRaw);
0806:                            }
0807:                        } else { // ICCProfile not compatible with SampleModel.
0808:                            // Append the raw ITS to the List.
0809:                            l.add(itsRaw);
0810:                        }
0811:                    } else { // No ICCProfile field or raw ColorModel not component.
0812:                        // Append the raw ITS to the List.
0813:                        l.add(itsRaw);
0814:                    }
0815:
0816:                    // Cache the ITS List.
0817:                    imageTypeMap.put(imageIndexInteger, l);
0818:                }
0819:
0820:                return l.iterator();
0821:            }
0822:
0823:            public IIOMetadata getImageMetadata(int imageIndex)
0824:                    throws IIOException {
0825:                seekToImage(imageIndex);
0826:                TIFFImageMetadata im = new TIFFImageMetadata(imageMetadata
0827:                        .getRootIFD().getTagSetList());
0828:                Node root = imageMetadata
0829:                        .getAsTree(TIFFImageMetadata.nativeMetadataFormatName);
0830:                im
0831:                        .setFromTree(
0832:                                TIFFImageMetadata.nativeMetadataFormatName,
0833:                                root);
0834:                return im;
0835:            }
0836:
0837:            public IIOMetadata getStreamMetadata(int imageIndex)
0838:                    throws IIOException {
0839:                readHeader();
0840:                TIFFStreamMetadata sm = new TIFFStreamMetadata();
0841:                Node root = sm
0842:                        .getAsTree(TIFFStreamMetadata.nativeMetadataFormatName);
0843:                sm.setFromTree(TIFFStreamMetadata.nativeMetadataFormatName,
0844:                        root);
0845:                return sm;
0846:            }
0847:
0848:            public boolean isRandomAccessEasy(int imageIndex)
0849:                    throws IOException {
0850:                if (currIndex != -1) {
0851:                    seekToImage(currIndex);
0852:                    return getCompression() == BaselineTIFFTagSet.COMPRESSION_NONE;
0853:                } else {
0854:                    return false;
0855:                }
0856:            }
0857:
0858:            // Thumbnails
0859:
0860:            public boolean readSupportsThumbnails() {
0861:                return false;
0862:            }
0863:
0864:            public boolean hasThumbnails(int imageIndex) {
0865:                return false;
0866:            }
0867:
0868:            public int getNumThumbnails(int imageIndex) throws IOException {
0869:                return 0;
0870:            }
0871:
0872:            public ImageReadParam getDefaultReadParam() {
0873:                return new TIFFImageReadParam();
0874:            }
0875:
0876:            public boolean isImageTiled(int imageIndex) throws IOException {
0877:                seekToImage(imageIndex);
0878:
0879:                TIFFField f = imageMetadata
0880:                        .getTIFFField(BaselineTIFFTagSet.TAG_TILE_WIDTH);
0881:                return f != null;
0882:            }
0883:
0884:            public int getTileWidth(int imageIndex) throws IOException {
0885:                seekToImage(imageIndex);
0886:                return getTileOrStripWidth();
0887:            }
0888:
0889:            public int getTileHeight(int imageIndex) throws IOException {
0890:                seekToImage(imageIndex);
0891:                return getTileOrStripHeight();
0892:            }
0893:
0894:            public BufferedImage readTile(int imageIndex, int tileX, int tileY)
0895:                    throws IOException {
0896:
0897:                int w = getWidth(imageIndex);
0898:                int h = getHeight(imageIndex);
0899:                int tw = getTileWidth(imageIndex);
0900:                int th = getTileHeight(imageIndex);
0901:
0902:                int x = tw * tileX;
0903:                int y = th * tileY;
0904:
0905:                if (tileX < 0 || tileY < 0 || x >= w || y >= h) {
0906:                    throw new IllegalArgumentException(
0907:                            "Tile indices are out of bounds!");
0908:                }
0909:
0910:                if (x + tw > w) {
0911:                    tw = w - x;
0912:                }
0913:
0914:                if (y + th > h) {
0915:                    th = h - y;
0916:                }
0917:
0918:                ImageReadParam param = getDefaultReadParam();
0919:                Rectangle tileRect = new Rectangle(x, y, tw, th);
0920:                param.setSourceRegion(tileRect);
0921:
0922:                return read(imageIndex, param);
0923:            }
0924:
0925:            public boolean canReadRaster() {
0926:                // Enable this?
0927:                return false;
0928:            }
0929:
0930:            public Raster readRaster(int imageIndex, ImageReadParam param)
0931:                    throws IOException {
0932:                // Enable this?
0933:                throw new UnsupportedOperationException();
0934:            }
0935:
0936:            //     public BufferedImage readTileRaster(int imageIndex,
0937:            //                                         int tileX, int tileY)
0938:            //         throws IOException {
0939:            //     }
0940:
0941:            private int[] sourceBands;
0942:            private int[] destinationBands;
0943:
0944:            private TIFFDecompressor decompressor;
0945:
0946:            // floor(num/den)
0947:            private static int ifloor(int num, int den) {
0948:                if (num < 0) {
0949:                    num -= den - 1;
0950:                }
0951:                return num / den;
0952:            }
0953:
0954:            // ceil(num/den)
0955:            private static int iceil(int num, int den) {
0956:                if (num > 0) {
0957:                    num += den - 1;
0958:                }
0959:                return num / den;
0960:            }
0961:
0962:            private void prepareRead(int imageIndex, ImageReadParam param)
0963:                    throws IOException {
0964:                if (stream == null) {
0965:                    throw new IllegalStateException("Input not set!");
0966:                }
0967:
0968:                // A null ImageReadParam means we use the default
0969:                if (param == null) {
0970:                    param = getDefaultReadParam();
0971:                }
0972:
0973:                this .imageReadParam = param;
0974:
0975:                seekToImage(imageIndex);
0976:
0977:                this .tileOrStripWidth = getTileOrStripWidth();
0978:                this .tileOrStripHeight = getTileOrStripHeight();
0979:                this .planarConfiguration = getPlanarConfiguration();
0980:
0981:                this .sourceBands = param.getSourceBands();
0982:                if (sourceBands == null) {
0983:                    sourceBands = new int[numBands];
0984:                    for (int i = 0; i < numBands; i++) {
0985:                        sourceBands[i] = i;
0986:                    }
0987:                }
0988:
0989:                // Initialize the destination image
0990:                Iterator imageTypes = getImageTypes(imageIndex);
0991:                ImageTypeSpecifier theImageType = ImageUtil.getDestinationType(
0992:                        param, imageTypes);
0993:
0994:                int destNumBands = theImageType.getSampleModel().getNumBands();
0995:
0996:                this .destinationBands = param.getDestinationBands();
0997:                if (destinationBands == null) {
0998:                    destinationBands = new int[destNumBands];
0999:                    for (int i = 0; i < destNumBands; i++) {
1000:                        destinationBands[i] = i;
1001:                    }
1002:                }
1003:
1004:                if (sourceBands.length != destinationBands.length) {
1005:                    throw new IllegalArgumentException(
1006:                            "sourceBands.length != destinationBands.length");
1007:                }
1008:
1009:                for (int i = 0; i < sourceBands.length; i++) {
1010:                    int sb = sourceBands[i];
1011:                    if (sb < 0 || sb >= numBands) {
1012:                        throw new IllegalArgumentException(
1013:                                "Source band out of range!");
1014:                    }
1015:                    int db = destinationBands[i];
1016:                    if (db < 0 || db >= destNumBands) {
1017:                        throw new IllegalArgumentException(
1018:                                "Destination band out of range!");
1019:                    }
1020:                }
1021:            }
1022:
1023:            public RenderedImage readAsRenderedImage(int imageIndex,
1024:                    ImageReadParam param) throws IOException {
1025:                prepareRead(imageIndex, param);
1026:                return new TIFFRenderedImage(this , imageIndex, imageReadParam,
1027:                        width, height);
1028:            }
1029:
1030:            private void decodeTile(int ti, int tj, int band)
1031:                    throws IOException {
1032:                if (DEBUG) {
1033:                    System.out.println("decodeTile(" + ti + "," + tj + ","
1034:                            + band + ")");
1035:                }
1036:
1037:                // Compute the region covered by the strip or tile
1038:                Rectangle tileRect = new Rectangle(ti * tileOrStripWidth, tj
1039:                        * tileOrStripHeight, tileOrStripWidth,
1040:                        tileOrStripHeight);
1041:
1042:                // Clip against the image bounds if the image is not tiled. If it
1043:                // is tiled, the tile may legally extend beyond the image bounds.
1044:                if (!isImageTiled(currIndex)) {
1045:                    tileRect = tileRect.intersection(new Rectangle(0, 0, width,
1046:                            height));
1047:                }
1048:
1049:                // Return if the intersection is empty.
1050:                if (tileRect.width <= 0 || tileRect.height <= 0) {
1051:                    return;
1052:                }
1053:
1054:                int srcMinX = tileRect.x;
1055:                int srcMinY = tileRect.y;
1056:                int srcWidth = tileRect.width;
1057:                int srcHeight = tileRect.height;
1058:
1059:                // Determine dest region that can be derived from the
1060:                // source region
1061:
1062:                dstMinX = iceil(srcMinX - sourceXOffset, srcXSubsampling);
1063:                int dstMaxX = ifloor(srcMinX + srcWidth - 1 - sourceXOffset,
1064:                        srcXSubsampling);
1065:
1066:                dstMinY = iceil(srcMinY - sourceYOffset, srcYSubsampling);
1067:                int dstMaxY = ifloor(srcMinY + srcHeight - 1 - sourceYOffset,
1068:                        srcYSubsampling);
1069:
1070:                dstWidth = dstMaxX - dstMinX + 1;
1071:                dstHeight = dstMaxY - dstMinY + 1;
1072:
1073:                dstMinX += dstXOffset;
1074:                dstMinY += dstYOffset;
1075:
1076:                // Clip against image bounds
1077:
1078:                Rectangle dstRect = new Rectangle(dstMinX, dstMinY, dstWidth,
1079:                        dstHeight);
1080:                dstRect = dstRect
1081:                        .intersection(theImage.getRaster().getBounds());
1082:
1083:                dstMinX = dstRect.x;
1084:                dstMinY = dstRect.y;
1085:                dstWidth = dstRect.width;
1086:                dstHeight = dstRect.height;
1087:
1088:                if (dstWidth <= 0 || dstHeight <= 0) {
1089:                    return;
1090:                }
1091:
1092:                // Backwards map dest region to source to determine
1093:                // active source region
1094:
1095:                int activeSrcMinX = (dstMinX - dstXOffset) * srcXSubsampling
1096:                        + sourceXOffset;
1097:                int sxmax = (dstMinX + dstWidth - 1 - dstXOffset)
1098:                        * srcXSubsampling + sourceXOffset;
1099:                int activeSrcWidth = sxmax - activeSrcMinX + 1;
1100:
1101:                int activeSrcMinY = (dstMinY - dstYOffset) * srcYSubsampling
1102:                        + sourceYOffset;
1103:                int symax = (dstMinY + dstHeight - 1 - dstYOffset)
1104:                        * srcYSubsampling + sourceYOffset;
1105:                int activeSrcHeight = symax - activeSrcMinY + 1;
1106:
1107:                decompressor.setSrcMinX(srcMinX);
1108:                decompressor.setSrcMinY(srcMinY);
1109:                decompressor.setSrcWidth(srcWidth);
1110:                decompressor.setSrcHeight(srcHeight);
1111:
1112:                decompressor.setDstMinX(dstMinX);
1113:                decompressor.setDstMinY(dstMinY);
1114:                decompressor.setDstWidth(dstWidth);
1115:                decompressor.setDstHeight(dstHeight);
1116:
1117:                decompressor.setActiveSrcMinX(activeSrcMinX);
1118:                decompressor.setActiveSrcMinY(activeSrcMinY);
1119:                decompressor.setActiveSrcWidth(activeSrcWidth);
1120:                decompressor.setActiveSrcHeight(activeSrcHeight);
1121:
1122:                int tileIndex = tj * tilesAcross + ti;
1123:
1124:                if (planarConfiguration == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
1125:                    tileIndex += band * tilesAcross * tilesDown;
1126:                }
1127:
1128:                long offset = getTileOrStripOffset(tileIndex);
1129:                long byteCount = getTileOrStripByteCount(tileIndex);
1130:
1131:                //
1132:                // Attempt to handle truncated streams, i.e., where reading the
1133:                // compressed strip or tile would result in an EOFException. The
1134:                // number of bytes to read is clamped to the number available
1135:                // from the stream starting at the indicated position in the hope
1136:                // that the decompressor will handle it.
1137:                //
1138:                long streamLength = stream.length();
1139:                if (streamLength > 0 && offset + byteCount > streamLength) {
1140:                    processWarningOccurred("Attempting to process truncated stream.");
1141:                    if (Math.max(byteCount = streamLength - offset, 0) == 0) {
1142:                        processWarningOccurred("No bytes in strip/tile: skipping.");
1143:                        return;
1144:                    }
1145:                }
1146:
1147:                decompressor.setStream(stream);
1148:                decompressor.setOffset(offset);
1149:                decompressor.setByteCount((int) byteCount);
1150:
1151:                decompressor.beginDecoding();
1152:
1153:                stream.mark();
1154:                decompressor.decode();
1155:                stream.reset();
1156:            }
1157:
1158:            private void reportProgress() {
1159:                // Report image progress/update to listeners after each tile
1160:                pixelsRead += dstWidth * dstHeight;
1161:                processImageProgress(100.0f * pixelsRead / pixelsToRead);
1162:                processImageUpdate(theImage, dstMinX, dstMinY, dstWidth,
1163:                        dstHeight, 1, 1, destinationBands);
1164:            }
1165:
1166:            public BufferedImage read(int imageIndex, ImageReadParam param)
1167:                    throws IOException {
1168:                prepareRead(imageIndex, param);
1169:                this .theImage = getDestination(param,
1170:                        getImageTypes(imageIndex), width, height);
1171:
1172:                srcXSubsampling = imageReadParam.getSourceXSubsampling();
1173:                srcYSubsampling = imageReadParam.getSourceYSubsampling();
1174:
1175:                Point p = imageReadParam.getDestinationOffset();
1176:                dstXOffset = p.x;
1177:                dstYOffset = p.y;
1178:
1179:                // This could probably be made more efficient...
1180:                Rectangle srcRegion = new Rectangle(0, 0, 0, 0);
1181:                Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1182:
1183:                computeRegions(imageReadParam, width, height, theImage,
1184:                        srcRegion, destRegion);
1185:
1186:                // Initial source pixel, taking source region and source
1187:                // subsamplimg offsets into account
1188:                sourceXOffset = srcRegion.x;
1189:                sourceYOffset = srcRegion.y;
1190:
1191:                pixelsToRead = destRegion.width * destRegion.height;
1192:                pixelsRead = 0;
1193:
1194:                processImageStarted(imageIndex);
1195:                processImageProgress(0.0f);
1196:
1197:                tilesAcross = (width + tileOrStripWidth - 1) / tileOrStripWidth;
1198:                tilesDown = (height + tileOrStripHeight - 1)
1199:                        / tileOrStripHeight;
1200:
1201:                int compression = getCompression();
1202:
1203:                // Attempt to get decompressor and color converted from the read param
1204:
1205:                TIFFColorConverter colorConverter = null;
1206:                if (imageReadParam instanceof  TIFFImageReadParam) {
1207:                    TIFFImageReadParam tparam = (TIFFImageReadParam) imageReadParam;
1208:                    this .decompressor = tparam.getTIFFDecompressor();
1209:                    colorConverter = tparam.getColorConverter();
1210:                }
1211:
1212:                // If we didn't find one, use a standard decompressor
1213:                if (this .decompressor == null) {
1214:                    if (compression == BaselineTIFFTagSet.COMPRESSION_NONE) {
1215:                        // Get the fillOrder field.
1216:                        TIFFField fillOrderField = imageMetadata
1217:                                .getTIFFField(BaselineTIFFTagSet.TAG_FILL_ORDER);
1218:
1219:                        // Set the decompressor based on the fill order.
1220:                        if (fillOrderField != null
1221:                                && fillOrderField.getAsInt(0) == 2) {
1222:                            this .decompressor = new TIFFLSBDecompressor();
1223:                        } else {
1224:                            this .decompressor = new TIFFNullDecompressor();
1225:                        }
1226:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_6) {
1227:
1228:                        // Try to create the codecLib decompressor.
1229:                        if (PackageUtil.isCodecLibAvailable()) {
1230:                            try {
1231:                                this .decompressor = new TIFFCodecLibFaxDecompressor(
1232:                                        compression);
1233:                                if (DEBUG) {
1234:                                    System.out
1235:                                            .println("Using codecLib T.6 decompressor");
1236:                                }
1237:                            } catch (RuntimeException re) {
1238:                                if (DEBUG) {
1239:                                    System.out.println(re);
1240:                                }
1241:                            }
1242:                        }
1243:
1244:                        // Fall back to the Java decompressor.
1245:                        if (this .decompressor == null) {
1246:                            if (DEBUG) {
1247:                                System.out
1248:                                        .println("Using Java T.6 decompressor");
1249:                            }
1250:                            this .decompressor = new TIFFFaxDecompressor();
1251:                        }
1252:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_T_4) {
1253:
1254:                        if (PackageUtil.isCodecLibAvailable()) {
1255:                            // Try to create the codecLib decompressor.
1256:                            try {
1257:                                this .decompressor = new TIFFCodecLibFaxDecompressor(
1258:                                        compression);
1259:                                if (DEBUG) {
1260:                                    System.out
1261:                                            .println("Using codecLib T.4 decompressor");
1262:                                }
1263:                            } catch (RuntimeException re) {
1264:                                if (DEBUG) {
1265:                                    System.out.println(re);
1266:                                }
1267:                            }
1268:                        }
1269:
1270:                        // Fall back to the Java decompressor.
1271:                        if (this .decompressor == null) {
1272:                            if (DEBUG) {
1273:                                System.out
1274:                                        .println("Using Java T.4 decompressor");
1275:                            }
1276:                            this .decompressor = new TIFFFaxDecompressor();
1277:                        }
1278:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_CCITT_RLE) {
1279:                        this .decompressor = new TIFFFaxDecompressor();
1280:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_PACKBITS) {
1281:                        if (DEBUG) {
1282:                            System.out
1283:                                    .println("Using TIFFPackBitsDecompressor");
1284:                        }
1285:                        this .decompressor = new TIFFPackBitsDecompressor();
1286:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_LZW) {
1287:                        if (DEBUG) {
1288:                            System.out.println("Using TIFFLZWDecompressor");
1289:                        }
1290:                        TIFFField predictorField = imageMetadata
1291:                                .getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR);
1292:                        int predictor = ((predictorField == null) ? BaselineTIFFTagSet.PREDICTOR_NONE
1293:                                : predictorField.getAsInt(0));
1294:                        this .decompressor = new TIFFLZWDecompressor(predictor);
1295:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_JPEG) {
1296:                        this .decompressor = new TIFFJPEGDecompressor();
1297:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_ZLIB
1298:                            || compression == BaselineTIFFTagSet.COMPRESSION_DEFLATE) {
1299:                        TIFFField predictorField = imageMetadata
1300:                                .getTIFFField(BaselineTIFFTagSet.TAG_PREDICTOR);
1301:                        int predictor = ((predictorField == null) ? BaselineTIFFTagSet.PREDICTOR_NONE
1302:                                : predictorField.getAsInt(0));
1303:                        this .decompressor = new TIFFDeflateDecompressor(
1304:                                predictor);
1305:                    } else if (compression == BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
1306:                        TIFFField JPEGProcField = imageMetadata
1307:                                .getTIFFField(BaselineTIFFTagSet.TAG_JPEG_PROC);
1308:                        if (JPEGProcField == null) {
1309:                            processWarningOccurred("JPEGProc field missing; assuming baseline sequential JPEG process.");
1310:                        } else if (JPEGProcField.getAsInt(0) != BaselineTIFFTagSet.JPEG_PROC_BASELINE) {
1311:                            throw new IIOException(
1312:                                    "Old-style JPEG supported for baseline sequential JPEG process only!");
1313:                        }
1314:                        this .decompressor = new TIFFOldJPEGDecompressor();
1315:                        //throw new IIOException("Old-style JPEG not supported!");
1316:                    } else {
1317:                        throw new IIOException(
1318:                                "Unsupported compression type (tag number = "
1319:                                        + compression + ")!");
1320:                    }
1321:
1322:                    if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR
1323:                            && compression != BaselineTIFFTagSet.COMPRESSION_JPEG
1324:                            && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
1325:                        boolean convertYCbCrToRGB = theImage.getColorModel()
1326:                                .getColorSpace().getType() == ColorSpace.TYPE_RGB;
1327:                        TIFFDecompressor wrappedDecompressor = this .decompressor instanceof  TIFFNullDecompressor ? null
1328:                                : this .decompressor;
1329:                        this .decompressor = new TIFFYCbCrDecompressor(
1330:                                wrappedDecompressor, convertYCbCrToRGB);
1331:                    }
1332:                }
1333:
1334:                if (DEBUG) {
1335:                    System.out.println("\nDecompressor class = "
1336:                            + decompressor.getClass().getName() + "\n");
1337:                }
1338:
1339:                if (colorConverter == null) {
1340:                    if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_CIELAB
1341:                            && theImage.getColorModel().getColorSpace()
1342:                                    .getType() == ColorSpace.TYPE_RGB) {
1343:                        colorConverter = new TIFFCIELabColorConverter();
1344:                    } else if (photometricInterpretation == BaselineTIFFTagSet.PHOTOMETRIC_INTERPRETATION_Y_CB_CR
1345:                            && !(this .decompressor instanceof  TIFFYCbCrDecompressor)
1346:                            && compression != BaselineTIFFTagSet.COMPRESSION_JPEG
1347:                            && compression != BaselineTIFFTagSet.COMPRESSION_OLD_JPEG) {
1348:                        colorConverter = new TIFFYCbCrColorConverter(
1349:                                imageMetadata);
1350:                    }
1351:                }
1352:
1353:                decompressor.setReader(this );
1354:                decompressor.setMetadata(imageMetadata);
1355:                decompressor.setImage(theImage);
1356:
1357:                decompressor
1358:                        .setPhotometricInterpretation(photometricInterpretation);
1359:                decompressor.setCompression(compression);
1360:                decompressor.setSamplesPerPixel(samplesPerPixel);
1361:                decompressor.setBitsPerSample(bitsPerSample);
1362:                decompressor.setSampleFormat(sampleFormat);
1363:                decompressor.setExtraSamples(extraSamples);
1364:                decompressor.setColorMap(colorMap);
1365:
1366:                decompressor.setColorConverter(colorConverter);
1367:
1368:                decompressor.setSourceXOffset(sourceXOffset);
1369:                decompressor.setSourceYOffset(sourceYOffset);
1370:                decompressor.setSubsampleX(srcXSubsampling);
1371:                decompressor.setSubsampleY(srcYSubsampling);
1372:
1373:                decompressor.setDstXOffset(dstXOffset);
1374:                decompressor.setDstYOffset(dstYOffset);
1375:
1376:                decompressor.setSourceBands(sourceBands);
1377:                decompressor.setDestinationBands(destinationBands);
1378:
1379:                // Compute bounds on the tile indices for this source region.
1380:                int minTileX = TIFFImageWriter.XToTileX(srcRegion.x, 0,
1381:                        tileOrStripWidth);
1382:                int minTileY = TIFFImageWriter.YToTileY(srcRegion.y, 0,
1383:                        tileOrStripHeight);
1384:                int maxTileX = TIFFImageWriter.XToTileX(srcRegion.x
1385:                        + srcRegion.width - 1, 0, tileOrStripWidth);
1386:                int maxTileY = TIFFImageWriter.YToTileY(srcRegion.y
1387:                        + srcRegion.height - 1, 0, tileOrStripHeight);
1388:
1389:                boolean isAbortRequested = false;
1390:                if (planarConfiguration == BaselineTIFFTagSet.PLANAR_CONFIGURATION_PLANAR) {
1391:
1392:                    decompressor.setPlanar(true);
1393:
1394:                    int[] sb = new int[1];
1395:                    int[] db = new int[1];
1396:                    for (int tj = minTileY; tj <= maxTileY; tj++) {
1397:                        for (int ti = minTileX; ti <= maxTileX; ti++) {
1398:                            for (int band = 0; band < numBands; band++) {
1399:                                sb[0] = sourceBands[band];
1400:                                decompressor.setSourceBands(sb);
1401:                                db[0] = destinationBands[band];
1402:                                decompressor.setDestinationBands(db);
1403:                                //XXX decompressor.beginDecoding();
1404:
1405:                                // The method abortRequested() is synchronized
1406:                                // so check it only once per loop just before
1407:                                // doing any actual decoding.
1408:                                if (abortRequested()) {
1409:                                    isAbortRequested = true;
1410:                                    break;
1411:                                }
1412:
1413:                                decodeTile(ti, tj, band);
1414:                            }
1415:
1416:                            if (isAbortRequested)
1417:                                break;
1418:
1419:                            reportProgress();
1420:                        }
1421:
1422:                        if (isAbortRequested)
1423:                            break;
1424:                    }
1425:                } else {
1426:                    //XXX decompressor.beginDecoding();
1427:
1428:                    for (int tj = minTileY; tj <= maxTileY; tj++) {
1429:                        for (int ti = minTileX; ti <= maxTileX; ti++) {
1430:                            // The method abortRequested() is synchronized
1431:                            // so check it only once per loop just before
1432:                            // doing any actual decoding.
1433:                            if (abortRequested()) {
1434:                                isAbortRequested = true;
1435:                                break;
1436:                            }
1437:
1438:                            decodeTile(ti, tj, -1);
1439:
1440:                            reportProgress();
1441:                        }
1442:
1443:                        if (isAbortRequested)
1444:                            break;
1445:                    }
1446:                }
1447:
1448:                if (isAbortRequested) {
1449:                    processReadAborted();
1450:                } else {
1451:                    processImageComplete();
1452:                }
1453:
1454:                return theImage;
1455:            }
1456:
1457:            public void reset() {
1458:                super .reset();
1459:                resetLocal();
1460:            }
1461:
1462:            protected void resetLocal() {
1463:                stream = null;
1464:                gotHeader = false;
1465:                imageReadParam = getDefaultReadParam();
1466:                streamMetadata = null;
1467:                currIndex = -1;
1468:                imageMetadata = null;
1469:                imageStartPosition = new ArrayList();
1470:                numImages = -1;
1471:                imageTypeMap = new HashMap();
1472:                width = -1;
1473:                height = -1;
1474:                numBands = -1;
1475:                tileOrStripWidth = -1;
1476:                tileOrStripHeight = -1;
1477:                planarConfiguration = BaselineTIFFTagSet.PLANAR_CONFIGURATION_CHUNKY;
1478:                rowsDone = 0;
1479:            }
1480:
1481:            /**
1482:             * Package scope method to allow decompressors, for example, to
1483:             * emit warning messages.
1484:             */
1485:            void forwardWarningMessage(String warning) {
1486:                processWarningOccurred(warning);
1487:            }
1488:
1489:            protected static BufferedImage getDestination(ImageReadParam param,
1490:                    Iterator imageTypes, int width, int height)
1491:                    throws IIOException {
1492:                if (imageTypes == null || !imageTypes.hasNext()) {
1493:                    throw new IllegalArgumentException(
1494:                            "imageTypes null or empty!");
1495:                }
1496:
1497:                BufferedImage dest = null;
1498:                ImageTypeSpecifier imageType = null;
1499:
1500:                // If param is non-null, use it
1501:                if (param != null) {
1502:                    // Try to get the image itself
1503:                    dest = param.getDestination();
1504:                    if (dest != null) {
1505:                        return dest;
1506:                    }
1507:
1508:                    // No image, get the image type
1509:                    imageType = param.getDestinationType();
1510:                }
1511:
1512:                // No info from param, use fallback image type
1513:                if (imageType == null) {
1514:                    Object o = imageTypes.next();
1515:                    if (!(o instanceof  ImageTypeSpecifier)) {
1516:                        throw new IllegalArgumentException(
1517:                                "Non-ImageTypeSpecifier retrieved from imageTypes!");
1518:                    }
1519:                    imageType = (ImageTypeSpecifier) o;
1520:                } else {
1521:                    boolean foundIt = false;
1522:                    while (imageTypes.hasNext()) {
1523:                        ImageTypeSpecifier type = (ImageTypeSpecifier) imageTypes
1524:                                .next();
1525:                        if (type.equals(imageType)) {
1526:                            foundIt = true;
1527:                            break;
1528:                        }
1529:                    }
1530:
1531:                    if (!foundIt) {
1532:                        throw new IIOException(
1533:                                "Destination type from ImageReadParam does not match!");
1534:                    }
1535:                }
1536:
1537:                Rectangle srcRegion = new Rectangle(0, 0, 0, 0);
1538:                Rectangle destRegion = new Rectangle(0, 0, 0, 0);
1539:                computeRegions(param, width, height, null, srcRegion,
1540:                        destRegion);
1541:
1542:                int destWidth = destRegion.x + destRegion.width;
1543:                int destHeight = destRegion.y + destRegion.height;
1544:                // Create a new image based on the type specifier
1545:
1546:                if ((long) destWidth * destHeight > Integer.MAX_VALUE) {
1547:                    throw new IllegalArgumentException(
1548:                            "width*height > Integer.MAX_VALUE!");
1549:                }
1550:
1551:                return imageType.createBufferedImage(destWidth, destHeight);
1552:            }
1553:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.