#204 TIFF metadata refactor

This commit is contained in:
Harald Kuhr
2016-12-12 22:28:22 +01:00
parent 7a0660c4d7
commit a86b76256b
37 changed files with 2471 additions and 1695 deletions
@@ -30,8 +30,8 @@ package com.twelvemonkeys.imageio.metadata.exif;
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
import com.twelvemonkeys.imageio.metadata.Directory;
import com.twelvemonkeys.imageio.metadata.Entry;
import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest;
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import org.junit.Test;
@@ -149,20 +149,6 @@ public class EXIFReaderTest extends MetadataReaderAbstractTest {
assertEquals("", directory.getEntryById(TIFF.TAG_IMAGE_DESCRIPTION).getValue());
}
@Test
public void testReadBadDataRationalZeroDenominator() throws IOException {
// This image seems to contain bad Exif. But as other tools are able to read, so should we..
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-rgb-thumbnail-bad-exif-kodak-dc210.jpg"));
stream.seek(12);
Directory directory = createReader().read(new SubImageInputStream(stream, 21674));
// Special case: Rational with zero-denominator inside EXIF data
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
Entry entry = exif.getEntryById(EXIF.TAG_COMPRESSED_BITS_PER_PIXEL);
assertNotNull(entry);
assertEquals(Rational.NaN, entry.getValue());
}
@Test
public void testReadBadDirectoryCount() throws IOException {
// This image seems to contain bad Exif. But as other tools are able to read, so should we..
@@ -29,6 +29,10 @@
package com.twelvemonkeys.imageio.metadata.exif;
import com.twelvemonkeys.imageio.metadata.*;
import com.twelvemonkeys.imageio.metadata.tiff.TIFF;
import com.twelvemonkeys.imageio.metadata.tiff.TIFFEntry;
import com.twelvemonkeys.imageio.metadata.tiff.TIFFReader;
import com.twelvemonkeys.imageio.metadata.tiff.TIFFWriter;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import com.twelvemonkeys.io.FastByteArrayOutputStream;
import org.junit.Test;
@@ -41,18 +45,16 @@ import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* EXIFWriterTest
* TIFFWriterTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: EXIFWriterTest.java,v 1.0 18.07.13 09:53 haraldk Exp$
* @version $Id: TIFFWriterTest.java,v 1.0 18.07.13 09:53 haraldk Exp$
*/
public class EXIFWriterTest extends MetadataWriterAbstractTest {
@@ -61,28 +63,28 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
return getResource("/exif/exif-jpeg-segment.bin").openStream();
}
protected EXIFReader createReader() {
return new EXIFReader();
protected TIFFReader createReader() {
return new TIFFReader();
}
@Override
protected EXIFWriter createWriter() {
return new EXIFWriter();
protected TIFFWriter createWriter() {
return new TIFFWriter();
}
@Test
public void testWriteReadSimple() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new EXIFEntry(TIFF.TAG_ORIENTATION, 1, TIFF.TYPE_SHORT));
entries.add(new EXIFEntry(TIFF.TAG_IMAGE_WIDTH, 1600, TIFF.TYPE_SHORT));
entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, TIFF.TYPE_SHORT, 1));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_SHORT, 1600));
entries.add(new AbstractEntry(TIFF.TAG_IMAGE_HEIGHT, 900) {});
entries.add(new EXIFEntry(TIFF.TAG_ARTIST, "Harald K.", TIFF.TYPE_ASCII));
entries.add(new TIFFEntry(TIFF.TAG_ARTIST, TIFF.TYPE_ASCII, "Harald K."));
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
new EXIFWriter().write(directory, imageStream);
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
@@ -95,13 +97,11 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
assertEquals(0, data[2]);
assertEquals(42, data[3]);
Directory read = new EXIFReader().read(new ByteArrayImageInputStream(data));
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(5, read.size());
// TODO: Assert that the tags are written in ascending order (don't test the read directory, but the file structure)!
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
assertEquals("TwelveMonkeys ImageIO", read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
@@ -122,7 +122,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
public void testWriteMotorola() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
entries.add(new EXIFEntry(TIFF.TAG_IMAGE_WIDTH, Integer.MAX_VALUE, TIFF.TYPE_LONG));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_LONG, Integer.MAX_VALUE));
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
@@ -130,7 +130,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
imageStream.setByteOrder(ByteOrder.BIG_ENDIAN); // BE = Motorola
new EXIFWriter().write(directory, imageStream);
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
@@ -143,7 +143,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
assertEquals(0, data[2]);
assertEquals(42, data[3]);
Directory read = new EXIFReader().read(new ByteArrayImageInputStream(data));
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(2, read.size());
@@ -157,7 +157,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
public void testWriteIntel() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
entries.add(new EXIFEntry(TIFF.TAG_IMAGE_WIDTH, Integer.MAX_VALUE, TIFF.TYPE_LONG));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_LONG, Integer.MAX_VALUE));
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
@@ -165,7 +165,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
imageStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // LE = Intel
new EXIFWriter().write(directory, imageStream);
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
@@ -178,7 +178,7 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
assertEquals(42, data[2]);
assertEquals(0, data[3]);
Directory read = new EXIFReader().read(new ByteArrayImageInputStream(data));
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(2, read.size());
@@ -188,45 +188,15 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
assertEquals((long) Integer.MAX_VALUE, read.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
}
@Test
public void testNesting() throws IOException {
EXIFEntry artist = new EXIFEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO", TIFF.TYPE_ASCII);
EXIFEntry subSubSubSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(artist)), TIFF.TYPE_LONG);
EXIFEntry subSubSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubSubSubIFD)), TIFF.TYPE_LONG);
EXIFEntry subSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubSubIFD)), TIFF.TYPE_LONG);
EXIFEntry subIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubIFD)), TIFF.TYPE_LONG);
Directory directory = new IFD(Collections.<Entry>singletonList(subIFD));
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
new EXIFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
Directory read = new EXIFReader().read(new ByteArrayImageInputStream(output.toByteArray()));
assertNotNull(read);
assertEquals(1, read.size());
assertEquals(subIFD, read.getEntryById(TIFF.TAG_SUB_IFD)); // Recursively tests content!
}
@Test
public void testReadWriteRead() throws IOException {
Directory original = createReader().read(getDataAsIIS());
ByteArrayOutputStream output = new FastByteArrayOutputStream(256);
ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output);
try {
try (ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output)) {
createWriter().write(original, imageOutput);
}
finally {
imageOutput.close();
}
Directory read = createReader().read(new ByteArrayImageInputStream(output.toByteArray()));
@@ -236,35 +206,16 @@ public class EXIFWriterTest extends MetadataWriterAbstractTest {
@Test
public void testComputeIFDSize() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new EXIFEntry(TIFF.TAG_ORIENTATION, 1, TIFF.TYPE_SHORT));
entries.add(new EXIFEntry(TIFF.TAG_IMAGE_WIDTH, 1600, TIFF.TYPE_SHORT));
entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, TIFF.TYPE_SHORT, 1));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_SHORT, 1600));
entries.add(new AbstractEntry(TIFF.TAG_IMAGE_HEIGHT, 900) {});
entries.add(new EXIFEntry(TIFF.TAG_ARTIST, "Harald K.", TIFF.TYPE_ASCII));
entries.add(new TIFFEntry(TIFF.TAG_ARTIST, TIFF.TYPE_ASCII, "Harald K."));
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
EXIFWriter writer = createWriter();
TIFFWriter writer = createWriter();
ImageOutputStream stream = new NullImageOutputStream();
writer.write(new IFD(entries), stream);
assertEquals(stream.getStreamPosition(), writer.computeIFDSize(entries) + 12);
}
@Test
public void testComputeIFDSizeNested() throws IOException {
EXIFEntry artist = new EXIFEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO", TIFF.TYPE_ASCII);
EXIFEntry subSubSubSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(artist)), TIFF.TYPE_LONG);
EXIFEntry subSubSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubSubSubIFD)), TIFF.TYPE_LONG);
EXIFEntry subSubIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubSubIFD)), TIFF.TYPE_LONG);
EXIFEntry subIFD = new EXIFEntry(TIFF.TAG_SUB_IFD, new IFD(Collections.singletonList(subSubIFD)), TIFF.TYPE_LONG);
List<Entry> entries = Collections.<Entry>singletonList(subIFD);
EXIFWriter writer = createWriter();
ImageOutputStream stream = new NullImageOutputStream();
writer.write(new IFD(entries), stream);
writer.write(entries, stream);
assertEquals(stream.getStreamPosition(), writer.computeIFDSize(entries) + 12);
}
@@ -0,0 +1,54 @@
package com.twelvemonkeys.imageio.metadata.exif;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* RationalTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: RationalTest.java,v 1.0 Nov 18, 2009 3:23:17 PM haraldk Exp$
*/
@SuppressWarnings("deprecation")
public class RationalTest {
@Test(expected = IllegalArgumentException.class)
public void testZeroDenominator() {
new Rational(1, 0);
}
@Test(expected = IllegalArgumentException.class)
public void testLongMinValueNumerator() {
new Rational(Long.MIN_VALUE, 1);
}
@Test(expected = IllegalArgumentException.class)
public void testLongMinValueDenominator() {
new Rational(1, Long.MIN_VALUE);
}
@Test
public void testEquals() {
assertEquals(new Rational(0, 1), new Rational(0, 999));
assertEquals(new Rational(0, 1), new Rational(0, -1));
assertEquals(new Rational(1, 2), new Rational(1000000, 2000000));
assertEquals(new Rational(1, -2), new Rational(-1, 2));
Rational x = new Rational(1, -2);
Rational y = new Rational(-1000000, 2000000);
assertEquals(x, y);
assertEquals(x.numerator(), y.numerator());
assertEquals(x.denominator(), y.denominator());
}
@Test
public void testEqualsBoundaries() {
assertEquals(new Rational(Long.MAX_VALUE, Long.MAX_VALUE), new Rational(1, 1));
// NOTE: Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE... :-P
assertEquals(new Rational(Long.MIN_VALUE + 1, Long.MIN_VALUE + 1), new Rational(1, 1));
assertEquals(new Rational(Long.MIN_VALUE + 1, Long.MAX_VALUE), new Rational(-1, 1));
assertEquals(new Rational(Long.MAX_VALUE, Long.MIN_VALUE + 1), new Rational(-1, 1));
}
}
@@ -26,7 +26,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.metadata.exif;
package com.twelvemonkeys.imageio.metadata.tiff;
import com.twelvemonkeys.imageio.metadata.Directory;
import com.twelvemonkeys.imageio.metadata.DirectoryAbstractTest;
@@ -1,41 +1,34 @@
package com.twelvemonkeys.imageio.metadata.exif;
package com.twelvemonkeys.imageio.metadata.tiff;
import junit.framework.TestCase;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
/**
* RationalTestCase
* RationalTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: RationalTestCase.java,v 1.0 Nov 18, 2009 3:23:17 PM haraldk Exp$
* @version $Id: RationalTest.java,v 1.0 Nov 18, 2009 3:23:17 PM haraldk Exp$
*/
public class RationalTestCase extends TestCase {
public class RationalTest {
@Test(expected = IllegalArgumentException.class)
public void testZeroDenominator() {
try {
new Rational(1, 0);
fail("IllegalArgumentException expected");
}
catch (IllegalArgumentException expected) {
}
new Rational(1, 0);
}
// TODO: Find a solution to this problem, as we should be able to work with it...
public void testLongMinValue() {
try {
new Rational(Long.MIN_VALUE, 1);
fail("IllegalArgumentException expected");
}
catch (IllegalArgumentException expected) {
}
try {
new Rational(1, Long.MIN_VALUE);
fail("IllegalArgumentException expected");
}
catch (IllegalArgumentException expected) {
}
@Test(expected = IllegalArgumentException.class)
public void testLongMinValueNumerator() {
new Rational(Long.MIN_VALUE, 1);
}
@Test(expected = IllegalArgumentException.class)
public void testLongMinValueDenominator() {
new Rational(1, Long.MIN_VALUE);
}
@Test
public void testEquals() {
assertEquals(new Rational(0, 1), new Rational(0, 999));
assertEquals(new Rational(0, 1), new Rational(0, -1));
@@ -47,9 +40,9 @@ public class RationalTestCase extends TestCase {
assertEquals(x, y);
assertEquals(x.numerator(), y.numerator());
assertEquals(x.denominator(), y.denominator());
}
@Test
public void testEqualsBoundaries() {
assertEquals(new Rational(Long.MAX_VALUE, Long.MAX_VALUE), new Rational(1, 1));
@@ -59,16 +52,19 @@ public class RationalTestCase extends TestCase {
assertEquals(new Rational(Long.MAX_VALUE, Long.MIN_VALUE + 1), new Rational(-1, 1));
}
@Test
public void testReciprocal() {
assertEquals(new Rational(1, 99), new Rational(99, 1).reciprocal());
assertEquals(new Rational(-1, 1234567), new Rational(-1234567, 1).reciprocal());
}
@Test
public void testNegate() {
assertEquals(new Rational(-1, 99), new Rational(1, 99).negate());
assertEquals(new Rational(1, 1234567), new Rational(1, -1234567).negate());
}
@Test
public void testPlus() {
Rational x, y;
@@ -96,6 +92,7 @@ public class RationalTestCase extends TestCase {
assertEquals(x, x.plus(Rational.ZERO));
}
@Test
public void testTimes() {
Rational x, y;
@@ -113,6 +110,7 @@ public class RationalTestCase extends TestCase {
assertEquals(Rational.ZERO, x.times(Rational.ZERO));
}
@Test
public void testMinus() {
// 1/6 - -4/-8 = -1/3
Rational x = new Rational(1, 6);
@@ -123,6 +121,7 @@ public class RationalTestCase extends TestCase {
assertEquals(x, x.minus(Rational.ZERO));
}
@Test
public void testDivides() {
// 3037141/3247033 / 3246599/3037547 = 841/961
Rational x = new Rational(3037141, 3247033);
@@ -133,11 +132,8 @@ public class RationalTestCase extends TestCase {
assertEquals(Rational.ZERO, new Rational(0, 386).divides(x));
}
@Test(expected = ArithmeticException.class)
public void testDivideZero() {
try {
new Rational(3037141, 3247033).divides(new Rational(0, 1));
}
catch (ArithmeticException expected) {
}
new Rational(3037141, 3247033).divides(new Rational(0, 1));
}
}
@@ -26,7 +26,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.metadata.exif;
package com.twelvemonkeys.imageio.metadata.tiff;
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
import com.twelvemonkeys.imageio.metadata.CompoundDirectoryAbstractTest;
@@ -35,15 +35,15 @@ import com.twelvemonkeys.imageio.metadata.Directory;
import java.util.Collection;
/**
* EXIFDirectoryTest
* TIFFDirectoryTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: EXIFDirectoryTest.java,v 1.0 02.01.12 16:41 haraldk Exp$
* @version $Id: TIFFDirectoryTest.java,v 1.0 02.01.12 16:41 haraldk Exp$
*/
public class EXIFDirectoryTest extends CompoundDirectoryAbstractTest {
public class TIFFDirectoryTest extends CompoundDirectoryAbstractTest {
@Override
protected CompoundDirectory createCompoundDirectory(Collection<Directory> directories) {
return new EXIFDirectory(directories);
return new TIFFDirectory(directories);
}
}
@@ -26,27 +26,27 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.metadata.exif;
package com.twelvemonkeys.imageio.metadata.tiff;
import com.twelvemonkeys.imageio.metadata.Entry;
import com.twelvemonkeys.imageio.metadata.EntryAbstractTest;
import org.junit.Test;
/**
* EXIFEntryTest
* TIFFEntryTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: EXIFEntryTest.java,v 1.0 02.01.12 17:35 haraldk Exp$
* @version $Id: TIFFEntryTest.java,v 1.0 02.01.12 17:35 haraldk Exp$
*/
public class EXIFEntryTest extends EntryAbstractTest {
public class TIFFEntryTest extends EntryAbstractTest {
@Override
protected Entry createEntry(final Object value) {
return createEXIFEntry(TIFF.TAG_COPYRIGHT, value, (short) 2);
}
private EXIFEntry createEXIFEntry(final int identifier, final Object value, final int type) {
return new EXIFEntry(identifier, value, (short) type);
private TIFFEntry createEXIFEntry(final int identifier, final Object value, final int type) {
return new TIFFEntry(identifier, (short) type, value);
}
@Test(expected = IllegalArgumentException.class)
@@ -0,0 +1,314 @@
/*
* Copyright (c) 2011, 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 "TwelveMonkeys" 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 OWNER 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.metadata.tiff;
import com.twelvemonkeys.imageio.metadata.CompoundDirectory;
import com.twelvemonkeys.imageio.metadata.Directory;
import com.twelvemonkeys.imageio.metadata.Entry;
import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest;
import com.twelvemonkeys.imageio.metadata.exif.EXIF;
import com.twelvemonkeys.imageio.stream.SubImageInputStream;
import org.junit.Test;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageInputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.junit.Assert.*;
/**
* TIFFReaderTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: TIFFReaderTest.java,v 1.0 23.12.11 13:50 haraldk Exp$
*/
public class TIFFReaderTest extends MetadataReaderAbstractTest {
@Override
protected InputStream getData() throws IOException {
return getResource("/exif/exif-jpeg-segment.bin").openStream();
}
@Override
protected TIFFReader createReader() {
return new TIFFReader();
}
@Test
public void testIsCompoundDirectory() throws IOException {
Directory exif = createReader().read(getDataAsIIS());
assertThat(exif, instanceOf(CompoundDirectory.class));
}
@Test
public void testDirectory() throws IOException {
CompoundDirectory exif = (CompoundDirectory) createReader().read(getDataAsIIS());
assertEquals(2, exif.directoryCount());
assertNotNull(exif.getDirectory(0));
assertNotNull(exif.getDirectory(1));
assertEquals(exif.size(), exif.getDirectory(0).size() + exif.getDirectory(1).size());
}
@Test(expected = IndexOutOfBoundsException.class)
public void testDirectoryOutOfBounds() throws IOException {
InputStream data = getData();
CompoundDirectory exif = (CompoundDirectory) createReader().read(ImageIO.createImageInputStream(data));
assertEquals(2, exif.directoryCount());
assertNotNull(exif.getDirectory(exif.directoryCount()));
}
@Test
public void testEntries() throws IOException {
CompoundDirectory exif = (CompoundDirectory) createReader().read(getDataAsIIS());
// From IFD0
assertNotNull(exif.getEntryById(TIFF.TAG_SOFTWARE));
assertEquals("Adobe Photoshop CS2 Macintosh", exif.getEntryById(TIFF.TAG_SOFTWARE).getValue());
assertEquals(exif.getEntryById(TIFF.TAG_SOFTWARE), exif.getEntryByFieldName("Software"));
// From IFD1
assertNotNull(exif.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT));
assertEquals((long) 418, exif.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT).getValue());
assertEquals(exif.getEntryById(TIFF.TAG_JPEG_INTERCHANGE_FORMAT), exif.getEntryByFieldName("JPEGInterchangeFormat"));
}
@Test
public void testIFD0() throws IOException {
CompoundDirectory exif = (CompoundDirectory) createReader().read(getDataAsIIS());
Directory ifd0 = exif.getDirectory(0);
assertNotNull(ifd0);
assertNotNull(ifd0.getEntryById(TIFF.TAG_IMAGE_WIDTH));
assertEquals(3601, ifd0.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
assertNotNull(ifd0.getEntryById(TIFF.TAG_IMAGE_HEIGHT));
assertEquals(4176, ifd0.getEntryById(TIFF.TAG_IMAGE_HEIGHT).getValue());
// Assert 'uncompressed' (there's no TIFF image here, really)
assertNotNull(ifd0.getEntryById(TIFF.TAG_COMPRESSION));
assertEquals(1, ifd0.getEntryById(TIFF.TAG_COMPRESSION).getValue());
}
@Test
public void testIFD1() throws IOException {
CompoundDirectory exif = (CompoundDirectory) createReader().read(getDataAsIIS());
Directory ifd1 = exif.getDirectory(1);
assertNotNull(ifd1);
// Assert 'JPEG compression' (thumbnail only)
assertNotNull(ifd1.getEntryById(TIFF.TAG_COMPRESSION));
assertEquals(6, ifd1.getEntryById(TIFF.TAG_COMPRESSION).getValue());
assertNull(ifd1.getEntryById(TIFF.TAG_IMAGE_WIDTH));
assertNull(ifd1.getEntryById(TIFF.TAG_IMAGE_HEIGHT));
}
@Test
public void testReadBadDataZeroCount() throws IOException {
// This image seems to contain bad Exif. But as other tools are able to read, so should we..
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-rgb-thumbnail-bad-exif-kodak-dc210.jpg"));
stream.seek(12);
Directory directory = createReader().read(new SubImageInputStream(stream, 21674));
assertEquals(22, directory.size());
// Special case: Ascii string with count == 0, not ok according to spec (?), but we'll let it pass
assertEquals("", directory.getEntryById(TIFF.TAG_IMAGE_DESCRIPTION).getValue());
}
@Test
public void testReadBadDataRationalZeroDenominator() throws IOException {
// This image seems to contain bad Exif. But as other tools are able to read, so should we..
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-rgb-thumbnail-bad-exif-kodak-dc210.jpg"));
stream.seek(12);
Directory directory = createReader().read(new SubImageInputStream(stream, 21674));
// Special case: Rational with zero-denominator inside EXIF data
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
Entry entry = exif.getEntryById(EXIF.TAG_COMPRESSED_BITS_PER_PIXEL);
assertNotNull(entry);
assertEquals(Rational.NaN, entry.getValue());
}
@Test
public void testReadBadDirectoryCount() throws IOException {
// This image seems to contain bad Exif. But as other tools are able to read, so should we..
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-bad-directory-entry-count.jpg"));
stream.seek(4424 + 10);
Directory directory = createReader().read(new SubImageInputStream(stream, 214 - 6));
assertEquals(7, directory.size()); // TIFF structure says 8, but the last entry isn't there
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(3, exif.size());
}
@Test
public void testTIFFWithBadExifIFD() throws IOException {
// This image seems to contain bad TIFF data. But as other tools are able to read, so should we..
// It seems that the EXIF data (at offset 494196 or 0x78a74) overlaps with a custom
// Microsoft 'OLE Property Set' entry at 0x78a70 (UNDEFINED, count 5632)...
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/tiff/chifley_logo.tif"));
Directory directory = createReader().read(stream);
assertEquals(22, directory.size());
// Some (all?) of the EXIF data is duplicated in the XMP, meaning PhotoShop can probably re-create it
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(0, exif.size()); // EXIFTool reports "Warning: Bad ExifIFD directory"
}
@Test
public void testReadExifJPEGWithInteropSubDirR98() throws IOException {
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-with-interop-subdir-R98.jpg"));
stream.seek(30);
CompoundDirectory directory = (CompoundDirectory) createReader().read(new SubImageInputStream(stream, 1360));
assertEquals(17, directory.size());
assertEquals(2, directory.directoryCount());
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(23, exif.size());
// The interop IFD is empty (entry count is 0)
Directory interop = (Directory) exif.getEntryById(TIFF.TAG_INTEROP_IFD).getValue();
assertNotNull(interop);
assertEquals(2, interop.size());
assertNotNull(interop.getEntryById(1)); // InteropIndex
assertEquals("ASCII", interop.getEntryById(1).getTypeName());
assertEquals("R98", interop.getEntryById(1).getValue()); // Known values: R98, THM or R03
assertNotNull(interop.getEntryById(2)); // InteropVersion
assertEquals("UNDEFINED", interop.getEntryById(2).getTypeName());
assertArrayEquals(new byte[] {'0', '1', '0', '0'}, (byte[]) interop.getEntryById(2).getValue());
}
@Test
public void testReadExifJPEGWithInteropSubDirEmpty() throws IOException {
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-with-interop-subdir-empty.jpg"));
stream.seek(30);
CompoundDirectory directory = (CompoundDirectory) createReader().read(new SubImageInputStream(stream, 1360));
assertEquals(11, directory.size());
assertEquals(1, directory.directoryCount());
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(24, exif.size());
// The interop IFD is empty (entry count is 0)
Directory interop = (Directory) exif.getEntryById(TIFF.TAG_INTEROP_IFD).getValue();
assertNotNull(interop);
assertEquals(0, interop.size());
}
@Test
public void testReadExifJPEGWithInteropSubDirEOF() throws IOException {
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-with-interop-subdir-eof.jpg"));
stream.seek(30);
CompoundDirectory directory = (CompoundDirectory) createReader().read(new SubImageInputStream(stream, 236));
assertEquals(8, directory.size());
assertEquals(1, directory.directoryCount());
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(5, exif.size());
// The interop IFD isn't there (offset points to outside the TIFF structure)...
// Have double-checked using ExifTool, which says "Warning : Bad InteropOffset SubDirectory start"
Directory interop = (Directory) exif.getEntryById(TIFF.TAG_INTEROP_IFD).getValue();
assertNotNull(interop);
assertEquals(0, interop.size());
}
@Test
public void testReadExifJPEGWithInteropSubDirBad() throws IOException {
ImageInputStream stream = ImageIO.createImageInputStream(getResource("/jpeg/exif-with-interop-subdir-bad.jpg"));
stream.seek(30);
CompoundDirectory directory = (CompoundDirectory) createReader().read(new SubImageInputStream(stream, 12185));
assertEquals(16, directory.size());
assertEquals(2, directory.directoryCount());
Directory exif = (Directory) directory.getEntryById(TIFF.TAG_EXIF_IFD).getValue();
assertNotNull(exif);
assertEquals(26, exif.size());
// JPEG starts at offset 1666 and length 10519, interop IFD points to offset 1900...
// Have double-checked using ExifTool, which says "Warning : Bad InteropIFD directory"
Directory interop = (Directory) exif.getEntryById(TIFF.TAG_INTEROP_IFD).getValue();
assertNotNull(interop);
assertEquals(0, interop.size());
}
@Test
public void testReadExifWithMissingEOFMarker() throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(getResource("/exif/noeof.tif"))) {
CompoundDirectory directory = (CompoundDirectory) createReader().read(stream);
assertEquals(15, directory.size());
assertEquals(1, directory.directoryCount());
}
}
@Test
public void testReadExifWithEmptyTag() throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(getResource("/exif/emptyexiftag.tif"))) {
CompoundDirectory directory = (CompoundDirectory) createReader().read(stream);
assertEquals(3, directory.directoryCount());
}
}
@Test
public void testReadValueBeyondEOF() throws IOException {
try (ImageInputStream stream = ImageIO.createImageInputStream(getResource("/exif/value-beyond-eof.tif"))) {
CompoundDirectory directory = (CompoundDirectory) createReader().read(stream);
assertEquals(1, directory.directoryCount());
assertEquals(5, directory.size());
assertEquals(1, directory.getEntryById(TIFF.TAG_PHOTOMETRIC_INTERPRETATION).getValue());
assertEquals(10, directory.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
assertEquals(10, directory.getEntryById(TIFF.TAG_IMAGE_HEIGHT).getValue());
assertEquals(42L, directory.getEntryById(32935).getValue());
// NOTE: Assumes current implementation, could possibly change in the future.
assertTrue(directory.getEntryById(32934).getValue() instanceof EOFException);
}
}
}
@@ -0,0 +1,293 @@
/*
* Copyright (c) 2013, 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 "TwelveMonkeys" 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 OWNER 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.metadata.tiff;
import com.twelvemonkeys.imageio.metadata.*;
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
import com.twelvemonkeys.io.FastByteArrayOutputStream;
import org.junit.Test;
import javax.imageio.ImageIO;
import javax.imageio.stream.ImageOutputStream;
import javax.imageio.stream.ImageOutputStreamImpl;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* TIFFWriterTest
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: TIFFWriterTest.java,v 1.0 18.07.13 09:53 haraldk Exp$
*/
public class TIFFWriterTest extends MetadataWriterAbstractTest {
@Override
protected InputStream getData() throws IOException {
return getResource("/exif/exif-jpeg-segment.bin").openStream();
}
protected TIFFReader createReader() {
return new TIFFReader();
}
@Override
protected TIFFWriter createWriter() {
return new TIFFWriter();
}
@Test
public void testWriteReadSimple() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, TIFF.TYPE_SHORT, 1));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_SHORT, 1600));
entries.add(new AbstractEntry(TIFF.TAG_IMAGE_HEIGHT, 900) {});
entries.add(new TIFFEntry(TIFF.TAG_ARTIST, TIFF.TYPE_ASCII, "Harald K."));
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
byte[] data = output.toByteArray();
assertEquals(106, data.length);
assertEquals('M', data[0]);
assertEquals('M', data[1]);
assertEquals(0, data[2]);
assertEquals(42, data[3]);
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(5, read.size());
// TODO: Assert that the tags are written in ascending order (don't test the read directory, but the file structure)!
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
assertEquals("TwelveMonkeys ImageIO", read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_IMAGE_WIDTH));
assertEquals(1600, read.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_IMAGE_HEIGHT));
assertEquals(900, read.getEntryById(TIFF.TAG_IMAGE_HEIGHT).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_ORIENTATION));
assertEquals(1, read.getEntryById(TIFF.TAG_ORIENTATION).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_ARTIST));
assertEquals("Harald K.", read.getEntryById(TIFF.TAG_ARTIST).getValue());
}
@Test
public void testWriteMotorola() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_LONG, Integer.MAX_VALUE));
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
imageStream.setByteOrder(ByteOrder.BIG_ENDIAN); // BE = Motorola
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
byte[] data = output.toByteArray();
assertEquals(60, data.length);
assertEquals('M', data[0]);
assertEquals('M', data[1]);
assertEquals(0, data[2]);
assertEquals(42, data[3]);
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(2, read.size());
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
assertEquals("TwelveMonkeys ImageIO", read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_IMAGE_WIDTH));
assertEquals((long) Integer.MAX_VALUE, read.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
}
@Test
public void testWriteIntel() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_LONG, Integer.MAX_VALUE));
Directory directory = new AbstractDirectory(entries) {};
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
imageStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); // LE = Intel
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
byte[] data = output.toByteArray();
assertEquals(60, data.length);
assertEquals('I', data[0]);
assertEquals('I', data[1]);
assertEquals(42, data[2]);
assertEquals(0, data[3]);
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(data));
assertNotNull(read);
assertEquals(2, read.size());
assertNotNull(read.getEntryById(TIFF.TAG_SOFTWARE));
assertEquals("TwelveMonkeys ImageIO", read.getEntryById(TIFF.TAG_SOFTWARE).getValue());
assertNotNull(read.getEntryById(TIFF.TAG_IMAGE_WIDTH));
assertEquals((long) Integer.MAX_VALUE, read.getEntryById(TIFF.TAG_IMAGE_WIDTH).getValue());
}
@Test
public void testNesting() throws IOException {
TIFFEntry artist = new TIFFEntry(TIFF.TAG_SOFTWARE, TIFF.TYPE_ASCII, "TwelveMonkeys ImageIO");
TIFFEntry subSubSubSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(artist)));
TIFFEntry subSubSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubSubIFD)));
TIFFEntry subSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubIFD)));
TIFFEntry subIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubIFD)));
Directory directory = new IFD(Collections.<Entry>singletonList(subIFD));
ByteArrayOutputStream output = new FastByteArrayOutputStream(1024);
ImageOutputStream imageStream = ImageIO.createImageOutputStream(output);
new TIFFWriter().write(directory, imageStream);
imageStream.flush();
assertEquals(output.size(), imageStream.getStreamPosition());
Directory read = new TIFFReader().read(new ByteArrayImageInputStream(output.toByteArray()));
assertNotNull(read);
assertEquals(1, read.size());
assertEquals(subIFD, read.getEntryById(TIFF.TAG_SUB_IFD)); // Recursively tests content!
}
@Test
public void testReadWriteRead() throws IOException {
Directory original = createReader().read(getDataAsIIS());
ByteArrayOutputStream output = new FastByteArrayOutputStream(256);
ImageOutputStream imageOutput = ImageIO.createImageOutputStream(output);
try {
createWriter().write(original, imageOutput);
}
finally {
imageOutput.close();
}
Directory read = createReader().read(new ByteArrayImageInputStream(output.toByteArray()));
assertEquals(original, read);
}
@Test
public void testComputeIFDSize() throws IOException {
ArrayList<Entry> entries = new ArrayList<>();
entries.add(new TIFFEntry(TIFF.TAG_ORIENTATION, TIFF.TYPE_SHORT, 1));
entries.add(new TIFFEntry(TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_SHORT, 1600));
entries.add(new AbstractEntry(TIFF.TAG_IMAGE_HEIGHT, 900) {});
entries.add(new TIFFEntry(TIFF.TAG_ARTIST, TIFF.TYPE_ASCII, "Harald K."));
entries.add(new AbstractEntry(TIFF.TAG_SOFTWARE, "TwelveMonkeys ImageIO") {});
TIFFWriter writer = createWriter();
ImageOutputStream stream = new NullImageOutputStream();
writer.write(new IFD(entries), stream);
assertEquals(stream.getStreamPosition(), writer.computeIFDSize(entries) + 12);
}
@Test
public void testComputeIFDSizeNested() throws IOException {
TIFFEntry artist = new TIFFEntry(TIFF.TAG_SOFTWARE, TIFF.TYPE_ASCII, "TwelveMonkeys ImageIO");
TIFFEntry subSubSubSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(artist)));
TIFFEntry subSubSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubSubIFD)));
TIFFEntry subSubIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubSubIFD)));
TIFFEntry subIFD = new TIFFEntry(TIFF.TAG_SUB_IFD, TIFF.TYPE_LONG, new IFD(Collections.singletonList(subSubIFD)));
List<Entry> entries = Collections.<Entry>singletonList(subIFD);
TIFFWriter writer = createWriter();
ImageOutputStream stream = new NullImageOutputStream();
writer.write(new IFD(entries), stream);
assertEquals(stream.getStreamPosition(), writer.computeIFDSize(entries) + 12);
}
private static class NullImageOutputStream extends ImageOutputStreamImpl {
@Override
public void write(int b) throws IOException {
streamPos++;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
streamPos += len;
}
@Override
public int read() throws IOException {
throw new UnsupportedOperationException("Method read not implemented");
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
throw new UnsupportedOperationException("Method read not implemented");
}
}
}
@@ -26,7 +26,7 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.metadata.exif;
package com.twelvemonkeys.imageio.metadata.tiff;
import com.twelvemonkeys.lang.ObjectAbstractTestCase;