- Implemented test for explicit destination type in ImageReaderBase.

- Implemented/enabled more test cases
- Fixed broken tests in various readers
This commit is contained in:
Harald Kuhr 2009-10-05 23:29:21 +02:00
parent 2759dc3a99
commit 96b65bc902
5 changed files with 186 additions and 44 deletions

View File

@ -31,9 +31,7 @@ package com.twelvemonkeys.imageio;
import com.twelvemonkeys.image.BufferedImageIcon;
import com.twelvemonkeys.imageio.util.IIOUtil;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.*;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
@ -46,6 +44,7 @@ import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Iterator;
/**
* ImageReaderBase
@ -191,6 +190,79 @@ public abstract class ImageReaderBase extends ImageReader {
}
}
/**
* Returns the {@code BufferedImage} to which decoded pixel
* data should be written.
* <p/>
* As {@link javax.imageio.ImageReader#getDestination} but tests if the explicit destination
* image (if set) is valid according to the {@code ImageTypeSpecifier}s given in {@code pTypes}
*
*
* @param pParam an {@code ImageReadParam} to be used to get
* the destination image or image type, or {@code null}.
* @param pTypes an {@code Iterator} of
* {@code ImageTypeSpecifier}s indicating the legal image
* types, with the default first.
* @param pWidth the true width of the image or tile begin decoded.
* @param pHeight the true width of the image or tile being decoded.
*
* @return the {@code BufferedImage} to which decoded pixel
* data should be written.
*
* @exception IIOException if the {@code ImageTypeSpecifier} or {@code BufferedImage}
* specified by {@code pParam} does not match any of the legal
* ones from {@code pTypes}.
* @throws IllegalArgumentException if {@code pTypes}
* is {@code null} or empty, or if an object not of type
* {@code ImageTypeSpecifier} is retrieved from it.
* Or, if the resulting image would
* have a width or height less than 1,
* or if the product of
* {@code pWidth} and {@code pHeight} is greater than
* {@code Integer.MAX_VALUE}.
*/
public static BufferedImage getDestination(final ImageReadParam pParam, final Iterator<ImageTypeSpecifier> pTypes,
final int pWidth, final int pHeight) throws IIOException {
BufferedImage image = ImageReader.getDestination(pParam, pTypes, pWidth, pHeight);
if (pParam != null) {
BufferedImage dest = pParam.getDestination();
if (dest != null) {
boolean found = false;
// NOTE: This is bad, as it relies on implementation details of super method...
// We know that the iterator has not been touched if explicit destination..
while (pTypes.hasNext()) {
ImageTypeSpecifier specifier = pTypes.next();
int imageType = specifier.getBufferedImageType();
if (imageType != 0 && imageType == dest.getType()) {
// Known types equal, perfect match
found = true;
break;
}
else {
// If types are different, or TYPE_CUSTOM, test if
// - transferType is ok
// - bands are ok
// TODO: Test if color model is ok?
if (specifier.getSampleModel().getTransferType() == dest.getSampleModel().getTransferType() &&
specifier.getNumBands() <= dest.getSampleModel().getNumBands()) {
found = true;
break;
}
}
}
if (!found) {
throw new IIOException(String.format("Illegal explicit destination image %s", dest));
}
}
}
return image;
}
/**
* Utility method for getting the area of interest (AOI) of an image.
* The AOI is defined by the {@link javax.imageio.IIOParam#setSourceRegion(java.awt.Rectangle)}

View File

@ -540,14 +540,14 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
}
public void readAsRenderedImageIndexNegative() {
public void testReadAsRenderedImageIndexNegative() {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
RenderedImage image = null;
try {
image = reader.read(-1, reader.getDefaultReadParam());
image = reader.readAsRenderedImage(-1, reader.getDefaultReadParam());
fail("Read image with illegal index");
}
catch (IndexOutOfBoundsException expected) {
@ -559,14 +559,14 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
assertNull(image);
}
public void readAsRenderedImageIndexOutOfBounds() {
public void testReadAsRenderedImageIndexOutOfBounds() {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
RenderedImage image = null;
try {
image = reader.read(11, reader.getDefaultReadParam());
image = reader.readAsRenderedImage(reader.getNumImages(true), reader.getDefaultReadParam());
fail("Read image with index out of bounds");
}
catch (IndexOutOfBoundsException expected) {
@ -578,7 +578,7 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
assertNull(image);
}
public void readAsRenderedImageNoInput() {
public void testReadAsRenderedImageNoInput() {
ImageReader reader = createReader();
// Do not set input
@ -596,7 +596,7 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
assertNull(image);
}
public void readAsRenderedImage() {
public void testReadAsRenderedImage() {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
@ -615,7 +615,7 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
data.getDimension(0).height, image.getHeight());
}
public void readAsRenderedImageWithDefaultParam() {
public void testReadAsRenderedImageWithDefaultParam() {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
@ -1181,28 +1181,93 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
assertSame(destination, result);
}
// TODO: This test is foobar..
public void testSetDestinationIllegal() throws IOException {
// TODO: Test that the reader throws IIOException if given an illegal destination
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
List<ImageTypeSpecifier> illegalTypes = createIllegalTypes(reader.getImageTypes(0));
ImageReadParam param = reader.getDefaultReadParam();
// TODO: Should either be a type from image type specifiers or throw IIOException in read
BufferedImage destination = new BufferedImage(50, 50, BufferedImage.TYPE_INT_RGB);
param.setDestination(destination);
for (ImageTypeSpecifier illegalType : illegalTypes) {
BufferedImage destination = illegalType.createBufferedImage(50, 50);
param.setDestination(destination);
try {
reader.read(0, param);
fail("Expected to throw exception with wrong type specifier");
try {
reader.read(0, param);
// NOTE: We allow the reader to read, as it's inconvenient to test all possible cases.
// However, it may NOT fail with any other exception in that case.
System.err.println("WARNING: Reader does not throw exception with non-declared destination: " + destination);
}
catch (IIOException expected) {
// TODO: This is thrown by ImageReader.getDestination. But are we happy with that?
// The problem is that the checkReadParamBandSettings throws IllegalArgumentException, which seems more appropriate...
String message = expected.getMessage();
assertTrue("Wrong message: " + message, message.toLowerCase().contains("destination"));
}
catch (IllegalArgumentException expected) {
String message = expected.getMessage();
assertTrue("Wrong message: " + message, message.toLowerCase().contains("dest"));
}
}
catch (IIOException e) {
assertTrue(e.getMessage().toLowerCase().contains("type"));
}
public void testSetDestinationTypeIllegal() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
List<ImageTypeSpecifier> illegalTypes = createIllegalTypes(reader.getImageTypes(0));
ImageReadParam param = reader.getDefaultReadParam();
for (ImageTypeSpecifier illegalType : illegalTypes) {
param.setDestinationType(illegalType);
try {
reader.read(0, param);
fail("Expected to throw exception with illegal type specifier");
}
catch (IIOException expected) {
// TODO: This is thrown by ImageReader.getDestination. But are we happy with that?
String message = expected.getMessage();
assertTrue(message.toLowerCase().contains("destination"));
assertTrue(message.toLowerCase().contains("type"));
}
catch (IllegalArgumentException expected) {
String message = expected.getMessage();
assertTrue(message.toLowerCase().contains("destination"));
assertTrue(message.toLowerCase().contains("type"));
}
}
}
private List<ImageTypeSpecifier> createIllegalTypes(Iterator<ImageTypeSpecifier> pValidTypes) {
List<ImageTypeSpecifier> allTypes = new ArrayList<ImageTypeSpecifier>();
for (int i = BufferedImage.TYPE_INT_RGB; i < BufferedImage.TYPE_BYTE_INDEXED; i++) {
allTypes.add(ImageTypeSpecifier.createFromBufferedImageType(i));
}
List<ImageTypeSpecifier> illegalTypes = new ArrayList<ImageTypeSpecifier>(allTypes);
while (pValidTypes.hasNext()) {
ImageTypeSpecifier valid = pValidTypes.next();
boolean removed = illegalTypes.remove(valid);
// TODO: 4BYTE_ABGR (6) and 4BYTE_ABGR_PRE (7) is essentially the same type...
// !#$#§%$! ImageTypeSpecifier.equals is not well-defined
if (!removed) {
for (Iterator<ImageTypeSpecifier> iterator = illegalTypes.iterator(); iterator.hasNext();) {
ImageTypeSpecifier illegalType = iterator.next();
if (illegalType.getBufferedImageType() == valid.getBufferedImageType()) {
iterator.remove();
}
}
}
}
return illegalTypes;
}
// TODO: Test dest offset + destination set?
public void testSetDestinationOffset() throws IOException {
final ImageReader reader = createReader();
@ -1266,18 +1331,17 @@ public abstract class ImageReaderAbstractTestCase<T extends ImageReader> extends
}
}
public void testSetDestinationTypeIllegal() throws IOException {
throw new UnsupportedOperationException("Method testSetDestinationTypeIllegal not implemented"); // TODO: Implement
}
public void testSetDestinationBands() throws IOException {
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
}
public void testSetSourceBands() throws IOException {
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
}
// public void testSetDestinationTypeIllegal() throws IOException {
// throw new UnsupportedOperationException("Method testSetDestinationTypeIllegal not implemented"); // TODO: Implement
// }
//
// public void testSetDestinationBands() throws IOException {
// throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
// }
//
// public void testSetSourceBands() throws IOException {
// throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
// }
protected URL getClassLoaderResource(final String pName) {
return getClass().getResource(pName);

View File

@ -292,10 +292,9 @@ public class ICOImageReader extends ImageReaderBase {
}
private BufferedImage readBitmap(final DirectoryEntry pEntry) throws IOException {
// TODO: Currently, we have a memory leak, as the values refer to the keys...
BitmapDescriptor descriptor = mDescriptors.get(pEntry);
if (!mDescriptors.containsKey(pEntry)) {
if (descriptor == null || !mDescriptors.containsKey(pEntry)) {
DIBHeader header = getHeader(pEntry);
int offset = pEntry.getOffset() + header.getSize();

View File

@ -2604,6 +2604,7 @@ public class PICTImageReader extends ImageReaderBase {
processImageStarted(pIndex);
// TODO: Param handling
// TODO: Real subsampling for bit/pixmap/QT stills
final int subX, subY;
if (pParam != null) {
subX = pParam.getSourceXSubsampling();

View File

@ -276,11 +276,9 @@ public class PSDImageReader extends ImageReaderBase {
readImageResources(false);
readLayerAndMaskInfo(false);
// TODO: Test if explicit destination is compatible or throw IllegalArgumentException
BufferedImage image = getDestination(pParam, getImageTypes(pIndex), mHeader.mWidth, mHeader.mHeight);
ImageTypeSpecifier rawType = getRawImageType(pIndex);
processImageStarted(pIndex);
checkReadParamBandSettings(pParam, rawType.getNumBands(), image.getSampleModel().getNumBands());
final Rectangle source = new Rectangle();
final Rectangle dest = new Rectangle();
@ -293,7 +291,7 @@ public class PSDImageReader extends ImageReaderBase {
// TODO: Create temp raster in native format w * 1
// Read (sub-sampled) row into temp raster (skip other rows)
// If color model (color space) is not RGB, do color convert op
// Otherwise, copy "through" ColorMode?l
// Otherwise, copy "through" ColorModel?
// Copy pixels from temp raster
// If possible, leave the destination image "untouched" (accelerated)
@ -322,6 +320,8 @@ public class PSDImageReader extends ImageReaderBase {
ySub = pParam.getSourceYSubsampling();
}
processImageStarted(pIndex);
int[] offsets = null;
int compression = mImageInput.readShort();
@ -342,7 +342,12 @@ public class PSDImageReader extends ImageReaderBase {
// Could be same as PNG prediction? Read up...
throw new IIOException("ZIP compression not supported yet");
default:
throw new IIOException("Unknown compression type: " + compression);
throw new IIOException(
String.format(
"Unknown PSD compression: %d. Expected 0 (none), 1 (RLE), 2 (ZIP) or 3 (ZIP w/prediction).",
compression
)
);
}
// What we read here is the "composite layer" of the PSD file
@ -532,6 +537,7 @@ public class PSDImageReader extends ImageReaderBase {
final byte[] pRow,
final Rectangle pSource, final Rectangle pDest, final int pXSub, final int pYSub,
final int[] pRowOffsets, boolean pRLECompressed) throws IOException {
// NOTE: 1 bit channels only occurs once
final int destWidth = (pDest.width + 7) / 8;
@ -878,7 +884,7 @@ public class PSDImageReader extends ImageReaderBase {
@Override
public BufferedImage readThumbnail(int pImageIndex, int pThumbnailIndex) throws IOException {
// TODO: Thumbnail listeners...
// TODO: Thumbnail progress listeners...
PSDThumbnail thumbnail = getThumbnailResource(pImageIndex, pThumbnailIndex);
// TODO: Defer decoding