ImageReaderAbstractTest.java
/*
* Copyright (c) 2008, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.util;
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
import com.twelvemonkeys.lang.Validate;
import org.junit.jupiter.api.Disabled;
import org.mockito.InOrder;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.event.IIOReadProgressListener;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.IIORegistry;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import static java.lang.Math.min;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* ImageReaderAbstractTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: ImageReaderAbstractTest.java,v 1.0 Apr 1, 2008 10:36:46 PM haraldk Exp$
*/
public abstract class ImageReaderAbstractTest<T extends ImageReader> {
// TODO: Should we really test if the provider is installed?
// - Pro: Tests the META-INF/services config
// - Con: Not all providers should be installed at runtime...
// TODO: Create own subclass for testing the Spis?
static {
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
ImageIO.setUseCache(false);
}
@SuppressWarnings("unchecked")
private final Class<T> readerClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
protected final ImageReaderSpi provider = createProvider();
protected abstract ImageReaderSpi createProvider();
protected final T createReader() throws IOException {
return readerClass.cast(provider.createReaderInstance(null));
}
protected abstract List<TestData> getTestData();
protected abstract List<String> getFormatNames();
protected abstract List<String> getSuffixes();
protected abstract List<String> getMIMETypes();
protected static void failBecause(String message, Throwable exception) {
throw new AssertionError(message, exception);
}
protected void assertProviderInstalledForName(final String pFormat, final Class<? extends ImageReader> pReaderClass) {
assertProviderInstalled0(pFormat.toUpperCase(), pReaderClass, ImageIO.getImageReadersByFormatName(pFormat.toUpperCase()));
assertProviderInstalled0(pFormat.toLowerCase(), pReaderClass, ImageIO.getImageReadersByFormatName(pFormat.toLowerCase()));
}
protected void assertProviderInstalledForMIMEType(final String pType, final Class<? extends ImageReader> pReaderClass) {
assertProviderInstalled0(pType, pReaderClass, ImageIO.getImageReadersByMIMEType(pType));
}
protected void assertProviderInstalledForSuffix(final String pType, final Class<? extends ImageReader> pReaderClass) {
assertProviderInstalled0(pType, pReaderClass, ImageIO.getImageReadersBySuffix(pType));
}
private void assertProviderInstalled0(final String pFormat, final Class<? extends ImageReader> pReaderClass, final Iterator<ImageReader> pReaders) {
boolean found = false;
while (pReaders.hasNext()) {
ImageReader reader = pReaders.next();
if (reader.getClass() == pReaderClass && isOurProvider(reader.getOriginatingProvider())) {
found = true;
}
}
assertTrue(found, String.format("%s not provided by %s for '%s'", pReaderClass.getSimpleName(), provider.getClass().getSimpleName(), pFormat));
}
private boolean isOurProvider(final ImageReaderSpi spi) {
return provider.getClass().isInstance(spi);
}
@Test
public void testProviderInstalledForNames() {
for (String name : getFormatNames()) {
assertProviderInstalledForName(name, readerClass);
}
}
@Test
public void testProviderInstalledForSuffixes() {
for (String suffix : getSuffixes()) {
assertProviderInstalledForSuffix(suffix, readerClass);
}
}
@Test
public void testProviderInstalledForMIMETypes() {
for (String type : getMIMETypes()) {
assertProviderInstalledForMIMEType(type, readerClass);
}
}
@Test
public void testProviderCanRead() throws IOException {
List<TestData> testData = getTestData();
for (TestData data : testData) {
ImageInputStream stream = data.getInputStream();
assertNotNull(stream);
assertTrue(provider.canDecodeInput(stream), "Provider is expected to be able to decode data: " + data);
}
}
@Test
public void testProviderCanReadNull() {
boolean canRead = false;
try {
canRead = provider.canDecodeInput(null);
}
catch (IllegalArgumentException ignore) {
}
catch (RuntimeException e) {
failBecause("RuntimeException other than IllegalArgumentException thrown", e);
}
catch (IOException e) {
failBecause("Could not test data for read", e);
}
assertFalse(canRead, "ImageReader can read null input");
}
@Test
public void testSetInput() throws IOException {
// Should just pass with no exceptions
ImageReader reader = createReader();
assertNotNull(reader);
for (TestData data : getTestData()) {
reader.setInput(data.getInputStream());
}
reader.dispose();
}
@Test
public void testSetInputNull() throws IOException {
// Should just pass with no exceptions
ImageReader reader = createReader();
assertNotNull(reader);
reader.setInput(null);
reader.dispose();
}
@Test
public void testRead() throws IOException {
ImageReader reader = createReader();
for (TestData data : getTestData()) {
reader.setInput(data.getInputStream());
for (int i = 0; i < data.getImageCount(); i++) {
BufferedImage image = null;
try {
image = reader.read(i);
}
catch (Exception e) {
e.printStackTrace();
failBecause(String.format("Image %s index %s could not be read: %s", data.getInput(), i, e), e);
}
assertNotNull(image, String.format("Image %s index %s was null!", data.getInput(), i));
assertEquals(
data.getDimension(i).width,
image.getWidth(),
String.format("Image %s index %s has wrong width: %s", data.getInput(), i, image.getWidth())
);
assertEquals(
data.getDimension(i).height, image.getHeight(),
String.format("Image %s index %s has wrong height: %s", data.getInput(), i, image.getHeight())
);
}
}
reader.dispose();
}
@Test
public void testReadIndexNegative() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
try {
image = reader.read(-1);
fail("Read image with illegal index");
}
catch (IndexOutOfBoundsException ignore) {
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNull(image);
reader.dispose();
}
@Test
public void testReadIndexOutOfBounds() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
try {
image = reader.read(Integer.MAX_VALUE); // TODO: This might actually not throw exception...
fail("Read image with index out of bounds");
}
catch (IndexOutOfBoundsException ignore) {
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNull(image);
reader.dispose();
}
@Test
public void testReRead() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream(), false); // Explicitly allow repositioning, even though it's the default
BufferedImage first = reader.read(0);
assertNotNull(first);
BufferedImage second = reader.read(0);
assertNotNull(second);
// TODO: These images should be exactly the same, but there's no equals for images
assertEquals(first.getType(), second.getType());
assertEquals(first.getWidth(), second.getWidth());
assertEquals(first.getHeight(), second.getHeight());
reader.dispose();
}
@Test
public void testReadNoInput() throws IOException {
ImageReader reader = createReader();
// Do not set input
assertThrows(IllegalStateException.class, () -> {
reader.read(0);
});
}
@Test
public void testReadIndexNegativeWithParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
try {
assertThrows(IndexOutOfBoundsException.class, () -> {
reader.read(-1, reader.getDefaultReadParam());
});
}
finally {
reader.dispose();
}
}
@Test
public void testReadIndexOutOfBoundsWithParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
try {
assertThrows(IndexOutOfBoundsException.class, () -> {
reader.read(Short.MAX_VALUE, reader.getDefaultReadParam());
});
}
finally {
reader.dispose();
}
}
@Test
public void testReadNoInputWithParam() throws IOException {
ImageReader reader = createReader();
// Do not set input
try {
assertThrows(IllegalStateException.class, () -> {
reader.read(0);
});
}
finally {
reader.dispose();
}
}
@Test
public void testReadWithNewParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
try {
image = reader.read(0, new ImageReadParam());
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(data.getDimension(0).width, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(data.getDimension(0).height, image.getHeight(), "Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadWithDefaultParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
try {
image = reader.read(0, reader.getDefaultReadParam());
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(data.getDimension(0).width, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(data.getDimension(0).height, image.getHeight(), "Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadWithNullParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage image = null;
try {
image = reader.read(0, null);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(data.getDimension(0).width, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(data.getDimension(0).height, image.getHeight(), "Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadWithSizeParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
if (param.canSetSourceRenderSize()) {
param.setSourceRenderSize(new Dimension(10, 10));
BufferedImage image = null;
try {
image = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(10, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(10, image.getHeight(), "Read image has wrong height: " + image.getHeight());
}
reader.dispose();
}
@Test
public void testReadWithSubsampleParamDimensions() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceSubsampling(5, 5, 0, 0);
BufferedImage image = null;
try {
image = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals((data.getDimension(0).width + 4) / 5, image.getWidth(), "Read image has wrong width: ");
assertEquals((data.getDimension(0).height + 4) / 5, image.getHeight(), "Read image has wrong height: ");
reader.dispose();
}
@Test
public void testReadWithSubsampleParamPixels() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
BufferedImage image = null;
BufferedImage subsampled = null;
try {
image = reader.read(0, param);
param.setSourceSubsampling(2, 2, 0, 0);
subsampled = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertSubsampledImageDataEquals("Subsampled image data does not match expected", image, subsampled, param);
reader.dispose();
}
// TODO: Subsample all test data
// TODO: Subsample with varying ratios and offsets
@SuppressWarnings("SameParameterValue")
protected final void assertSubsampledImageDataEquals(String message, BufferedImage expected, BufferedImage actual, ImageReadParam param) throws IOException {
assertNotNull(expected, "Expected image was null");
assertNotNull(actual, "Actual image was null!");
if (expected == actual) {
return;
}
int xOff = param.getSubsamplingXOffset();
int yOff = param.getSubsamplingYOffset();
int xSub = param.getSourceXSubsampling();
int ySub = param.getSourceYSubsampling();
assertEquals((expected.getWidth() - xOff + xSub - 1) / xSub, actual.getWidth(), "Subsampled image has wrong width: ");
assertEquals((expected.getHeight() - yOff + ySub - 1) / ySub, actual.getHeight(), "Subsampled image has wrong height: ");
assertEquals(expected.getType(), actual.getType(), "Subsampled has different type");
for (int y = 0; y < actual.getHeight(); y++) {
for (int x = 0; x < actual.getWidth(); x++) {
int expectedRGB = expected.getRGB(xOff + x * xSub, yOff + y * ySub);
int actualRGB = actual.getRGB(x, y);
try {
assertEquals((expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 5);
assertEquals((expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5);
assertEquals((expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5);
assertEquals(expectedRGB & 0xff, actualRGB & 0xff, 5);
}
catch (AssertionError e) {
File tempExpected = File.createTempFile("junit-expected-", ".png");
System.err.println("tempExpected.getAbsolutePath(): " + tempExpected.getAbsolutePath());
ImageIO.write(expected, "PNG", tempExpected);
File tempActual = File.createTempFile("junit-actual-", ".png");
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
ImageIO.write(actual, "PNG", tempActual);
assertEquals(String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB), String.format("%s ARGB at (%d, %d)", message, x, y));
}
}
}
}
public static void assertImageDataEquals(String message, BufferedImage expected, BufferedImage actual) {
assertNotNull(expected, "Expected image was null");
assertNotNull(actual, "Actual image was null!");
if (expected == actual) {
return;
}
for (int y = 0; y < expected.getHeight(); y++) {
for (int x = 0; x < expected.getWidth(); x++) {
int expectedRGB = expected.getRGB(x, y);
int actualRGB = actual.getRGB(x, y);
assertEquals((expectedRGB >> 24) & 0xff, (actualRGB >> 24) & 0xff, 5, String.format("%s alpha at (%d, %d)", message, x, y));
assertEquals((expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, 5, String.format("%s red at (%d, %d)", message, x, y));
assertEquals((expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, 5, String.format("%s green at (%d, %d)", message, x, y));
assertEquals(expectedRGB & 0xff, actualRGB & 0xff, 5, String.format("%s blue at (%d, %d)", message, x, y));
}
}
}
@Test
public void testReadWithSourceRegionParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(0, 0, 10, 10));
BufferedImage image = null;
try {
image = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(10, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(10, image.getHeight(), "Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadWithSourceRegionParamEqualImage() throws IOException {
// Default invocation
assertReadWithSourceRegionParamEqualImage(new Rectangle(3, 3, 9, 9), getTestData().get(0), 0);
}
protected void assertReadWithSourceRegionParamEqualImage(final Rectangle r, final TestData data, @SuppressWarnings("SameParameterValue") final int imageIndex) throws IOException {
ImageReader reader = createReader();
try (ImageInputStream inputStream = data.getInputStream()) {
reader.setInput(inputStream);
ImageReadParam param = reader.getDefaultReadParam();
// Read full image and get sub image for comparison
BufferedImage original = reader.read(imageIndex, param);
final BufferedImage roi = original.getSubimage(r.x, r.y, r.width, r.height);
param.setSourceRegion(r);
final BufferedImage image = reader.read(imageIndex, param);
assertNotNull(image, "Image was null!");
assertEquals(r.width, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(r.height, image.getHeight(), "Read image has wrong height: " + image.getHeight());
try {
assertImageDataEquals("Images differ", roi, image);
}
catch (AssertionError e) {
File tempExpected = File.createTempFile("junit-expected-", ".png");
System.err.println("tempExpected.getAbsolutePath(): " + tempExpected.getAbsolutePath());
Graphics2D graphics = original.createGraphics();
try {
graphics.setColor(Color.RED);
graphics.draw(r);
}
finally {
graphics.dispose();
}
ImageIO.write(original, "PNG", tempExpected);
File tempActual = File.createTempFile("junit-actual-", ".png");
System.err.println("tempActual.getAbsolutePath(): " + tempActual.getAbsolutePath());
ImageIO.write(image, "PNG", tempActual);
throw e;
}
}
finally {
reader.dispose();
}
}
@Test
public void testReadWithSizeAndSourceRegionParam() throws IOException {
// TODO: Is this test correct???
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
if (param.canSetSourceRenderSize()) {
Dimension size = data.getDimension(0);
size = new Dimension(size.width * 2, size.height * 2);
param.setSourceRenderSize(size);
param.setSourceRegion(new Rectangle(0, 0, 10, 10));
BufferedImage image = null;
try {
image = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(10, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(10, image.getHeight(), "Read image has wrong height: " + image.getHeight());
}
reader.dispose();
}
@Test
public void testReadWithSubsampleAndSourceRegionParam() throws IOException {
// NOTE: The "standard" (com.sun.imageio.plugin.*) ImageReaders pass
// this test, so the test should be correct...
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceSubsampling(2, 2, 0, 0);
param.setSourceRegion(new Rectangle(0, 0, 10, 10));
BufferedImage image = null;
try {
image = reader.read(0, param);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(5, image.getWidth(), "Read image has wrong width: " + image.getWidth());
assertEquals(5, image.getHeight(), "Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadAsRenderedImageIndexNegative() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
RenderedImage image = null;
try {
image = reader.readAsRenderedImage(-1, reader.getDefaultReadParam());
fail("Read image with illegal index");
}
catch (IndexOutOfBoundsException expected) {
// Ignore
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNull(image);
reader.dispose();
}
@Test
public void testReadAsRenderedImageIndexOutOfBounds() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
RenderedImage image = null;
try {
image = reader.readAsRenderedImage(reader.getNumImages(true), reader.getDefaultReadParam());
fail("Read image with index out of bounds");
}
catch (IndexOutOfBoundsException expected) {
// Ignore
}
catch (IIOException e) {
// Allow this to bubble up, due to a bug in the Sun JPEGImageReader
throw e;
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNull(image);
reader.dispose();
}
@Test
public void testReadAsRenderedImageNoInput() throws IOException {
ImageReader reader = createReader();
// Do not set input
RenderedImage image = null;
try {
image = reader.readAsRenderedImage(0, reader.getDefaultReadParam());
fail("Read image with no input");
}
catch (IllegalStateException expected) {
// Ignore
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNull(image);
reader.dispose();
}
@Test
public void testReadAsRenderedImage() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
RenderedImage image = null;
try {
image = reader.readAsRenderedImage(0, null);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals( data.getDimension(0).width, image.getWidth(),
"Read image has wrong width: " + image.getWidth());
assertEquals( data.getDimension(0).height, image.getHeight(),
"Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testReadAsRenderedImageWithDefaultParam() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
RenderedImage image = null;
try {
image = reader.readAsRenderedImage(0, reader.getDefaultReadParam());
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
assertNotNull(image, "Image was null!");
assertEquals(data.getDimension(0).width, image.getWidth(),
"Read image has wrong width: " + image.getWidth());
assertEquals(data.getDimension(0).height, image.getHeight(),
"Read image has wrong height: " + image.getHeight());
reader.dispose();
}
@Test
public void testGetDefaultReadParam() throws IOException {
ImageReader reader = createReader();
ImageReadParam param = reader.getDefaultReadParam();
assertNotNull(param);
reader.dispose();
}
@Test
public void testGetFormatName() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
String name = null;
try {
name = reader.getFormatName();
}
catch (IOException e) {
fail(e.getMessage());
}
assertNotNull(name);
reader.dispose();
}
@Test
public void testGetMinIndex() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
int num = 0;
try {
num = reader.getMinIndex();
}
catch (IllegalStateException ignore) {
}
assertEquals(0, num);
reader.dispose();
}
@Test
public void testGetMinIndexNoInput() throws IOException {
ImageReader reader = createReader();
int num = 0;
try {
num = reader.getMinIndex();
}
catch (IllegalStateException ignore) {
}
assertEquals(0, num);
reader.dispose();
}
@Test
public void testGetNumImages() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
int num = -1;
try {
num = reader.getNumImages(false);
}
catch (IOException e) {
fail(e.getMessage());
}
assertTrue(num == -1 || num > 0);
try {
num = reader.getNumImages(true);
}
catch (IOException e) {
fail(e.getMessage());
}
assertTrue(num > 0);
assertTrue(data.getImageCount() <= num);
if (data.getImageCount() != num) {
System.err.println("WARNING: Image count not equal to test data count");
}
reader.dispose();
}
@Test
public void testGetNumImagesNoInput() throws IOException {
ImageReader reader = createReader();
int num = -1;
try {
num = reader.getNumImages(false);
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail(e.getMessage());
}
assertEquals(-1, num);
try {
num = reader.getNumImages(true);
fail("Should throw IllegalStateException");
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail(e.getMessage());
}
assertEquals(-1, num);
reader.dispose();
}
@Test
public void testGetWidth() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
int width = 0;
try {
width = reader.getWidth(0);
}
catch (IOException e) {
fail("Could not read image width: " + e);
}
assertEquals(data.getDimension(0).width, width, "Wrong width reported");
reader.dispose();
}
@Test
public void testGetWidthIndexOutOfBounds() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
//int width = 0;
try {
/*width = */reader.getWidth(-1);
// NOTE: Some readers (like the com.sun.imageio stuff) ignores
// index in getWidth/getHeight for formats with only one image...
//assertEquals("Wrong width reported", data.getDimension().width, width);
}
catch (IndexOutOfBoundsException ignore) {
}
catch (IOException e) {
fail("Could not read image aspect ratio: " + e);
}
reader.dispose();
}
@Test
public void testGetWidthNoInput() throws IOException {
ImageReader reader = createReader();
int width = 0;
try {
width = reader.getWidth(0);
fail("Width read without input");
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail("Could not read image width: " + e);
}
assertEquals(0, width, "Wrong width reported");
reader.dispose();
}
@Test
public void testGetHeight() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
int height = 0;
try {
height = reader.getHeight(0);
}
catch (IOException e) {
fail("Could not read image height: " + e);
}
assertEquals(data.getDimension(0).height, height, "Wrong height reported");
reader.dispose();
}
@Test
public void testGetHeightNoInput() throws IOException {
ImageReader reader = createReader();
int height = 0;
try {
height = reader.getHeight(0);
fail("height read without input");
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail("Could not read image height: " + e);
}
assertEquals(0, height, "Wrong height reported");
reader.dispose();
}
@Test
public void testGetHeightIndexOutOfBounds() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
//int height = 0;
try {
/*height =*/ reader.getHeight(-1);
// NOTE: Some readers (like the com.sun.imageio stuff) ignores
// index in getWidth/getHeight for formats with only one image...
//assertEquals("Wrong height reported", data.getDimension().height, height);
}
catch (IndexOutOfBoundsException ignore) {
}
catch (IOException e) {
fail("Could not read image height: " + e);
}
reader.dispose();
}
@Test
public void testGetAspectRatio() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
float aspectRatio = 0f;
try {
aspectRatio = reader.getAspectRatio(0);
}
catch (IOException e) {
fail("Could not read image aspect ratio" + e);
}
Dimension d = data.getDimension(0);
assertEquals(d.getWidth() / d.getHeight(), aspectRatio, 0.001, "Wrong aspect aspect ratio");
reader.dispose();
}
@Test
public void testGetAspectRatioNoInput() throws IOException {
ImageReader reader = createReader();
float aspectRatio = 0f;
try {
aspectRatio = reader.getAspectRatio(0);
fail("aspect read without input");
}
catch (IllegalStateException ignore) {
}
catch (IOException e) {
fail("Could not read image aspect ratio" + e);
}
assertEquals(0f, aspectRatio, 0f, "Wrong aspect aspect ratio");
reader.dispose();
}
@Test
public void testGetAspectRatioIndexOutOfBounds() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
//float aspectRatio = 0f;
try {
// NOTE: Some readers (like the com.sun.imageio stuff) ignores
// index in getWidth/getHeight for formats with only one image...
/*aspectRatio =*/ reader.getAspectRatio(-1);
//assertEquals("Wrong aspect ratio", data.getDimension().width / (float) data.getDimension().height, aspectRatio, 0f);
}
catch (IndexOutOfBoundsException ignore) {
}
catch (IOException e) {
fail("Could not read image aspect ratio" + e);
}
reader.dispose();
}
@Test
public void testDisposeBeforeRead() throws IOException {
ImageReader reader = createReader();
reader.dispose(); // Just pass with no exceptions
}
@Test
public void testDisposeAfterRead() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
reader.dispose(); // Just pass with no exceptions
}
@Test
public void testAddIIOReadProgressListener() throws IOException {
ImageReader reader = createReader();
reader.addIIOReadProgressListener(mock(IIOReadProgressListener.class));
reader.dispose();
}
@Test
public void testAddIIOReadProgressListenerNull() throws IOException {
ImageReader reader = createReader();
reader.addIIOReadProgressListener(null);
reader.dispose();
}
@Test
public void testAddIIOReadProgressListenerCallbacks() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// At least imageStarted and imageComplete, plus any number of imageProgress
InOrder ordered = inOrder(listener);
ordered.verify(listener).imageStarted(reader, 0);
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
ordered.verify(listener).imageComplete(reader);
reader.dispose();
}
@Test
public void testMultipleAddIIOReadProgressListenerCallbacks() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
IIOReadProgressListener listenerToo = mock(IIOReadProgressListener.class);
IIOReadProgressListener listenerThree = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
reader.addIIOReadProgressListener(listenerToo);
reader.addIIOReadProgressListener(listenerThree);
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// At least imageStarted and imageComplete, plus any number of imageProgress
InOrder ordered = inOrder(listener, listenerToo, listenerThree);
ordered.verify(listener).imageStarted(reader, 0);
ordered.verify(listenerToo).imageStarted(reader, 0);
ordered.verify(listenerThree).imageStarted(reader, 0);
ordered.verify(listener, atLeastOnce()).imageProgress(eq(reader), anyFloat());
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyFloat());
ordered.verify(listenerThree, atLeastOnce()).imageProgress(eq(reader), anyFloat());
ordered.verify(listener).imageComplete(reader);
ordered.verify(listenerToo).imageComplete(reader);
ordered.verify(listenerThree).imageComplete(reader);
reader.dispose();
}
@Test
public void testRemoveIIOReadProgressListenerNull() throws IOException {
ImageReader reader = createReader();
reader.removeIIOReadProgressListener(null);
reader.dispose();
}
@Test
public void testRemoveIIOReadProgressListenerNone() throws IOException {
ImageReader reader = createReader();
reader.removeIIOReadProgressListener(mock(IIOReadProgressListener.class));
reader.dispose();
}
@Test
public void testRemoveIIOReadProgressListener() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
reader.removeIIOReadProgressListener(listener);
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// Should not have called any methods...
verifyNoInteractions(listener);
reader.dispose();
}
@Test
public void testRemoveIIOReadProgressListenerMultiple() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class, "Listener1");
reader.addIIOReadProgressListener(listener);
IIOReadProgressListener listenerToo = mock(IIOReadProgressListener.class, "Listener2");
reader.addIIOReadProgressListener(listenerToo);
reader.removeIIOReadProgressListener(listener);
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// Should not have called any methods on listener1...
verifyNoInteractions(listener);
InOrder ordered = inOrder(listenerToo);
ordered.verify(listenerToo).imageStarted(reader, 0);
ordered.verify(listenerToo, atLeastOnce()).imageProgress(eq(reader), anyFloat());
ordered.verify(listenerToo).imageComplete(reader);
reader.dispose();
}
@Test
public void testRemoveAllIIOReadProgressListeners() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
reader.removeAllIIOReadProgressListeners();
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// Should not have called any methods...
verifyNoInteractions(listener);
reader.dispose();
}
@Test
public void testRemoveAllIIOReadProgressListenersMultiple() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
IIOReadProgressListener listenerToo = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listenerToo);
reader.removeAllIIOReadProgressListeners();
try {
reader.read(0);
}
catch (IOException e) {
fail("Could not read image");
}
// Should not have called any methods...
verifyNoInteractions(listener);
verifyNoInteractions(listenerToo);
reader.dispose();
}
@Test
public void testAbort() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
IIOReadProgressListener listener = mock(IIOReadProgressListener.class, "Progress1");
reader.addIIOReadProgressListener(listener);
IIOReadProgressListener listenerToo = mock(IIOReadProgressListener.class, "Progress2");
reader.addIIOReadProgressListener(listenerToo);
// Create a listener that just makes the reader abort immediately...
IIOReadProgressListener abortingListener = mock(IIOReadProgressListener.class, "Aborter");
Answer<Void> abort = new Answer<Void>() {
public Void answer(InvocationOnMock invocation) {
reader.abort();
return null;
}
};
doAnswer(abort).when(abortingListener).imageStarted(any(ImageReader.class), anyInt());
doAnswer(abort).when(abortingListener).imageProgress(any(ImageReader.class), anyFloat());
reader.addIIOReadProgressListener(abortingListener);
try {
reader.read(0);
}
catch (IOException e) {
failBecause("Image could not be read", e);
}
verify(listener).readAborted(reader);
verify(listenerToo).readAborted(reader);
reader.dispose();
}
@Test
public void testGetTypeSpecifiers() throws IOException {
final ImageReader reader = createReader();
for (TestData data : getTestData()) {
reader.setInput(data.getInputStream());
ImageTypeSpecifier rawType = reader.getRawImageType(0);
assertNotNull(rawType);
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
assertNotNull(types);
assertTrue(types.hasNext());
// TODO: This might fail even though the specifiers are obviously equal, if the
// color spaces they use are not the SAME instance, as ColorSpace uses identity equals
// and Interleaved ImageTypeSpecifiers are only equal if color spaces are equal...
boolean rawFound = false;
while (types.hasNext()) {
ImageTypeSpecifier type = types.next();
if (type.equals(rawType)) {
rawFound = true;
break;
}
}
assertTrue(rawFound, "ImageTypeSpecifier from getRawImageType should be in the iterator from getImageTypes");
}
reader.dispose();
}
@Test
public void testSetDestination() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
Dimension size = data.getDimension(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
while (types.hasNext()) {
ImageTypeSpecifier type = types.next();
BufferedImage destination = type.createBufferedImage(size.width, size.height);
param.setDestination(destination);
BufferedImage result = null;
try {
result = reader.read(0, param);
}
catch (Exception e) {
failBecause("Could not read " + data.getInput() + " with explicit destination " + destination, e);
}
assertSame(destination, result);
}
reader.dispose();
}
@Test
public void testSetDestinationRaw() throws IOException {
ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
ImageTypeSpecifier type = reader.getRawImageType(0);
if (type != null) {
BufferedImage destination = type.createBufferedImage(reader.getWidth(0), reader.getHeight(0));
param.setDestination(destination);
BufferedImage result = null;
try {
result = reader.read(0, param);
}
catch (Exception e) {
failBecause("Image could not be read", e);
}
assertSame(destination, result);
}
else {
System.err.println("WARNING: Test skipped due to reader.getRawImageType(0) returning null");
}
reader.dispose();
}
@Test
public void testSetDestinationIllegal() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
Dimension size = data.getDimension(0);
reader.setInput(data.getInputStream());
List<ImageTypeSpecifier> illegalTypes = createIllegalTypes(reader.getImageTypes(0));
ImageReadParam param = reader.getDefaultReadParam();
for (ImageTypeSpecifier illegalType : illegalTypes) {
BufferedImage destination = illegalType.createBufferedImage(size.width, size.height);
param.setDestination(destination);
try {
BufferedImage result = 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.
// TODO: Special case for BufferedImage type 2/3 and 6/7
System.err.println("WARNING: Reader does not throw exception with non-declared destination: " + destination);
// Test that the destination is really taken into account
assertSame(destination, result);
}
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().toLowerCase();
if (!(message.contains("destination") || message.contains("band size") || // For JDK classes
((destination.getType() == BufferedImage.TYPE_BYTE_BINARY ||
destination.getType() == BufferedImage.TYPE_BYTE_INDEXED) &&
message.contains("indexcolormodel")))) {
failBecause(
"Wrong message: " + message + " for type " + destination.getType(), expected
);
}
}
catch (IllegalArgumentException expected) {
String message = expected.getMessage().toLowerCase();
assertTrue(message.contains("dest"), "Wrong message: " + message);
}
}
reader.dispose();
}
@Test
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 | IllegalArgumentException expected) {
// TODO: This is thrown by ImageReader.getDestination. But are we happy with that?
String message = expected.getMessage().toLowerCase();
if (!(message.contains("destination") && message.contains("type")
|| message.contains("num source & dest bands differ"))) {
// Allow this to bubble up, due to a bug in the Sun PNGImageReader
throw expected;
}
}
}
reader.dispose();
}
private List<ImageTypeSpecifier> createIllegalTypes(Iterator<ImageTypeSpecifier> pValidTypes) {
List<ImageTypeSpecifier> allTypes = new ArrayList<>();
for (int i = BufferedImage.TYPE_INT_RGB; i < BufferedImage.TYPE_BYTE_INDEXED; i++) {
allTypes.add(ImageTypeSpecifier.createFromBufferedImageType(i));
}
List<ImageTypeSpecifier> illegalTypes = new ArrayList<>(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?
// TODO: Test that destination offset is used for image data, not just image dimensions...
@Test
public void testSetDestinationOffset() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
Point point = new Point(37, 42);
param.setDestinationOffset(point);
BufferedImage image = reader.read(0, param);
assertNotNull(image);
assertEquals(reader.getWidth(0) + point.x, image.getWidth());
assertEquals(reader.getHeight(0) + point.y, image.getHeight());
reader.dispose();
}
@Test
public void testSetDestinationOffsetNull() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
try {
param.setDestinationOffset(null);
fail("Null offset not allowed");
}
catch (IllegalArgumentException e) {
assertTrue(e.getMessage().toLowerCase().contains("offset"));
}
reader.dispose();
}
@Test
public void testSetDestinationType() throws IOException {
final ImageReader reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
ImageReadParam param = reader.getDefaultReadParam();
Iterator<ImageTypeSpecifier> types = reader.getImageTypes(0);
while (types.hasNext()) {
ImageTypeSpecifier type = types.next();
param.setDestinationType(type);
BufferedImage result = null;
try {
result = reader.read(0, param);
}
catch (Exception e) {
failBecause("Could not read " + data.getInput() + " with explicit destination type " + type, e);
}
assertNotNull(result);
assertEquals(type.getColorModel(), result.getColorModel());
// The following logically tests
// assertEquals(type.getSampleModel(), result.getSampleModel());
// but SampleModel does not have a proper equals method.
SampleModel expectedModel = type.getSampleModel();
SampleModel resultModel = result.getSampleModel();
assertEquals(expectedModel.getDataType(), resultModel.getDataType());
assertEquals(expectedModel.getNumBands(), resultModel.getNumBands());
assertEquals(expectedModel.getNumDataElements(), resultModel.getNumDataElements());
assertArrayEquals(expectedModel.getSampleSize(), resultModel.getSampleSize());
assertEquals(expectedModel.getTransferType(), resultModel.getTransferType());
for (int i = 0; i < expectedModel.getNumBands(); i++) {
assertEquals(expectedModel.getSampleSize(i), resultModel.getSampleSize(i));
}
}
reader.dispose();
}
@Test
public void testNotBadCaching() throws IOException {
T reader = createReader();
TestData data = getTestData().get(0);
reader.setInput(data.getInputStream());
BufferedImage one = reader.read(0);
BufferedImage two = reader.read(0);
// Test for same BufferedImage instance
assertNotSame(one, two, "Multiple reads return same (mutable) image");
// Test for same backing storage (array)
one.setRGB(0, 0, Color.BLACK.getRGB());
two.setRGB(0, 0, Color.WHITE.getRGB());
assertTrue(one.getRGB(0, 0) != two.getRGB(0, 0));
reader.dispose();
}
@Test
public void testReadThumbnails() throws IOException {
T reader = createReader();
if (reader.readerSupportsThumbnails()) {
for (TestData testData : getTestData()) {
try (ImageInputStream inputStream = testData.getInputStream()) {
reader.setInput(inputStream);
int numImages = reader.getNumImages(true);
for (int i = 0; i < numImages; i++) {
int numThumbnails = reader.getNumThumbnails(0);
for (int t = 0; t < numThumbnails; t++) {
BufferedImage thumbnail = reader.readThumbnail(0, t);
assertNotNull(thumbnail);
}
}
}
}
}
reader.dispose();
}
@Test
public void testThumbnailProgress() throws IOException {
T reader = createReader();
IIOReadProgressListener listener = mock(IIOReadProgressListener.class);
reader.addIIOReadProgressListener(listener);
if (reader.readerSupportsThumbnails()) {
for (TestData testData : getTestData()) {
try (ImageInputStream inputStream = testData.getInputStream()) {
reader.setInput(inputStream);
int numThumbnails = reader.getNumThumbnails(0);
for (int i = 0; i < numThumbnails; i++) {
reset(listener);
reader.readThumbnail(0, i);
InOrder order = inOrder(listener);
order.verify(listener).thumbnailStarted(reader, 0, i);
order.verify(listener, atLeastOnce()).thumbnailProgress(reader, 100f);
order.verify(listener).thumbnailComplete(reader);
}
}
}
}
reader.dispose();
}
@Test
public void testNotBadCachingThumbnails() throws IOException {
T reader = createReader();
if (reader.readerSupportsThumbnails()) {
for (TestData data : getTestData()) {
reader.setInput(data.getInputStream());
int images = reader.getNumImages(true);
for (int i = 0; i < images; i++) {
int thumbnails = reader.getNumThumbnails(0);
for (int j = 0; j < thumbnails; j++) {
BufferedImage one = reader.readThumbnail(i, j);
BufferedImage two = reader.readThumbnail(i, j);
assertNotSame(one, two, "Multiple reads return same (mutable) image");
Graphics2D g = one.createGraphics();
try {
g.setColor(Color.WHITE);
g.setXORMode(Color.BLACK);
g.fillRect(0, 0, one.getWidth(), one.getHeight());
}
finally {
g.dispose();
}
assertTrue(one.getRGB(0, 0) != two.getRGB(0, 0));
}
if (thumbnails > 0) {
// We've tested thumbnails, let's get out of here
return;
}
}
}
fail("No thumbnails tested for reader that supports thumbnails.");
}
reader.dispose();
}
protected List<TestData> getTestDataForAffineTransformOpCompatibility() {
// Allow subclasses to filter out test data that can't be converted to a compatible image without data loss
return getTestData();
}
@Test
public void testAffineTransformOpCompatibility() throws IOException {
// Test that the output of normal images are compatible with AffineTransformOp. Is unlikely to work on all test data
ImageReader reader = createReader();
for (TestData testData : getTestDataForAffineTransformOpCompatibility()) {
Dimension size = testData.getDimension(0);
try (ImageInputStream input = testData.getInputStream()) {
reader.setInput(input);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(new Rectangle(size.width, size.height));
BufferedImage originalImage = reader.read(0, param);
AffineTransform transform = AffineTransform.getTranslateInstance(10, 10);
AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_NEAREST_NEIGHBOR);
try {
BufferedImage resultImage = op.filter(originalImage, null); // The exception happens here
assertNotNull(resultImage);
}
catch (ImagingOpException e) {
fail(e.getMessage() + ".\n\t"
+ originalImage + "\n\t"
+ testData);
}
}
}
reader.dispose();
}
@Disabled("TODO: Implement")
@Test
public void testSetDestinationBands() {
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
}
@Disabled("TODO: Implement")
@Test
public void testSetSourceBands() {
throw new UnsupportedOperationException("Method testSetDestinationBands not implemented"); // TODO: Implement
}
@Test
public void testProviderAndMetadataFormatNamesMatch() throws IOException {
ImageReader reader = createReader();
reader.setInput(getTestData().get(0).getInputStream());
IIOMetadata imageMetadata = reader.getImageMetadata(0);
if (imageMetadata != null) {
assertEquals(provider.getNativeImageMetadataFormatName(), imageMetadata.getNativeMetadataFormatName());
}
IIOMetadata streamMetadata = reader.getStreamMetadata();
if (streamMetadata != null) {
assertEquals(provider.getNativeStreamMetadataFormatName(), streamMetadata.getNativeMetadataFormatName());
}
reader.dispose();
}
protected URL getClassLoaderResource(final String pName) {
return getClass().getResource(pName);
}
/**
* Slightly fuzzy RGB equals method. Variable tolerance.
*/
public static void assertRGBEquals(String message, int expectedRGB, int actualRGB, int tolerance) {
try {
assertEquals((expectedRGB >>> 24) & 0xff, (actualRGB >>> 24) & 0xff, 0);
assertEquals((expectedRGB >> 16) & 0xff, (actualRGB >> 16) & 0xff, tolerance);
assertEquals((expectedRGB >> 8) & 0xff, (actualRGB >> 8) & 0xff, tolerance);
assertEquals((expectedRGB ) & 0xff, (actualRGB ) & 0xff, tolerance);
}
catch (AssertionError e) {
assertEquals(String.format("#%08x", expectedRGB), String.format("#%08x", actualRGB), message);
}
}
static final protected class TestData {
private final Object input;
private final List<Dimension> sizes;
private final List<BufferedImage> images;
public TestData(final Object input, final Dimension... dimensions) {
this(input, Arrays.asList(dimensions), null);
}
public TestData(final Object input, final BufferedImage... images) {
this(input, null, Arrays.asList(images));
}
public TestData(final Object input, final List<Dimension> dimensions, final List<BufferedImage> images) {
Validate.notNull(input, "input");
Validate.isTrue(dimensions != null || images != null, "Need either dimensions or image");
List<Dimension> combinedDimensions;
if (dimensions == null) {
// Copy dimensions from images
combinedDimensions = new ArrayList<>(images.size());
for (BufferedImage image : images) {
combinedDimensions.add(new Dimension(image.getWidth(), image.getHeight()));
}
}
else {
// Validate equal dimensions
if (images != null) {
if (images.size() != dimensions.size()) {
throw new IllegalArgumentException("Dimensions and images parameter's size differs");
}
for (int i = 0; i < dimensions.size(); i++) {
if (!new Dimension(images.get(i).getWidth(), images.get(i).getHeight()).equals(dimensions.get(i))) {
throw new IllegalArgumentException("Dimensions and images parameter's dimensions differ");
}
}
}
combinedDimensions = new ArrayList<>(dimensions);
}
this.sizes = Collections.unmodifiableList(combinedDimensions);
this.images = images != null
? Collections.unmodifiableList(new ArrayList<>(images))
: Collections.<BufferedImage>emptyList();
this.input = input;
}
public Object getInput() {
return input;
}
public ImageInputStream getInputStream() {
try {
ImageInputStream stream = ImageIO.createImageInputStream(input);
assertNotNull(stream, "Could not create ImageInputStream for input: " + input);
return stream;
}
catch (IOException e) {
failBecause("Could not create ImageInputStream for input: " + input, e);
}
return null;
}
public int getImageCount() {
return sizes.size();
}
public Dimension getDimension(final int index) {
return sizes.get(index);
}
@SuppressWarnings("unused")
public BufferedImage getImage(final int index) {
return images.get(index);
}
@Override
public String toString() {
return String.format("%s: %s", getClass().getSimpleName(), input);
}
}
}