JPEG Exif/thumbnail refactoring

This commit is contained in:
Harald Kuhr
2021-02-26 17:13:08 +01:00
parent 97a8806bfb
commit 85fb9e6af3
20 changed files with 728 additions and 784 deletions
@@ -39,6 +39,7 @@ import java.io.IOException;
import java.net.URL;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
/**
* AbstractThumbnailReaderTest
@@ -52,9 +53,9 @@ public abstract class AbstractThumbnailReaderTest {
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
}
protected abstract ThumbnailReader createReader(
ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream
) throws IOException;
protected final JPEGSegmentWarningListener listener = mock(JPEGSegmentWarningListener.class);
protected abstract ThumbnailReader createReader(ImageInputStream stream) throws IOException;
protected final ImageInputStream createStream(final String name) throws IOException {
URL resource = getClass().getResource(name);
@@ -35,18 +35,19 @@ import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
import org.junit.Test;
import org.mockito.InOrder;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
/**
* EXIFThumbnailReaderTest
@@ -57,31 +58,28 @@ import static org.mockito.Mockito.*;
*/
public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
private final ImageReader thumbnailReader = ImageIO.getImageReadersByFormatName("jpeg").next();
@Override
protected EXIFThumbnailReader createReader(final ThumbnailReadProgressListener progressListener, final int imageIndex, final int thumbnailIndex, final ImageInputStream stream) throws IOException {
protected ThumbnailReader createReader(final ImageInputStream stream) throws IOException {
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP1, "Exif");
stream.close();
assertNotNull(segments);
assertFalse(segments.isEmpty());
TIFFReader reader = new TIFFReader();
InputStream data = segments.get(0).data();
if (data.read() < 0) {
throw new AssertionError("EOF!");
}
JPEGSegment exifSegment = segments.get(0);
InputStream data = exifSegment.segmentData();
byte[] exifData = new byte[exifSegment.segmentLength() - 2];
new DataInputStream(data).readFully(exifData);
ImageInputStream exifStream = ImageIO.createImageInputStream(data);
CompoundDirectory ifds = (CompoundDirectory) reader.read(exifStream);
assertEquals(2, ifds.directoryCount());
return new EXIFThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("JPEG").next(), imageIndex, thumbnailIndex, ifds.getDirectory(1), exifStream);
EXIF exif = new EXIF(exifData);
return EXIFThumbnail.from(exif, (CompoundDirectory) new TIFFReader().read(exif.exifData()), thumbnailReader, listener);
}
@Test
public void testReadJPEG() throws IOException {
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"));
ThumbnailReader reader = createReader(createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg"));
assertEquals(114, reader.getWidth());
assertEquals(160, reader.getHeight());
@@ -94,7 +92,7 @@ public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
@Test
public void testReadRaw() throws IOException {
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg"));
ThumbnailReader reader = createReader(createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg"));
assertEquals(80, reader.getWidth());
assertEquals(60, reader.getHeight());
@@ -104,28 +102,4 @@ public class EXIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertEquals(80, thumbnail.getWidth());
assertEquals(60, thumbnail.getHeight());
}
@Test
public void testProgressListenerJPEG() throws IOException {
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
createReader(listener, 42, 43, createStream("/jpeg/cmyk-sample-multiple-chunk-icc.jpg")).read();
InOrder order = inOrder(listener);
order.verify(listener).thumbnailStarted(42, 43);
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
order.verify(listener).thumbnailComplete();
}
@Test
public void testProgressListenerRaw() throws IOException {
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
createReader(listener, 0, 99, createStream("/jpeg/exif-rgb-thumbnail-sony-d700.jpg")).read();
InOrder order = inOrder(listener);
order.verify(listener).thumbnailStarted(0, 99);
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
order.verify(listener).thumbnailComplete();
}
}
@@ -33,8 +33,8 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
import org.junit.Test;
import org.mockito.InOrder;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
@@ -53,8 +53,9 @@ import static org.mockito.Mockito.*;
* @version $Id: JFIFThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
*/
public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
@Override
protected JFIFThumbnailReader createReader(ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream) throws IOException {
protected ThumbnailReader createReader(ImageInputStream stream) throws IOException {
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFIF");
stream.close();
@@ -62,12 +63,54 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertFalse(segments.isEmpty());
JPEGSegment segment = segments.get(0);
return new JFIFThumbnailReader(progressListener, imageIndex, thumbnailIndex, JFIF.read(new DataInputStream(segment.segmentData()), segment.segmentLength()));
return JFIFThumbnail.from(JFIF.read(new DataInputStream(segment.segmentData()), segment.segmentLength()), listener);
}
@Test
public void testFromNull() {
assertNull(JFIFThumbnail.from(null, listener));
verify(listener, never()).warningOccurred(anyString());
}
@Test
public void testFromNullThumbnail() {
assertNull(JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 0, 0, null), listener));
verify(listener, never()).warningOccurred(anyString());
}
@Test
public void testFromEmpty() {
assertNull(JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 0, 0, new byte[0]), listener));
verify(listener, never()).warningOccurred(anyString());
}
@Test
public void testFromTruncated() {
assertNull(JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 255, 170, new byte[99]), listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromValid() throws IOException {
ThumbnailReader reader = JFIFThumbnail.from(new JFIF(1, 1, 0, 1, 1, 30, 20, new byte[30 * 20 * 3]), listener);
assertNotNull(reader);
verify(listener, never()).warningOccurred(anyString());
// Sanity check below
assertEquals(30, reader.getWidth());
assertEquals(20, reader.getHeight());
assertNotNull(reader.read());
}
@Test
public void testReadRaw() throws IOException {
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg"));
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg"));
assertEquals(131, reader.getWidth());
assertEquals(122, reader.getHeight());
@@ -80,7 +123,7 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
@Test
public void testReadNonSpecGray() throws IOException {
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-grayscale-thumbnail.jpg"));
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-grayscale-thumbnail.jpg"));
assertEquals(127, reader.getWidth());
assertEquals(76, reader.getHeight());
@@ -91,16 +134,4 @@ public class JFIFThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertEquals(127, thumbnail.getWidth());
assertEquals(76, thumbnail.getHeight());
}
@Test
public void testProgressListenerRaw() throws IOException {
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
createReader(listener, 0, 99, createStream("/jpeg/jfif-jfif-and-exif-thumbnail-sharpshot-iphone.jpg")).read();
InOrder order = inOrder(listener);
order.verify(listener).thumbnailStarted(0, 99);
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
order.verify(listener).thumbnailComplete();
}
}
@@ -33,10 +33,12 @@ package com.twelvemonkeys.imageio.plugins.jpeg;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEG;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegment;
import com.twelvemonkeys.imageio.metadata.jpeg.JPEGSegmentUtil;
import org.junit.After;
import org.junit.Test;
import org.mockito.InOrder;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.image.BufferedImage;
import java.io.DataInputStream;
@@ -44,6 +46,7 @@ import java.io.IOException;
import java.util.List;
import static org.junit.Assert.*;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.*;
/**
@@ -54,8 +57,10 @@ import static org.mockito.Mockito.*;
* @version $Id: JFXXThumbnailReaderTest.java,v 1.0 04.05.12 15:56 haraldk Exp$
*/
public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
private final ImageReader thumbnailReader = ImageIO.getImageReadersByFormatName("jpeg").next();
@Override
protected JFXXThumbnailReader createReader(ThumbnailReadProgressListener progressListener, int imageIndex, int thumbnailIndex, ImageInputStream stream) throws IOException {
protected ThumbnailReader createReader(ImageInputStream stream) throws IOException {
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(stream, JPEG.APP0, "JFXX");
stream.close();
@@ -63,12 +68,81 @@ public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
assertFalse(segments.isEmpty());
JPEGSegment jfxx = segments.get(0);
return new JFXXThumbnailReader(progressListener, ImageIO.getImageReadersByFormatName("jpeg").next(), imageIndex, thumbnailIndex, JFXX.read(new DataInputStream(jfxx.segmentData()), jfxx.length()));
return JFXXThumbnail.from(JFXX.read(new DataInputStream(jfxx.segmentData()), jfxx.length()), thumbnailReader, listener);
}
@After
public void tearDown() {
thumbnailReader.dispose();
}
@Test
public void testFromNull() {
assertNull(JFXXThumbnail.from(null, thumbnailReader, listener));
verify(listener, never()).warningOccurred(anyString());
}
@Test
public void testFromNullThumbnail() {
assertNull(JFXXThumbnail.from(new JFXX(JFXX.JPEG, null), thumbnailReader, listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromEmpty() {
assertNull(JFXXThumbnail.from(new JFXX(JFXX.JPEG, new byte[0]), thumbnailReader, listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromTruncatedJPEG() {
assertNull(JFXXThumbnail.from(new JFXX(JFXX.JPEG, new byte[99]), thumbnailReader, listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromTruncatedRGB() {
byte[] thumbnail = new byte[765];
thumbnail[0] = (byte) 160;
thumbnail[1] = 90;
assertNull(JFXXThumbnail.from(new JFXX(JFXX.RGB, thumbnail), thumbnailReader, listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromTruncatedIndexed() {
byte[] thumbnail = new byte[365];
thumbnail[0] = (byte) 160;
thumbnail[1] = 90;
assertNull(JFXXThumbnail.from(new JFXX(JFXX.INDEXED, thumbnail), thumbnailReader, listener));
verify(listener, only()).warningOccurred(anyString());
}
@Test
public void testFromValid() throws IOException {
byte[] thumbnail = new byte[14];
thumbnail[0] = 2;
thumbnail[1] = 2;
ThumbnailReader reader = JFXXThumbnail.from(new JFXX(JFXX.RGB, thumbnail), thumbnailReader, listener);
assertNotNull(reader);
verify(listener, never()).warningOccurred(anyString());
// Sanity check below
assertEquals(2, reader.getWidth());
assertEquals(2, reader.getHeight());
assertNotNull(reader.read());
}
@Test
public void testReadJPEG() throws IOException {
ThumbnailReader reader = createReader(mock(ThumbnailReadProgressListener.class), 0, 0, createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"));
ThumbnailReader reader = createReader(createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg"));
assertEquals(80, reader.getWidth());
assertEquals(60, reader.getHeight());
@@ -81,16 +155,4 @@ public class JFXXThumbnailReaderTest extends AbstractThumbnailReaderTest {
// TODO: Test JFXX indexed thumbnail
// TODO: Test JFXX RGB thumbnail
@Test
public void testProgressListenerRaw() throws IOException {
ThumbnailReadProgressListener listener = mock(ThumbnailReadProgressListener.class);
createReader(listener, 0, 99, createStream("/jpeg/jfif-jfxx-thumbnail-olympus-d320l.jpg")).read();
InOrder order = inOrder(listener);
order.verify(listener).thumbnailStarted(0, 99);
order.verify(listener, atLeastOnce()).thumbnailProgress(100f);
order.verify(listener).thumbnailComplete();
}
}