mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-04 03:55:28 -04:00
PNM clean-up.
This commit is contained in:
parent
60eab81709
commit
4d190892df
@ -35,6 +35,7 @@ import com.twelvemonkeys.imageio.spi.ImageReaderSpiBase;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Locale;
|
||||
|
||||
public final class PAMImageReaderSpi extends ImageReaderSpiBase {
|
||||
@ -53,13 +54,16 @@ public final class PAMImageReaderSpi extends ImageReaderSpiBase {
|
||||
}
|
||||
|
||||
ImageInputStream stream = (ImageInputStream) source;
|
||||
ByteOrder order = stream.getByteOrder();
|
||||
stream.mark();
|
||||
|
||||
try {
|
||||
stream.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
return stream.readShort() == PNM.PAM && stream.readInt() != PNM.XV_THUMBNAIL_MAGIC;
|
||||
}
|
||||
finally {
|
||||
stream.reset();
|
||||
stream.setByteOrder(order);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,6 @@ package com.twelvemonkeys.imageio.plugins.pnm;
|
||||
|
||||
import com.twelvemonkeys.io.FastByteArrayOutputStream;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@ -78,12 +77,12 @@ final class PNMHeaderParser extends HeaderParser {
|
||||
while (width == 0 || height == 0 || maxSample == 0) {
|
||||
tokenBuffer.delete(0, tokenBuffer.length());
|
||||
|
||||
while (tokenBuffer.length() < 16) {
|
||||
while (tokenBuffer.length() < 16) { // Limit reads if we should read across into the binary part...
|
||||
byte read = input.readByte();
|
||||
|
||||
if (read == '#') {
|
||||
// Read rest of the line as comment
|
||||
String comment = readComment(input);
|
||||
String comment = readLineUTF8(input);
|
||||
|
||||
if (!comment.trim().isEmpty()) {
|
||||
comments.add(comment);
|
||||
@ -111,11 +110,8 @@ final class PNMHeaderParser extends HeaderParser {
|
||||
else if (height == 0) {
|
||||
height = Integer.parseInt(token);
|
||||
}
|
||||
else if (maxSample == 0) {
|
||||
maxSample = Integer.parseInt(token);
|
||||
}
|
||||
else {
|
||||
throw new IIOException("Unknown PNM token: " + token);
|
||||
maxSample = Integer.parseInt(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -123,22 +119,27 @@ final class PNMHeaderParser extends HeaderParser {
|
||||
return new PNMHeader(fileType, tupleType, width, height, tupleType.getSamplesPerPixel(), maxSample, comments);
|
||||
}
|
||||
|
||||
private static String readComment(final ImageInputStream input) throws IOException {
|
||||
ByteArrayOutputStream commentBuffer = new FastByteArrayOutputStream(128);
|
||||
// Similar to DataInput.readLine, except it uses UTF8 encoding
|
||||
private static String readLineUTF8(final ImageInputStream input) throws IOException {
|
||||
ByteArrayOutputStream buffer = new FastByteArrayOutputStream(128);
|
||||
|
||||
int read;
|
||||
int value;
|
||||
do {
|
||||
switch (read = input.read()) {
|
||||
case -1:
|
||||
case '\n':
|
||||
switch (value = input.read()) {
|
||||
case '\r':
|
||||
read = -1;
|
||||
// Check for CR + LF pattern and skip, otherwise fall through
|
||||
if (input.read() != '\n') {
|
||||
input.seek(input.getStreamPosition() - 1);
|
||||
}
|
||||
case '\n':
|
||||
case -1:
|
||||
value = -1;
|
||||
break;
|
||||
default:
|
||||
commentBuffer.write(read);
|
||||
buffer.write(value);
|
||||
}
|
||||
} while (read != -1);
|
||||
} while (value != -1);
|
||||
|
||||
return commentBuffer.toString("UTF8");
|
||||
return buffer.toString("UTF8");
|
||||
}
|
||||
}
|
||||
|
@ -49,12 +49,14 @@ import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static com.twelvemonkeys.imageio.util.IIOUtil.subsampleRow;
|
||||
import static com.twelvemonkeys.imageio.util.RasterUtils.asByteRaster;
|
||||
|
||||
public final class PNMImageReader extends ImageReaderBase {
|
||||
// TODO: Allow reading unknown tuple types as Raster!
|
||||
@ -73,6 +75,7 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
|
||||
private void readHeader() throws IOException {
|
||||
if (header == null) {
|
||||
imageInput.setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
header = HeaderParser.parse(imageInput);
|
||||
|
||||
imageInput.flushBefore(imageInput.getStreamPosition());
|
||||
@ -122,27 +125,19 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
case GRAYSCALE_ALPHA:
|
||||
case BLACKANDWHITE:
|
||||
case GRAYSCALE:
|
||||
// PGM: Linear or non-linear gray?
|
||||
ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
|
||||
if (header.getTransferType() == DataBuffer.TYPE_FLOAT) {
|
||||
return ImageTypeSpecifiers.createInterleaved(gray, createBandOffsets(samplesPerPixel), transferType, hasAlpha, false);
|
||||
}
|
||||
if (header.getMaxSample() <= PNM.MAX_VAL_16BIT) {
|
||||
return hasAlpha ? ImageTypeSpecifiers.createGrayscale(bitsPerSample, transferType, false)
|
||||
: ImageTypeSpecifiers.createGrayscale(bitsPerSample, transferType);
|
||||
}
|
||||
|
||||
// PGM: Linear or non-linear gray?
|
||||
ColorSpace gray = ColorSpace.getInstance(ColorSpace.CS_GRAY);
|
||||
return ImageTypeSpecifiers.createInterleaved(gray, createBandOffsets(samplesPerPixel), transferType, hasAlpha, false);
|
||||
|
||||
case RGB:
|
||||
case RGB_ALPHA:
|
||||
// Using sRGB seems sufficient for PPM, as it is very close to ITU-R Recommendation BT.709 (same gamut and white point CIE D65)
|
||||
ColorSpace sRGB = ColorSpace.getInstance(ColorSpace.CS_sRGB);
|
||||
if (header.getTransferType() == DataBuffer.TYPE_FLOAT) {
|
||||
return ImageTypeSpecifiers.createInterleaved(sRGB, createBandOffsets(samplesPerPixel), transferType, hasAlpha, false);
|
||||
}
|
||||
|
||||
return ImageTypeSpecifiers.createInterleaved(sRGB, createBandOffsets(samplesPerPixel), transferType, hasAlpha, false);
|
||||
|
||||
case CMYK:
|
||||
@ -185,10 +180,9 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
case RGB_ALPHA:
|
||||
if (header.getTransferType() == DataBuffer.TYPE_BYTE) {
|
||||
specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR));
|
||||
// TODO: Why does ColorConvertOp choke on these (Ok, because it misinterprets the alpha channel for a color component, but how do we make it work)?
|
||||
// specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
||||
specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB));
|
||||
specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE));
|
||||
specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_4BYTE_ABGR_PRE));
|
||||
// specifiers.add(ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB_PRE));
|
||||
}
|
||||
|
||||
break;
|
||||
@ -215,11 +209,6 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
Rectangle destRegion = new Rectangle();
|
||||
computeRegions(param, width, height, destination, srcRegion, destRegion);
|
||||
|
||||
WritableRaster destRaster = clipToRect(destination.getRaster(), destRegion, param != null
|
||||
? param.getDestinationBands()
|
||||
: null);
|
||||
checkReadParamBandSettings(param, rawType.getNumBands(), destRaster.getNumBands());
|
||||
|
||||
WritableRaster rowRaster = rawType.createBufferedImage(width, 1).getRaster();
|
||||
// Clip to source region
|
||||
Raster clippedRow = clipRowToRect(rowRaster, srcRegion,
|
||||
@ -247,10 +236,10 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
throw new AssertionError("Unsupported transfer type: " + transferType);
|
||||
}
|
||||
|
||||
ColorConvertOp colorConvert = null;
|
||||
if (!destination.getColorModel().isCompatibleRaster(rowRaster)) {
|
||||
colorConvert = new ColorConvertOp(rawType.getColorModel().getColorSpace(), destination.getColorModel().getColorSpace(), null);
|
||||
}
|
||||
WritableRaster destRaster = transferType == DataBuffer.TYPE_BYTE ? asByteRaster(destination.getRaster())
|
||||
: destination.getRaster();
|
||||
destRaster = clipToRect(destRaster, destRegion, param != null ? param.getDestinationBands() : null);
|
||||
checkReadParamBandSettings(param, rawType.getNumBands(), destRaster.getNumBands());
|
||||
|
||||
int xSub = param == null ? 1 : param.getSourceXSubsampling();
|
||||
int ySub = param == null ? 1 : param.getSourceYSubsampling();
|
||||
@ -262,7 +251,7 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
for (int y = 0; y < height; y++) {
|
||||
switch (transferType) {
|
||||
case DataBuffer.TYPE_BYTE:
|
||||
readRowByte(destRaster, clippedRow, colorConvert, rowDataByte, header.getBitsPerSample(), samplesPerPixel, input, y, srcRegion, xSub, ySub);
|
||||
readRowByte(destRaster, clippedRow, rowDataByte, header.getBitsPerSample(), samplesPerPixel, input, y, srcRegion, xSub, ySub);
|
||||
break;
|
||||
case DataBuffer.TYPE_USHORT:
|
||||
readRowUShort(destRaster, clippedRow, rowDataUShort, samplesPerPixel, input, y, srcRegion, xSub, ySub);
|
||||
@ -287,6 +276,10 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
}
|
||||
}
|
||||
|
||||
if (destination.isAlphaPremultiplied()) {
|
||||
rawType.getColorModel().coerceData(destRaster, true);
|
||||
}
|
||||
|
||||
processImageComplete();
|
||||
|
||||
return destination;
|
||||
@ -338,7 +331,6 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
|
||||
private void readRowByte(final WritableRaster destRaster,
|
||||
Raster rowRaster,
|
||||
final ColorConvertOp colorConvert,
|
||||
final byte[] rowDataByte,
|
||||
final int bitsPerSample, final int samplesPerPixel,
|
||||
final DataInput input, final int y,
|
||||
@ -357,12 +349,7 @@ public final class PNMImageReader extends ImageReaderBase {
|
||||
normalize(rowDataByte, 0, rowDataByte.length / xSub);
|
||||
|
||||
int destY = (y - srcRegion.y) / ySub;
|
||||
if (colorConvert != null) {
|
||||
colorConvert.filter(rowRaster, destRaster.createWritableChild(0, destY, rowRaster.getWidth(), 1, 0, 0, null));
|
||||
}
|
||||
else {
|
||||
destRaster.setDataElements(0, destY, rowRaster);
|
||||
}
|
||||
destRaster.setDataElements(0, destY, rowRaster);
|
||||
}
|
||||
|
||||
private void readRowUShort(final WritableRaster destRaster,
|
||||
|
@ -57,7 +57,7 @@ public final class PNMImageReaderSpi extends ImageReaderSpiBase {
|
||||
stream.mark();
|
||||
|
||||
try {
|
||||
short magic = stream.readShort();
|
||||
short magic = (short) ((stream.readByte() & 0xFF) << 8 | (stream.readByte() & 0xFF));
|
||||
|
||||
switch (magic) {
|
||||
case PNM.PBM_PLAIN:
|
||||
|
@ -33,7 +33,9 @@ import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
@ -102,6 +104,33 @@ public class PAMImageReaderTest extends ImageReaderAbstractTest<PNMImageReader>
|
||||
assertImageDataEquals("Images differ from reference", expected, reader.read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypes() throws IOException {
|
||||
ImageReader reader = createReader();
|
||||
TestData data = new TestData(getClassLoaderResource("/pam/rgba.pam"), new Dimension(4, 2));
|
||||
reader.setInput(data.getInputStream());
|
||||
|
||||
int[] types = new int[] {BufferedImage.TYPE_INT_ARGB, BufferedImage.TYPE_4BYTE_ABGR, BufferedImage.TYPE_INT_ARGB_PRE};
|
||||
|
||||
for (int type : types) {
|
||||
BufferedImage expected = new BufferedImage(4, 2, type);
|
||||
|
||||
expected.setRGB(0, 0, new Color(0, 0, 255).getRGB());
|
||||
expected.setRGB(1, 0, new Color(0, 255, 0).getRGB());
|
||||
expected.setRGB(2, 0, new Color(255, 0, 0).getRGB());
|
||||
expected.setRGB(3, 0, new Color(255, 255, 255).getRGB());
|
||||
|
||||
expected.setRGB(0, 1, new Color(0, 0, 255, 127).getRGB());
|
||||
expected.setRGB(1, 1, new Color(0, 255, 0, 127).getRGB());
|
||||
expected.setRGB(2, 1, new Color(255, 0, 0, 127).getRGB());
|
||||
expected.setRGB(3, 1, new Color(255, 255, 255, 127).getRGB());
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setDestinationType(ImageTypeSpecifier.createFromBufferedImageType(type));
|
||||
assertImageDataEquals("Images differ from reference for type: " + type, expected, reader.read(0, param));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testXVThumbNotIncorrectlyRecognizedAsPAM() throws IOException {
|
||||
assertTrue("Should recognize PAM format", provider.canDecodeInput(new TestData(getClassLoaderResource("/pam/rgba.pam"), new Dimension()).getInputStream())); // Sanity
|
||||
|
@ -33,7 +33,9 @@ import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
@ -120,4 +122,29 @@ public class PNMImageReaderTest extends ImageReaderAbstractTest<PNMImageReader>
|
||||
|
||||
assertImageDataEquals("Images differ from reference", expected, reader.read(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTypes() throws IOException {
|
||||
ImageReader reader = createReader();
|
||||
TestData data = new TestData(getClassLoaderResource("/ppm/colors.ppm"), new Dimension(3, 2));
|
||||
reader.setInput(data.getInputStream());
|
||||
|
||||
int[] types = new int[] {BufferedImage.TYPE_INT_RGB, BufferedImage.TYPE_INT_BGR, BufferedImage.TYPE_3BYTE_BGR};
|
||||
|
||||
for (int type : types) {
|
||||
BufferedImage expected = new BufferedImage(3, 2, type);
|
||||
|
||||
expected.setRGB(0, 0, new Color(255, 0, 0).getRGB());
|
||||
expected.setRGB(1, 0, new Color(0, 255, 0).getRGB());
|
||||
expected.setRGB(2, 0, new Color(0, 0, 255).getRGB());
|
||||
|
||||
expected.setRGB(0, 1, new Color(255, 255, 0).getRGB());
|
||||
expected.setRGB(1, 1, new Color(255, 255, 255).getRGB());
|
||||
expected.setRGB(2, 1, new Color(0, 0, 0).getRGB());
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setDestinationType(ImageTypeSpecifier.createFromBufferedImageType(type));
|
||||
assertImageDataEquals("Images differ from reference for type: " + type, expected, reader.read(0, param));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user