mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
#975: Fix for broken decoding gray + extra samples
This commit is contained in:
parent
f7d4557c57
commit
ee7d4ba724
@ -33,11 +33,12 @@ package com.twelvemonkeys.imageio.plugins.tiff;
|
|||||||
import com.twelvemonkeys.lang.Validate;
|
import com.twelvemonkeys.lang.Validate;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.color.ColorSpace;
|
import java.awt.color.*;
|
||||||
import java.awt.image.*;
|
import java.awt.image.*;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
import static java.awt.image.DataBuffer.getDataTypeSize;
|
import static com.twelvemonkeys.imageio.plugins.tiff.TIFFImageReader.createOffsets;
|
||||||
|
import static java.awt.image.DataBuffer.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExtraSamplesColorModel.
|
* ExtraSamplesColorModel.
|
||||||
@ -55,11 +56,25 @@ final class ExtraSamplesColorModel extends ComponentColorModel {
|
|||||||
private final int componentSize;
|
private final int componentSize;
|
||||||
|
|
||||||
ExtraSamplesColorModel(ColorSpace cs, boolean hasAlpha, boolean isAlphaPremultiplied, int dataType, int extraComponents) {
|
ExtraSamplesColorModel(ColorSpace cs, boolean hasAlpha, boolean isAlphaPremultiplied, int dataType, int extraComponents) {
|
||||||
super(cs, hasAlpha, isAlphaPremultiplied, Transparency.TRANSLUCENT, dataType);
|
this(cs, null, hasAlpha, isAlphaPremultiplied, dataType, extraComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExtraSamplesColorModel(ColorSpace cs, int[] bits, boolean hasAlpha, boolean isAlphaPremultiplied, int dataType, int extraComponents) {
|
||||||
|
super(cs, bits, hasAlpha, isAlphaPremultiplied, Transparency.TRANSLUCENT, dataType);
|
||||||
Validate.isTrue(extraComponents > 0, "Extra components must be > 0");
|
Validate.isTrue(extraComponents > 0, "Extra components must be > 0");
|
||||||
this.numComponents = cs.getNumComponents() + (hasAlpha ? 1 : 0) + extraComponents;
|
this.numComponents = cs.getNumComponents() + (hasAlpha ? 1 : 0) + extraComponents;
|
||||||
|
|
||||||
|
if (bits != null) {
|
||||||
|
Validate.isTrue(bits.length == numComponents, "bits.length must be == " + numComponents);
|
||||||
|
this.componentSize = bits[0];
|
||||||
|
for (int bit : bits) {
|
||||||
|
Validate.isTrue(bit == componentSize, "Variable bits per component not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
this.componentSize = getDataTypeSize(dataType);
|
this.componentSize = getDataTypeSize(dataType);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getNumComponents() {
|
public int getNumComponents() {
|
||||||
@ -160,4 +175,21 @@ final class ExtraSamplesColorModel extends ComponentColorModel {
|
|||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(super.hashCode(), numComponents, componentSize);
|
return Objects.hash(super.hashCode(), numComponents, componentSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SampleModel createCompatibleSampleModel(int w, int h) {
|
||||||
|
return new PixelInterleavedSampleModel(transferType, 1, 1, numComponents, numComponents, createOffsets(numComponents));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WritableRaster createCompatibleWritableRaster(int w, int h) {
|
||||||
|
switch (transferType) {
|
||||||
|
case DataBuffer.TYPE_BYTE:
|
||||||
|
case DataBuffer.TYPE_USHORT:
|
||||||
|
return Raster.createInterleavedRaster(transferType, w, h, numComponents, null);
|
||||||
|
default:
|
||||||
|
SampleModel sampleModel = createCompatibleSampleModel(w, h);
|
||||||
|
return Raster.createWritableRaster(sampleModel, sampleModel.createDataBuffer(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,18 +514,27 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : ColorSpaces.createColorSpace(profile);
|
cs = profile == null ? ColorSpace.getInstance(ColorSpace.CS_GRAY) : ColorSpaces.createColorSpace(profile);
|
||||||
|
|
||||||
if (cs == ColorSpace.getInstance(ColorSpace.CS_GRAY) && (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 || bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32)) {
|
if (samplesPerPixel == significantSamples && cs == ColorSpace.getInstance(ColorSpace.CS_GRAY)
|
||||||
|
&& (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 || bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32)) {
|
||||||
return ImageTypeSpecifiers.createGrayscale(bitsPerSample, dataType);
|
return ImageTypeSpecifiers.createGrayscale(bitsPerSample, dataType);
|
||||||
}
|
}
|
||||||
else if (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4) {
|
else if (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4) {
|
||||||
|
if (samplesPerPixel != significantSamples) {
|
||||||
|
throw new IIOException(String.format("ExtraSamples not supported for Bi-level/Gray TIFF with < 8 bitsPerSample: %d", bitsPerSample));
|
||||||
|
}
|
||||||
|
|
||||||
// Use packed format for 1/2/4 bits
|
// Use packed format for 1/2/4 bits
|
||||||
return ImageTypeSpecifiers.createPackedGrayscale(cs, bitsPerSample, dataType);
|
return ImageTypeSpecifiers.createPackedGrayscale(cs, bitsPerSample, dataType);
|
||||||
}
|
}
|
||||||
else if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) {
|
else if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) {
|
||||||
return createImageTypeSpecifier(TIFFBaseline.PLANARCONFIG_CHUNKY, cs, dataType, significantSamples, samplesPerPixel, false, false);
|
return createImageTypeSpecifier(planarConfiguration, cs, dataType, significantSamples, samplesPerPixel, hasAlpha, isAlphaPremultiplied);
|
||||||
}
|
}
|
||||||
else if (bitsPerSample % 2 == 0) {
|
else if (bitsPerSample % 2 == 0) {
|
||||||
ColorModel colorModel = new ComponentColorModel(cs, new int[] {bitsPerSample}, false, false, Transparency.OPAQUE, dataType);
|
int[] bits = new int[samplesPerPixel];
|
||||||
|
Arrays.fill(bits, bitsPerSample);
|
||||||
|
ColorModel colorModel = samplesPerPixel > significantSamples
|
||||||
|
? new ExtraSamplesColorModel(cs, bits, false, false, dataType, samplesPerPixel - significantSamples)
|
||||||
|
: new ComponentColorModel(cs, bits, false, false, Transparency.OPAQUE, dataType);
|
||||||
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1));
|
return new ImageTypeSpecifier(colorModel, colorModel.createCompatibleSampleModel(1, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +718,7 @@ public final class TIFFImageReader extends ImageReaderBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int[] createOffsets(int samplesPerPixel) {
|
static int[] createOffsets(int samplesPerPixel) {
|
||||||
int[] offsets = new int[samplesPerPixel];
|
int[] offsets = new int[samplesPerPixel];
|
||||||
for (int i = 0; i < samplesPerPixel; i++) {
|
for (int i = 0; i < samplesPerPixel; i++) {
|
||||||
offsets[i] = i;
|
offsets[i] = i;
|
||||||
|
@ -88,6 +88,7 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
|||||||
new TestData(getClassLoaderResource("/tiff/quad-lzw.tif"), new Dimension(512, 384)), // RGB, Old spec (reversed) LZW compressed, tiled
|
new TestData(getClassLoaderResource("/tiff/quad-lzw.tif"), new Dimension(512, 384)), // RGB, Old spec (reversed) LZW compressed, tiled
|
||||||
new TestData(getClassLoaderResource("/tiff/bali.tif"), new Dimension(725, 489)), // Palette-based, LZW compressed
|
new TestData(getClassLoaderResource("/tiff/bali.tif"), new Dimension(725, 489)), // Palette-based, LZW compressed
|
||||||
new TestData(getClassLoaderResource("/tiff/f14.tif"), new Dimension(640, 480)), // Gray, uncompressed
|
new TestData(getClassLoaderResource("/tiff/f14.tif"), new Dimension(640, 480)), // Gray, uncompressed
|
||||||
|
new TestData(getClassLoaderResource("/tiff/house.tif"), new Dimension(512, 512)), // Gray + extra sample, uncompressed
|
||||||
new TestData(getClassLoaderResource("/tiff/marbles.tif"), new Dimension(1419, 1001)), // RGB, LZW compressed w/predictor
|
new TestData(getClassLoaderResource("/tiff/marbles.tif"), new Dimension(1419, 1001)), // RGB, LZW compressed w/predictor
|
||||||
new TestData(getClassLoaderResource("/tiff/lzw-full-12-bit-table.tif"), new Dimension(874, 1240)), // Gray, LZW compressed, w/predictor
|
new TestData(getClassLoaderResource("/tiff/lzw-full-12-bit-table.tif"), new Dimension(874, 1240)), // Gray, LZW compressed, w/predictor
|
||||||
new TestData(getClassLoaderResource("/tiff/chifley_logo.tif"), new Dimension(591, 177)), // CMYK, uncompressed
|
new TestData(getClassLoaderResource("/tiff/chifley_logo.tif"), new Dimension(591, 177)), // CMYK, uncompressed
|
||||||
|
BIN
imageio/imageio-tiff/src/test/resources/tiff/house.tif
Normal file
BIN
imageio/imageio-tiff/src/test/resources/tiff/house.tif
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user