diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java index fe51a31d..0c6f5403 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java @@ -193,6 +193,8 @@ final class EXIFEntry extends AbstractEntry { return "Flash"; case EXIF.TAG_FOCAL_LENGTH: return "FocalLength"; + case EXIF.TAG_SENSING_METHOD: + return "SensingMethod"; case EXIF.TAG_FILE_SOURCE: return "FileSource"; case EXIF.TAG_SCENE_TYPE: @@ -219,6 +221,8 @@ final class EXIFEntry extends AbstractEntry { return "Saturation"; case EXIF.TAG_SHARPNESS: return "Sharpness"; + case EXIF.TAG_IMAGE_UNIQUE_ID: + return "ImageUniqueID"; case EXIF.TAG_FLASHPIX_VERSION: return "FlashpixVersion"; 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 c77fe49d..c6dd6e90 100755 --- 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 @@ -115,7 +115,6 @@ import java.util.zip.InflaterInputStream; public class TIFFImageReader extends ImageReaderBase { // TODOs ImageIO basic functionality: // TODO: Thumbnail support - // TODO: TIFFImageWriter + Spi // TODOs Full BaseLine support: // TODO: Support ExtraSamples (an array, if multiple extra samples!) @@ -129,10 +128,7 @@ public class TIFFImageReader extends ImageReaderBase { // http://download.java.net/media/jai-imageio/javadoc/1.1/com/sun/media/imageio/plugins/tiff/package-summary.html#ImageMetadata // TODOs Extension support - // TODO: Support PlanarConfiguration 2, look at PCXImageReader // TODO: Auto-rotate based on Orientation - // TODO: Support ICCProfile (fully) - // TODO: Support Compression 3 & 4 (CCITT T.4 & T.6) // TODO: Support Compression 34712 (JPEG2000)? Depends on JPEG2000 ImageReader // TODO: Support Compression 34661 (JBIG)? Depends on JBIG ImageReader @@ -143,6 +139,9 @@ public class TIFFImageReader extends ImageReaderBase { // Source region // Subsampling // IIOMetadata (stay close to Sun's TIFF metadata) + // Support ICCProfile + // Support PlanarConfiguration 2 + // Support Compression 3 & 4 (CCITT T.4 & T.6) final static boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.imageio.plugins.tiff.debug")); @@ -317,7 +316,23 @@ public class TIFFImageReader extends ImageReaderBase { int bitsPerSample = getBitsPerSample(); int dataType = getDataType(sampleFormat, bitsPerSample); - // TODO: Validate CS using ColorSpaces.validateProfile + int opaqueSamplesPerPixel = getOpaqueSamplesPerPixel(interpretation); + + // Spec says ExtraSamples are mandatory of extra samples, however known encoders + // (ie. SeaShore) writes ARGB TIFFs without ExtraSamples. + long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", false); + if (extraSamples == null && samplesPerPixel > opaqueSamplesPerPixel) { + // TODO: Log warning! + // First extra is alpha, rest is "unspecified" + extraSamples = new long[samplesPerPixel - opaqueSamplesPerPixel]; + extraSamples[0] = TIFFBaseline.EXTRASAMPLE_UNASSOCIATED_ALPHA; + } + + // Determine alpha + boolean hasAlpha = extraSamples != null; + boolean isAlphaPremultiplied = hasAlpha && extraSamples[0] == TIFFBaseline.EXTRASAMPLE_ASSOCIATED_ALPHA; + int significantSamples = opaqueSamplesPerPixel + (hasAlpha ? 1 : 0); + // Read embedded cs ICC_Profile profile = getICCProfile(); ColorSpace cs; @@ -327,11 +342,10 @@ public class TIFFImageReader extends ImageReaderBase { case TIFFBaseline.PHOTOMETRIC_WHITE_IS_ZERO: // WhiteIsZero // NOTE: We handle this by inverting the values when reading, as Java has no ColorModel that easily supports this. - // TODO: Consider returning null? case TIFFBaseline.PHOTOMETRIC_BLACK_IS_ZERO: // BlackIsZero // Gray scale or B/W - switch (samplesPerPixel) { + switch (significantSamples) { case 1: // TIFF 6.0 Spec says: 1, 4 or 8 for baseline (1 for bi-level, 4/8 for gray) // ImageTypeSpecifier supports 1, 2, 4, 8 or 16 bits per sample, we'll support 32 bits as well. @@ -347,6 +361,7 @@ public class TIFFImageReader extends ImageReaderBase { return ImageTypeSpecifiers.createGrayscale(bitsPerSample, dataType); } else if (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 || bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) { + // TODO: Should use packed format for 1/2/4 return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0}, dataType, false, false); } @@ -364,28 +379,26 @@ public class TIFFImageReader extends ImageReaderBase { cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : ColorSpaces.createColorSpace(profile); - // ExtraSamples 0=unspecified, 1=associated (pre-multiplied), 2=unassociated (TODO: Support unspecified, not alpha) - long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", true); - if (cs == ColorSpace.getInstance(ColorSpace.CS_GRAY) && (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32)) { switch (planarConfiguration) { case TIFFBaseline.PLANARCONFIG_CHUNKY: - return ImageTypeSpecifiers.createGrayscale(bitsPerSample, dataType, extraSamples[0] == 1); + return ImageTypeSpecifiers.createGrayscale(bitsPerSample, dataType, isAlphaPremultiplied); case TIFFExtension.PLANARCONFIG_PLANAR: - return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, dataType, true, isAlphaPremultiplied); } } - else if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) { + else if (/*bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 ||*/ bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) { + // TODO: Should use packed format for 1/2/4 chunky. + // TODO: For 1/2/4 bit planar, we might need to fix while reading... Look at IFFImageReader? switch (planarConfiguration) { case TIFFBaseline.PLANARCONFIG_CHUNKY: - return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1}, dataType, true, isAlphaPremultiplied); case TIFFExtension.PLANARCONFIG_PLANAR: - return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, dataType, true, isAlphaPremultiplied); } } throw new IIOException(String.format("Unsupported BitsPerSample for Gray + Alpha TIFF (expected 8, 16 or 32): %d", bitsPerSample)); - // TODO: More samples might be ok, if multiple alpha or unknown samples default: throw new IIOException(String.format("Unsupported SamplesPerPixel/BitsPerSample combination for Bi-level/Gray TIFF (expected 1/1, 1/2, 1/4, 1/8, 1/16 or 1/32, or 2/8, 2/16 or 2/32): %d/%d", samplesPerPixel, bitsPerSample)); @@ -403,15 +416,12 @@ public class TIFFImageReader extends ImageReaderBase { cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_sRGB) : ColorSpaces.createColorSpace(profile); - switch (samplesPerPixel) { + switch (significantSamples) { case 3: if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) { switch (planarConfiguration) { case TIFFBaseline.PLANARCONFIG_CHUNKY: - if (bitsPerSample == 8 && cs.isCS_sRGB()) { - return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR); - } - + // "TYPE_3_BYTE_RGB" if cs.isCS_sRGB() return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2}, dataType, false, false); case TIFFExtension.PLANARCONFIG_PLANAR: @@ -420,27 +430,18 @@ public class TIFFImageReader extends ImageReaderBase { } case 4: if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) { - // ExtraSamples 0=unspecified, 1=associated (pre-multiplied), 2=unassociated (TODO: Support unspecified, not alpha) - long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", true); - switch (planarConfiguration) { case TIFFBaseline.PLANARCONFIG_CHUNKY: - if (bitsPerSample == 8 && cs.isCS_sRGB()) { - return ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR); - } - - return ImageTypeSpecifiers.createInterleaved(cs, new int[]{ 0, 1, 2, 3}, dataType, true, extraSamples[0] == 1); + // "TYPE_4_BYTE_RGBA" if cs.isCS_sRGB() + return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2, 3}, dataType, true, isAlphaPremultiplied); case TIFFExtension.PLANARCONFIG_PLANAR: - return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1, 2, 3}, new int[] {0, 0, 0, 0}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1, 2, 3}, new int[] {0, 0, 0, 0}, dataType, true, isAlphaPremultiplied); } } else if (bitsPerSample == 4) { - long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", true); - - return ImageTypeSpecifier.createPacked(cs, 0xF000, 0xF00, 0xF0, 0xF, DataBuffer.TYPE_USHORT, extraSamples[0] == 1); + return ImageTypeSpecifiers.createPacked(cs, 0xF000, 0xF00, 0xF0, 0xF, DataBuffer.TYPE_USHORT, isAlphaPremultiplied); } - // TODO: More samples might be ok, if multiple alpha or unknown samples default: throw new IIOException(String.format("Unsupported SamplesPerPixels/BitsPerSample combination for RGB TIFF (expected 3/8, 4/8, 3/16 or 4/16): %d/%d", samplesPerPixel, bitsPerSample)); } @@ -452,8 +453,8 @@ public class TIFFImageReader extends ImageReaderBase { else if (bitsPerSample <= 0 || bitsPerSample > 16) { throw new IIOException("Bad BitsPerSample value for Palette TIFF (expected <= 16): " + bitsPerSample); } - // NOTE: If ExtraSamples is used, PlanarConfiguration must be taken into account also for pixel data + // NOTE: If ExtraSamples is used, PlanarConfiguration must be taken into account also for pixel data Entry colorMap = currentIFD.getEntryById(TIFF.TAG_COLOR_MAP); if (colorMap == null) { throw new IIOException("Missing ColorMap for Palette TIFF"); @@ -483,7 +484,7 @@ public class TIFFImageReader extends ImageReaderBase { cs = profile == null ? ColorSpaces.getColorSpace(ColorSpaces.CS_GENERIC_CMYK) : ColorSpaces.createColorSpace(profile); - switch (samplesPerPixel) { + switch (significantSamples) { case 4: if (bitsPerSample == 8 || bitsPerSample == 16) { switch (planarConfiguration) { @@ -495,19 +496,14 @@ public class TIFFImageReader extends ImageReaderBase { } case 5: if (bitsPerSample == 8 || bitsPerSample == 16) { - // ExtraSamples 0=unspecified, 1=associated (pre-multiplied), 2=unassociated (TODO: Support unspecified, not alpha) - long[] extraSamples = getValueAsLongArray(TIFF.TAG_EXTRA_SAMPLES, "ExtraSamples", true); - switch (planarConfiguration) { case TIFFBaseline.PLANARCONFIG_CHUNKY: - return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2, 3, 4}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0, 1, 2, 3, 4}, dataType, true, isAlphaPremultiplied); case TIFFExtension.PLANARCONFIG_PLANAR: - return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1, 2, 3, 4}, new int[] {0, 0, 0, 0, 0}, dataType, true, extraSamples[0] == 1); + return ImageTypeSpecifiers.createBanded(cs, new int[] {0, 1, 2, 3, 4}, new int[] {0, 0, 0, 0, 0}, dataType, true, isAlphaPremultiplied); } } - // TODO: More samples might be ok, if multiple alpha or unknown samples, consult ExtraSamples - default: throw new IIOException( String.format("Unsupported TIFF SamplesPerPixels/BitsPerSample combination for Separated TIFF (expected 4/8, 4/16, 5/8 or 5/16): %d/%s", samplesPerPixel, bitsPerSample) @@ -515,13 +511,42 @@ public class TIFFImageReader extends ImageReaderBase { } case TIFFBaseline.PHOTOMETRIC_MASK: // Transparency mask - + case TIFFExtension.PHOTOMETRIC_CIELAB: + case TIFFExtension.PHOTOMETRIC_ICCLAB: + case TIFFExtension.PHOTOMETRIC_ITULAB: + // L*a*b* color. Handled using conversion to linear RGB + case TIFFCustom.PHOTOMETRIC_LOGL: + case TIFFCustom.PHOTOMETRIC_LOGLUV: + // Log + case TIFFCustom.PHOTOMETRIC_CFA: + case TIFFCustom.PHOTOMETRIC_LINEAR_RAW: + // RAW (DNG) throw new IIOException("Unsupported TIFF PhotometricInterpretation value: " + interpretation); default: throw new IIOException("Unknown TIFF PhotometricInterpretation value: " + interpretation); } } + private int getOpaqueSamplesPerPixel(final int photometricInterpretation) throws IIOException { + switch (photometricInterpretation) { + case TIFFBaseline.PHOTOMETRIC_WHITE_IS_ZERO: + case TIFFBaseline.PHOTOMETRIC_BLACK_IS_ZERO: + case TIFFBaseline.PHOTOMETRIC_PALETTE: + case TIFFBaseline.PHOTOMETRIC_MASK: + return 1; + case TIFFBaseline.PHOTOMETRIC_RGB: + case TIFFExtension.PHOTOMETRIC_YCBCR: + case TIFFExtension.PHOTOMETRIC_CIELAB: + case TIFFExtension.PHOTOMETRIC_ICCLAB: + case TIFFExtension.PHOTOMETRIC_ITULAB: + return 3; + case TIFFExtension.PHOTOMETRIC_SEPARATED: + return getValueAsIntWithDefault(TIFF.TAG_NUMBER_OF_INKS, 4); + default: + throw new IIOException("Unknown TIFF PhotometricInterpretation value: " + photometricInterpretation); + } + } + private int getDataType(int sampleFormat, int bitsPerSample) throws IIOException { switch (sampleFormat) { case TIFFBaseline.SAMPLEFORMAT_UINT: @@ -623,9 +648,14 @@ public class TIFFImageReader extends ImageReaderBase { else { int bitsPerSample = (int) value[0]; - for (int i = 1; i < value.length; i++) { - if (value[i] != bitsPerSample) { - throw new IIOException("Variable BitsPerSample not supported: " + Arrays.toString(value)); + if (value.length == 3 && (value[0] == 5 && value[1] == 6 && value[2] == 5)) { + // Special case for UINT_565. We're good. + } + else { + for (int i = 1; i < value.length; i++) { + if (value[i] != bitsPerSample) { + throw new IIOException("Variable BitsPerSample not supported: " + Arrays.toString(value)); + } } } @@ -719,7 +749,7 @@ public class TIFFImageReader extends ImageReaderBase { int tilesAcross = (width + stripTileWidth - 1) / stripTileWidth; int tilesDown = (height + stripTileHeight - 1) / stripTileHeight; -// WritableRaster rowRaster = rawType.getColorModel().createCompatibleWritableRaster(stripTileWidth, 1); + // TODO: If extrasamples, we might need to create a raster with more samples... WritableRaster rowRaster = rawType.createBufferedImage(stripTileWidth, 1).getRaster(); Rectangle clip = new Rectangle(srcRegion); int row = 0; @@ -1310,120 +1340,169 @@ public class TIFFImageReader extends ImageReaderBase { final int colsInTile, final int rowsInTile, final DataInput input) throws IOException { + DataBuffer dataBuffer = tileRowRaster.getDataBuffer(); + int bands = dataBuffer.getNumBanks(); + boolean banded = bands > 1; + switch (tileRowRaster.getTransferType()) { case DataBuffer.TYPE_BYTE: - byte[] rowDataByte = ((DataBufferByte) tileRowRaster.getDataBuffer()).getData(); - for (int row = startRow; row < startRow + rowsInTile; row++) { - if (row >= srcRegion.y + srcRegion.height) { - break; // We're done with this tile - } + for (int band = 0; band < bands; band++) { + byte[] rowDataByte = ((DataBufferByte) dataBuffer).getData(band); + WritableRaster destChannel = banded + ? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band}) + : raster; + Raster srcChannel = banded + ? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band}) + : tileRowRaster; - input.readFully(rowDataByte); - - if (row % ySub == 0 && row >= srcRegion.y) { - normalizeBlack(interpretation, rowDataByte); - - // Subsample horizontal - if (xSub != 1) { - for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { - System.arraycopy(rowDataByte, x * xSub, rowDataByte, x, numBands); - } + for (int row = startRow; row < startRow + rowsInTile; row++) { + if (row >= srcRegion.y + srcRegion.height) { + break; // We're done with this tile } - raster.setDataElements(startCol, (row - srcRegion.y) / ySub, tileRowRaster); + input.readFully(rowDataByte); + + if (row % ySub == 0 && row >= srcRegion.y) { + normalizeBlack(interpretation, rowDataByte); + + // Subsample horizontal + if (xSub != 1) { + for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { + System.arraycopy(rowDataByte, x * xSub, rowDataByte, x, numBands); + } + } + + destChannel.setDataElements(startCol, (row - srcRegion.y) / ySub, srcChannel); + } + // Else skip data } - // Else skip data } break; case DataBuffer.TYPE_USHORT: case DataBuffer.TYPE_SHORT: - short[] rowDataShort = tileRowRaster.getTransferType() == DataBuffer.TYPE_USHORT - ? ((DataBufferUShort) tileRowRaster.getDataBuffer()).getData() - : ((DataBufferShort) tileRowRaster.getDataBuffer()).getData(); + for (int band = 0; band < bands; band++) { + short[] rowDataShort = dataBuffer.getDataType() == DataBuffer.TYPE_USHORT + ? ((DataBufferUShort) dataBuffer).getData(band) + : ((DataBufferShort) dataBuffer).getData(band); - for (int row = startRow; row < startRow + rowsInTile; row++) { - if (row >= srcRegion.y + srcRegion.height) { - break; // We're done with this tile - } + WritableRaster destChannel = banded + ? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band}) + : raster; + Raster srcChannel = banded + ? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band}) + : tileRowRaster; - readFully(input, rowDataShort); - - if (row >= srcRegion.y) { - normalizeBlack(interpretation, rowDataShort); - - // Subsample horizontal - if (xSub != 1) { - for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { - System.arraycopy(rowDataShort, x * xSub, rowDataShort, x, numBands); - } + for (int row = startRow; row < startRow + rowsInTile; row++) { + if (row >= srcRegion.y + srcRegion.height) { + break; // We're done with this tile } - raster.setDataElements(startCol, row - srcRegion.y, tileRowRaster); - // TODO: Possible speedup ~30%!: + readFully(input, rowDataShort); + + if (row >= srcRegion.y) { + normalizeBlack(interpretation, rowDataShort); + + // Subsample horizontal + if (xSub != 1) { + for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { + System.arraycopy(rowDataShort, x * xSub, rowDataShort, x, numBands); + } + } + + destChannel.setDataElements(startCol, row - srcRegion.y, srcChannel); + // TODO: Possible speedup ~30%!: // raster.setDataElements(startCol, row - srcRegion.y, colsInTile, 1, rowDataShort); + } + // Else skip data } - // Else skip data } break; case DataBuffer.TYPE_INT: - int[] rowDataInt = ((DataBufferInt) tileRowRaster.getDataBuffer()).getData(); + for (int band = 0; band < bands; band++) { + int[] rowDataInt = ((DataBufferInt) dataBuffer).getData(band); - for (int row = startRow; row < startRow + rowsInTile; row++) { - if (row >= srcRegion.y + srcRegion.height) { - break; // We're done with this tile - } + WritableRaster destChannel = banded + ? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band}) + : raster; + Raster srcChannel = banded + ? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band}) + : tileRowRaster; - readFully(input, rowDataInt); - - if (row >= srcRegion.y) { - normalizeBlack(interpretation, rowDataInt); - - // Subsample horizontal - if (xSub != 1) { - for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { - System.arraycopy(rowDataInt, x * xSub, rowDataInt, x, numBands); - } + for (int row = startRow; row < startRow + rowsInTile; row++) { + if (row >= srcRegion.y + srcRegion.height) { + break; // We're done with this tile } - raster.setDataElements(startCol, row - srcRegion.y, tileRowRaster); + readFully(input, rowDataInt); + + if (row >= srcRegion.y) { + normalizeBlack(interpretation, rowDataInt); + + // Subsample horizontal + if (xSub != 1) { + for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { + System.arraycopy(rowDataInt, x * xSub, rowDataInt, x, numBands); + } + } + + destChannel.setDataElements(startCol, row - srcRegion.y, srcChannel); + } + // Else skip data } - // Else skip data } break; case DataBuffer.TYPE_FLOAT: - float[] rowDataFloat = ((DataBufferFloat) tileRowRaster.getDataBuffer()).getData(); + for (int band = 0; band < bands; band++) { + float[] rowDataFloat = ((DataBufferFloat) tileRowRaster.getDataBuffer()).getData(band); - for (int row = startRow; row < startRow + rowsInTile; row++) { - if (row >= srcRegion.y + srcRegion.height) { - break; // We're done with this tile - } + WritableRaster destChannel = banded + ? raster.createWritableChild(raster.getMinX(), raster.getMinY(), raster.getWidth(), raster.getHeight(), 0, 0, new int[] {band}) + : raster; + Raster srcChannel = banded + ? tileRowRaster.createChild(tileRowRaster.getMinX(), 0, tileRowRaster.getWidth(), 1, 0, 0, new int[] {band}) + : tileRowRaster; - readFully(input, rowDataFloat); - - if (row >= srcRegion.y) { -// normalizeBlack(interpretation, rowDataFloat); - - // Subsample horizontal - if (xSub != 1) { - for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { - System.arraycopy(rowDataFloat, x * xSub, rowDataFloat, x, numBands); - } + for (int row = startRow; row < startRow + rowsInTile; row++) { + if (row >= srcRegion.y + srcRegion.height) { + break; // We're done with this tile } - raster.setDataElements(startCol, row - srcRegion.y, tileRowRaster); + readFully(input, rowDataFloat); + + if (row >= srcRegion.y) { + // TODO: Allow param to decide tone mapping strategy, like in the HDRImageReader + clamp(rowDataFloat); + + // Subsample horizontal + if (xSub != 1) { + for (int x = srcRegion.x / xSub * numBands; x < ((srcRegion.x + srcRegion.width) / xSub) * numBands; x += numBands) { + System.arraycopy(rowDataFloat, x * xSub, rowDataFloat, x, numBands); + } + } + + destChannel.setDataElements(startCol, row - srcRegion.y, srcChannel); + } + // Else skip data } - // Else skip data } break; } } + private void clamp(float[] rowDataFloat) { + for (int i = 0; i < rowDataFloat.length; i++) { + if (rowDataFloat[i] > 1) { + rowDataFloat[i] = 1; + } + } + } + // TODO: Candidate util method (with off/len + possibly byte order) private void readFully(final DataInput input, final float[] rowDataFloat) throws IOException { if (input instanceof ImageInputStream) { diff --git a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFProviderInfo.java b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFProviderInfo.java index 0a5e59d2..d484d5d5 100644 --- a/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFProviderInfo.java +++ b/imageio/imageio-tiff/src/main/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFProviderInfo.java @@ -50,8 +50,8 @@ final class TIFFProviderInfo extends ReaderWriterProviderInfo { new String[] {"com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReaderSpi"}, "com.twelvemonkeys.imageio.plugins.tiff.TIFFImageWriter", new String[] {"com.twelvemkonkeys.imageio.plugins.tif.TIFFImageWriterSpi"}, - false, TIFFMedataFormat.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadata", null, null, - true, TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME, "TODO", null, null + false, TIFFMedataFormat.SUN_NATIVE_STREAM_METADATA_FORMAT_NAME, "TODO", null, null, + true, TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME, "com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadata", null, null ); } } diff --git a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReaderTest.java b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReaderTest.java index 6d00c633..85d98d6b 100644 --- a/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReaderTest.java +++ b/imageio/imageio-tiff/src/test/java/com/twelvemonkeys/imageio/plugins/tiff/TIFFImageReaderTest.java @@ -95,8 +95,33 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest using a development version of +GraphicsMagick 1.2. + +See the file summary.txt for a description of the images. + +These files are hereby placed in the public domain. + + diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-02.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-02.tif new file mode 100644 index 00000000..2278aff1 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-02.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-04.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-04.tif new file mode 100644 index 00000000..2583c42f Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-04.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-06.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-06.tif new file mode 100644 index 00000000..a9c0c3dd Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-06.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-08.tif new file mode 100644 index 00000000..f7d83407 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-10.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-10.tif new file mode 100644 index 00000000..d93960cb Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-10.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-12.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-12.tif new file mode 100644 index 00000000..1673be84 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-12.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-14.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-14.tif new file mode 100644 index 00000000..1d53867f Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-14.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-16.tif new file mode 100644 index 00000000..3c2a6dd7 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-24.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-24.tif new file mode 100644 index 00000000..5035df45 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-24.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-32.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-32.tif new file mode 100644 index 00000000..36d48d4d Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-minisblack-32.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-02.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-02.tif new file mode 100644 index 00000000..6bd445de Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-02.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-04.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-04.tif new file mode 100644 index 00000000..b50ac8cc Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-04.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-08.tif new file mode 100644 index 00000000..b778037e Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-16.tif new file mode 100644 index 00000000..cf3de609 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-palette-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-02.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-02.tif new file mode 100644 index 00000000..3813313d Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-02.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-04.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-04.tif new file mode 100644 index 00000000..b469f946 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-04.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-08.tif new file mode 100644 index 00000000..2ea09440 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-10.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-10.tif new file mode 100644 index 00000000..b6a22402 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-10.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-12.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-12.tif new file mode 100644 index 00000000..20485733 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-12.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-14.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-14.tif new file mode 100644 index 00000000..c9e27c02 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-14.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-16.tif new file mode 100644 index 00000000..869fe05a Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-24.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-24.tif new file mode 100644 index 00000000..6037f52f Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-24.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-32.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-32.tif new file mode 100644 index 00000000..eb13d6c2 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-contig-32.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-02.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-02.tif new file mode 100644 index 00000000..afd364c7 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-02.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-04.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-04.tif new file mode 100644 index 00000000..ec97dc3b Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-04.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-08.tif new file mode 100644 index 00000000..bbe287fb Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-10.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-10.tif new file mode 100644 index 00000000..9d21bbe9 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-10.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-12.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-12.tif new file mode 100644 index 00000000..34a39449 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-12.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-14.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-14.tif new file mode 100644 index 00000000..2c690024 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-14.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-16.tif new file mode 100644 index 00000000..93566664 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-24.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-24.tif new file mode 100644 index 00000000..e9365d18 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-24.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-32.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-32.tif new file mode 100644 index 00000000..000391cf Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-rgb-planar-32.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-08.tif new file mode 100644 index 00000000..7eefd539 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-16.tif new file mode 100644 index 00000000..5df4246f Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-contig-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-08.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-08.tif new file mode 100644 index 00000000..6994a129 Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-08.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-16.tif b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-16.tif new file mode 100644 index 00000000..380b9b4f Binary files /dev/null and b/imageio/imageio-tiff/src/test/resources/tiff/depth/flower-separated-planar-16.tif differ diff --git a/imageio/imageio-tiff/src/test/resources/tiff/depth/summary.txt b/imageio/imageio-tiff/src/test/resources/tiff/depth/summary.txt new file mode 100644 index 00000000..19f3aabd --- /dev/null +++ b/imageio/imageio-tiff/src/test/resources/tiff/depth/summary.txt @@ -0,0 +1,37 @@ + +flower-minisblack-02.tif 73x43 2-bit minisblack gray image +flower-minisblack-04.tif 73x43 4-bit minisblack gray image +flower-minisblack-06.tif 73x43 6-bit minisblack gray image +flower-minisblack-08.tif 73x43 8-bit minisblack gray image +flower-minisblack-10.tif 73x43 10-bit minisblack gray image +flower-minisblack-12.tif 73x43 12-bit minisblack gray image +flower-minisblack-14.tif 73x43 14-bit minisblack gray image +flower-minisblack-16.tif 73x43 16-bit minisblack gray image +flower-minisblack-24.tif 73x43 24-bit minisblack gray image +flower-minisblack-32.tif 73x43 32-bit minisblack gray image +flower-palette-02.tif 73x43 4-entry colormapped image +flower-palette-04.tif 73x43 16-entry colormapped image +flower-palette-08.tif 73x43 256-entry colormapped image +flower-palette-16.tif 73x43 65536-entry colormapped image +flower-rgb-contig-02.tif 73x43 2-bit contiguous RGB image +flower-rgb-contig-04.tif 73x43 4-bit contiguous RGB image +flower-rgb-contig-08.tif 73x43 8-bit contiguous RGB image +flower-rgb-contig-10.tif 73x43 10-bit contiguous RGB image +flower-rgb-contig-12.tif 73x43 12-bit contiguous RGB image +flower-rgb-contig-14.tif 73x43 14-bit contiguous RGB image +flower-rgb-contig-16.tif 73x43 16-bit contiguous RGB image +flower-rgb-contig-24.tif 73x43 24-bit contiguous RGB image +flower-rgb-contig-32.tif 73x43 32-bit contiguous RGB image +flower-rgb-planar-02.tif 73x43 2-bit seperated RGB image +flower-rgb-planar-04.tif 73x43 4-bit seperated RGB image +flower-rgb-planar-08.tif 73x43 8-bit seperated RGB image +flower-rgb-planar-10.tif 73x43 10-bit seperated RGB image +flower-rgb-planar-12.tif 73x43 12-bit seperated RGB image +flower-rgb-planar-14.tif 73x43 14-bit seperated RGB image +flower-rgb-planar-16.tif 73x43 16-bit seperated RGB image +flower-rgb-planar-24.tif 73x43 24-bit seperated RGB image +flower-rgb-planar-32.tif 73x43 32-bit seperated RGB image +flower-separated-contig-08.tif 73x43 8-bit contiguous CMYK image +flower-separated-contig-16.tif 73x43 16-bit contiguous CMYK image +flower-separated-planar-08.tif 73x43 8-bit separated CMYK image +flower-separated-planar-16.tif 73x43 16-bit separated CMYK image