mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 20:15:28 -04:00
#267: Reads monochrome images with gray ICC profile.
This commit is contained in:
parent
9a6096664e
commit
f4b61820ac
@ -28,12 +28,14 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.util;
|
||||
|
||||
import com.twelvemonkeys.lang.Validate;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import java.awt.color.ColorSpace;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.DirectColorModel;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.awt.image.*;
|
||||
|
||||
import static com.twelvemonkeys.lang.Validate.isTrue;
|
||||
import static com.twelvemonkeys.lang.Validate.notNull;
|
||||
|
||||
/**
|
||||
* Factory class for creating {@code ImageTypeSpecifier}s.
|
||||
@ -59,17 +61,9 @@ public final class ImageTypeSpecifiers {
|
||||
final int transferType, boolean isAlphaPremultiplied) {
|
||||
if (transferType == DataBuffer.TYPE_BYTE || transferType == DataBuffer.TYPE_USHORT) {
|
||||
// ImageTypeSpecifier unconditionally uses bits == 32, we'll use a workaround for BYTE/USHORT types
|
||||
if (colorSpace == null) {
|
||||
throw new IllegalArgumentException("colorSpace == null!");
|
||||
}
|
||||
|
||||
if (colorSpace.getType() != ColorSpace.TYPE_RGB) {
|
||||
throw new IllegalArgumentException("colorSpace is not of type TYPE_RGB!");
|
||||
}
|
||||
|
||||
if (redMask == 0 && greenMask == 0 && blueMask == 0 && alphaMask == 0) {
|
||||
throw new IllegalArgumentException("No mask has at least 1 bit set!");
|
||||
}
|
||||
notNull(colorSpace, "colorSpace");
|
||||
isTrue(colorSpace.getType() == ColorSpace.TYPE_RGB, colorSpace, "ColorSpace must be TYPE_RGB");
|
||||
isTrue(redMask != 0 || greenMask != 0 || blueMask != 0 || alphaMask != 0, "No mask has at least 1 bit set");
|
||||
|
||||
int bits = transferType == DataBuffer.TYPE_BYTE ? 8 : 16;
|
||||
|
||||
@ -131,6 +125,34 @@ public final class ImageTypeSpecifiers {
|
||||
return ImageTypeSpecifier.createGrayscale(bits, dataType, false, isAlphaPremultiplied);
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createPackedGrayscale(final ColorSpace colorSpace, final int bits, final int dataType) {
|
||||
notNull(colorSpace, "colorSpace");
|
||||
isTrue(colorSpace.getType() == ColorSpace.TYPE_GRAY, colorSpace, "ColorSpace must be TYPE_GRAY");
|
||||
isTrue(bits == 1 || bits == 2 || bits == 4, bits, "bits must be 1, 2, or 4: %s");
|
||||
isTrue(dataType == DataBuffer.TYPE_BYTE, dataType, "dataType must be TYPE_BYTE: %s");
|
||||
|
||||
int numEntries = 1 << bits;
|
||||
|
||||
byte[] arr = new byte[numEntries];
|
||||
byte[] arg = new byte[numEntries];
|
||||
byte[] arb = new byte[numEntries];
|
||||
|
||||
// Scale array values according to color profile..
|
||||
for (int i = 0; i < numEntries; i++) {
|
||||
float[] gray = new float[]{i / (float) (numEntries - 1)};
|
||||
float[] rgb = colorSpace.toRGB(gray);
|
||||
|
||||
arr[i] = (byte) (rgb[0] * 255);
|
||||
arg[i] = (byte) (rgb[1] * 255);
|
||||
arb[i] = (byte) (rgb[2]* 255);
|
||||
}
|
||||
|
||||
ColorModel colorModel = new IndexColorModel(bits, numEntries, arr, arg, arb);
|
||||
SampleModel sampleModel = new MultiPixelPackedSampleModel(dataType, 1, 1, bits);
|
||||
|
||||
return new ImageTypeSpecifier(colorModel, sampleModel);
|
||||
}
|
||||
|
||||
public static ImageTypeSpecifier createIndexed(final byte[] redLUT, final byte[] greenLUT,
|
||||
final byte[] blueLUT, final byte[] alphaLUT,
|
||||
final int bits, final int dataType) {
|
||||
|
@ -463,6 +463,30 @@ public class ImageTypeSpecifiersTest {
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePackedGrayscale1() {
|
||||
assertEquals(
|
||||
ImageTypeSpecifier.createGrayscale(1, DataBuffer.TYPE_BYTE, false),
|
||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 1, DataBuffer.TYPE_BYTE)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePackedGrayscale2() {
|
||||
assertEquals(
|
||||
ImageTypeSpecifier.createGrayscale(2, DataBuffer.TYPE_BYTE, false),
|
||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 2, DataBuffer.TYPE_BYTE)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreatePackedGrayscale4() {
|
||||
assertEquals(
|
||||
ImageTypeSpecifier.createGrayscale(4, DataBuffer.TYPE_BYTE, false),
|
||||
ImageTypeSpecifiers.createPackedGrayscale(GRAY, 4, DataBuffer.TYPE_BYTE)
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateIndexedByteArrays1to8() {
|
||||
for (int bits = 1; bits <= 8; bits <<= 1) {
|
||||
|
@ -364,8 +364,11 @@ public class TIFFImageReader extends ImageReaderBase {
|
||||
if (cs == ColorSpace.getInstance(ColorSpace.CS_GRAY) && (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 || bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32)) {
|
||||
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
|
||||
else if (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4 ) {
|
||||
// Use packed format for 1/2/4 bits
|
||||
return ImageTypeSpecifiers.createPackedGrayscale(cs, bitsPerSample, dataType);
|
||||
}
|
||||
else if (bitsPerSample == 8 || bitsPerSample == 16 || bitsPerSample == 32) {
|
||||
return ImageTypeSpecifiers.createInterleaved(cs, new int[] {0}, dataType, false, false);
|
||||
}
|
||||
|
||||
|
@ -90,6 +90,7 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-rgba-padded-icc.tif"), new Dimension(19, 11)), // RGBA, LZW compression with padded ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-rgba-4444.tif"), new Dimension(64, 64)), // RGBA, LZW compression with UINT 4/4/4/4 + gray 2/2
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-buffer-overflow.tif"), new Dimension(5, 49)), // RGBA, LZW compression, will throw IOOBE if small buffer
|
||||
new TestData(getClassLoaderResource("/tiff/scan-mono-iccgray.tif"), new Dimension(2408, 3436)), // B/W, PackBits w/gray ICC profile
|
||||
// CCITT
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_1d.tif"), new Dimension(6, 4)), // B/W, CCITT T4 1D
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_1d_fill.tif"), new Dimension(6, 4)), // B/W, CCITT T4 1D
|
||||
|
BIN
imageio/imageio-tiff/src/test/resources/tiff/scan-mono-iccgray.tif
Executable file
BIN
imageio/imageio-tiff/src/test/resources/tiff/scan-mono-iccgray.tif
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user