diff --git a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/util/IIOUtil.java b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/util/IIOUtil.java index 072a65c1..4084a442 100644 --- a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/util/IIOUtil.java +++ b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/util/IIOUtil.java @@ -223,7 +223,12 @@ public final class IIOUtil { public static void subsampleRow(byte[] srcRow, int srcPos, int srcWidth, byte[] destRow, int destPos, int samplesPerPixel, int bitsPerSample, int samplePeriod) { - Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op... + // Period == 1 is a no-op... + if (samplePeriod == 1) { + return; + } + + Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 8 && (bitsPerSample == 1 || bitsPerSample % 2 == 0), "bitsPerSample must be > 0 and <= 8 and a power of 2"); Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0"); @@ -261,7 +266,12 @@ public final class IIOUtil { public static void subsampleRow(short[] srcRow, int srcPos, int srcWidth, short[] destRow, int destPos, int samplesPerPixel, int bitsPerSample, int samplePeriod) { - Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op... + // Period == 1 is a no-op... + if (samplePeriod == 1) { + return; + } + + Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 16 && (bitsPerSample == 1 || bitsPerSample % 2 == 0), "bitsPerSample must be > 0 and <= 16 and a power of 2"); Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0"); @@ -278,7 +288,12 @@ public final class IIOUtil { public static void subsampleRow(int[] srcRow, int srcPos, int srcWidth, int[] destRow, int destPos, int samplesPerPixel, int bitsPerSample, int samplePeriod) { - Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); // Period == 1 could be a no-op... + // Period == 1 is a no-op... + if (samplePeriod == 1) { + return; + } + + Validate.isTrue(samplePeriod > 1, "samplePeriod must be > 1"); Validate.isTrue(bitsPerSample > 0 && bitsPerSample <= 32 && (bitsPerSample == 1 || bitsPerSample % 2 == 0), "bitsPerSample must be > 0 and <= 32 and a power of 2"); Validate.isTrue(samplesPerPixel > 0, "samplesPerPixel must be > 0"); diff --git a/imageio/imageio-pnm/src/main/java/com/twelvemonkeys/imageio/plugins/pnm/PNMImageReader.java b/imageio/imageio-pnm/src/main/java/com/twelvemonkeys/imageio/plugins/pnm/PNMImageReader.java index f878ac1c..7e036116 100755 --- a/imageio/imageio-pnm/src/main/java/com/twelvemonkeys/imageio/plugins/pnm/PNMImageReader.java +++ b/imageio/imageio-pnm/src/main/java/com/twelvemonkeys/imageio/plugins/pnm/PNMImageReader.java @@ -353,10 +353,7 @@ public final class PNMImageReader extends ImageReaderBase { input.readFully(rowDataByte); // Subsample (horizontal) - if (xSub > 1) { - subsampleRow(rowDataByte, srcRegion.x, srcRegion.width, rowDataByte, 0, samplesPerPixel, bitsPerSample, xSub); - } - + subsampleRow(rowDataByte, srcRegion.x, srcRegion.width, rowDataByte, 0, samplesPerPixel, bitsPerSample, xSub); normalize(rowDataByte, 0, rowDataByte.length / xSub); int destY = (y - srcRegion.y) / ySub; @@ -382,10 +379,7 @@ public final class PNMImageReader extends ImageReaderBase { readFully(input, rowDataUShort); // Subsample (horizontal) - if (xSub > 1) { - subsampleRow(rowDataUShort, srcRegion.x, srcRegion.width, rowDataUShort, 0, samplesPerPixel, 16, xSub); - } - + subsampleRow(rowDataUShort, srcRegion.x, srcRegion.width, rowDataUShort, 0, samplesPerPixel, 16, xSub); normalize(rowDataUShort); int destY = (y - srcRegion.y) / ySub; diff --git a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java index b4b879a2..a0cef77a 100644 --- a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java +++ b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReader.java @@ -48,10 +48,10 @@ import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader; import com.twelvemonkeys.imageio.metadata.xmp.XMPReader; import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream; import com.twelvemonkeys.imageio.stream.SubImageInputStream; -import com.twelvemonkeys.imageio.util.IIOUtil; import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers; import com.twelvemonkeys.imageio.util.ProgressListenerBase; import com.twelvemonkeys.io.FastByteArrayOutputStream; +import com.twelvemonkeys.io.FileUtil; import com.twelvemonkeys.io.LittleEndianDataInputStream; import com.twelvemonkeys.io.enc.DecoderStream; import com.twelvemonkeys.io.enc.PackBitsDecoder; @@ -696,7 +696,7 @@ public final class TIFFImageReader extends ImageReaderBase { } private int getPhotometricInterpretationWithFallback() throws IIOException { - // PhotometricInterpretation is a required TAG, but as it can be guessed this does a fallback that is equal to JAI ImageIO. + // PhotometricInterpretation is a required tag, but as it can be guessed this does a fallback that is similar to JAI ImageIO. int interpretation = getValueAsIntWithDefault(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, "PhotometricInterpretation", -1); if (interpretation == -1) { int compression = getValueAsIntWithDefault(TIFF.TAG_COMPRESSION, TIFFBaseline.COMPRESSION_NONE); @@ -713,7 +713,13 @@ public final class TIFFImageReader extends ImageReaderBase { interpretation = TIFFBaseline.PHOTOMETRIC_PALETTE; } else if ((samplesPerPixel - extraSamples) == 3) { - interpretation = TIFFBaseline.PHOTOMETRIC_RGB; + if (compression == TIFFExtension.COMPRESSION_JPEG + || compression == TIFFExtension.COMPRESSION_OLD_JPEG) { + interpretation = TIFFExtension.PHOTOMETRIC_YCBCR; + } + else { + interpretation = TIFFBaseline.PHOTOMETRIC_RGB; + } } else if ((samplesPerPixel - extraSamples) == 4) { interpretation = TIFFExtension.PHOTOMETRIC_SEPARATED; @@ -959,10 +965,9 @@ public final class TIFFImageReader extends ImageReaderBase { int tilesAcross = (width + stripTileWidth - 1) / stripTileWidth; int tilesDown = (height + stripTileHeight - 1) / stripTileHeight; - // TODO: Get number of extra samples not part of the rawType spec... - // TODO: If extrasamples, we might need to create a raster with more samples... + // Raw type may contain extra samples WritableRaster rowRaster = rawType.createBufferedImage(stripTileWidth, 1).getRaster(); -// WritableRaster rowRaster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, stripTileWidth, 1, 2, null).createWritableChild(0, 0, stripTileWidth, 1, 0, 0, new int[]{0}); + Rectangle clip = new Rectangle(srcRegion); int srcRow = 0; Boolean needsCSConversion = null; @@ -1121,6 +1126,13 @@ public final class TIFFImageReader extends ImageReaderBase { // TODO: Cache the JPEG reader for later use? Remember to reset to avoid resource leaks ImageReader jpegReader = createJPEGDelegate(); + // TODO: Use proper inner class + add case for old JPEG + jpegReader.addIIOReadWarningListener(new IIOReadWarningListener() { + @Override + public void warningOccurred(final ImageReader source, final String warning) { + processWarningOccurred(warning); + } + }); JPEGImageReadParam jpegParam = (JPEGImageReadParam) jpegReader.getDefaultReadParam(); // JPEG_TABLES should be a full JPEG 'abbreviated table specification', containing: @@ -1135,7 +1147,8 @@ public final class TIFFImageReader extends ImageReaderBase { // This initializes the tables and other internal settings for the reader, // and is actually a feature of JPEG, see abbreviated streams: // http://docs.oracle.com/javase/6/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#abbrev - jpegReader.getStreamMetadata(); + IIOMetadata streamMetadata = jpegReader.getStreamMetadata(); + new XMLSerializer(System.out, "UTF8").serialize(streamMetadata.getAsTree(streamMetadata.getNativeMetadataFormatName()), false); } else if (tilesDown * tilesAcross > 1) { processWarningOccurred("Missing JPEGTables for tiled/striped TIFF with compression: 7 (JPEG)"); @@ -1810,8 +1823,6 @@ public final class TIFFImageReader extends ImageReaderBase { out.writeByte(0); // Spectral selection end out.writeByte(0); // Approx high & low -// System.err.println(TIFFReader.HexDump.dump(stream.toByteArray())); -// return stream.createInputStream(); } @@ -1872,10 +1883,8 @@ public final class TIFFImageReader extends ImageReaderBase { } // Subsample horizontal - if (xSub != 1) { - IIOUtil.subsampleRow(rowDataByte, srcRegion.x * numBands, colsInTile, - rowDataByte, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); - } + subsampleRow(rowDataByte, srcRegion.x * numBands, colsInTile, + rowDataByte, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel); } @@ -1914,10 +1923,8 @@ public final class TIFFImageReader extends ImageReaderBase { normalizeColor(interpretation, rowDataShort); // Subsample horizontal - if (xSub != 1) { - subsampleRow(rowDataShort, srcRegion.x * numBands, colsInTile, - rowDataShort, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); - } + subsampleRow(rowDataShort, srcRegion.x * numBands, colsInTile, + rowDataShort, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel); // TODO: Possible speedup ~30%!: @@ -1950,10 +1957,8 @@ public final class TIFFImageReader extends ImageReaderBase { normalizeColor(interpretation, rowDataInt); // Subsample horizontal - if (xSub != 1) { - subsampleRow(rowDataInt, srcRegion.x * numBands, colsInTile, - rowDataInt, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); - } + subsampleRow(rowDataInt, srcRegion.x * numBands, colsInTile, + rowDataInt, srcRegion.x * numBands / xSub, numBands, bitsPerSample, xSub); destChannel.setDataElements(startCol / xSub, (row - srcRegion.y) / ySub, srcChannel); } @@ -2596,12 +2601,19 @@ public final class TIFFImageReader extends ImageReaderBase { Iterator readers = ImageIO.getImageReaders(input); if (!readers.hasNext()) { - System.err.println("No reader for: " + file); - continue; + String suffix = FileUtil.getExtension(file.getName()); + readers = ImageIO.getImageReadersBySuffix(suffix); + + if (!readers.hasNext()) { + System.err.println("No reader for: " + file); + continue; + } + + System.err.println("Could not determine file format, falling back to file extension: ." + suffix); } ImageReader reader = readers.next(); - System.err.printf("Reading %s format (%s)%n", reader.getFormatName(), reader); + System.out.printf("Reading %s format (%s)%n", reader.getFormatName(), reader); reader.addIIOReadWarningListener(new IIOReadWarningListener() { public void warningOccurred(ImageReader source, String warning) { diff --git a/imageio/imageio-xwd/src/main/java/com/twelvemonkeys/imageio/plugins/xwd/XWDImageReader.java b/imageio/imageio-xwd/src/main/java/com/twelvemonkeys/imageio/plugins/xwd/XWDImageReader.java index 4826eb0e..ebc62f01 100644 --- a/imageio/imageio-xwd/src/main/java/com/twelvemonkeys/imageio/plugins/xwd/XWDImageReader.java +++ b/imageio/imageio-xwd/src/main/java/com/twelvemonkeys/imageio/plugins/xwd/XWDImageReader.java @@ -171,11 +171,9 @@ final class XWDImageReader extends ImageReaderBase { } } - if (xSub != 1) { - // Horizontal subsampling - int samplesPerPixel = header.numComponents(); - subsampleRow(row, srcRegion.x * samplesPerPixel, srcRegion.width, row, srcRegion.x * samplesPerPixel, samplesPerPixel, header.bitsPerRGB, xSub); - } + // Horizontal subsampling + int samplesPerPixel = header.numComponents(); + subsampleRow(row, srcRegion.x * samplesPerPixel, srcRegion.width, row, srcRegion.x * samplesPerPixel, samplesPerPixel, header.bitsPerRGB, xSub); raster.setDataElements(0, (y - srcRegion.y) / ySub, rowRaster);