mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2026-05-01 00:00:02 -04:00
Merge remote-tracking branch 'remotes/haraldk/master' into CCITTWriter
This commit is contained in:
+599
@@ -0,0 +1,599 @@
|
||||
package com.twelvemonkeys.imageio.plugins.tiff;
|
||||
|
||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFReader;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
||||
import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.IIORegistry;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* TIFFImageMetadataTest.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: harald.kuhr$
|
||||
* @version $Id: TIFFImageMetadataTest.java,v 1.0 30/07/15 harald.kuhr Exp$
|
||||
*/
|
||||
public class TIFFImageMetadataTest {
|
||||
|
||||
static {
|
||||
IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi());
|
||||
ImageIO.setUseCache(false);
|
||||
}
|
||||
|
||||
// TODO: Candidate super method
|
||||
private URL getClassLoaderResource(final String resource) {
|
||||
return getClass().getResource(resource);
|
||||
}
|
||||
|
||||
// TODO: Candidate abstract super method
|
||||
private IIOMetadata createMetadata(final String resource) throws IOException {
|
||||
try (ImageInputStream input = ImageIO.createImageInputStream(getClassLoaderResource(resource))) {
|
||||
Directory ifd = new EXIFReader().read(input);
|
||||
// System.err.println("ifd: " + ifd);
|
||||
return new TIFFImageMetadata(ifd);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadataStandardFormat() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/smallliz.tif");
|
||||
Node root = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||
|
||||
// Root: "javax_imageio_1.0"
|
||||
assertNotNull(root);
|
||||
assertEquals(IIOMetadataFormatImpl.standardMetadataFormatName, root.getNodeName());
|
||||
assertEquals(6, root.getChildNodes().getLength());
|
||||
|
||||
// "Chroma"
|
||||
Node chroma = root.getFirstChild();
|
||||
assertEquals("Chroma", chroma.getNodeName());
|
||||
|
||||
assertEquals(3, chroma.getChildNodes().getLength());
|
||||
|
||||
Node colorSpaceType = chroma.getFirstChild();
|
||||
assertEquals("ColorSpaceType", colorSpaceType.getNodeName());
|
||||
assertEquals("YCbCr", ((Element) colorSpaceType).getAttribute("value"));
|
||||
|
||||
Node numChannels = colorSpaceType.getNextSibling();
|
||||
assertEquals("NumChannels", numChannels.getNodeName());
|
||||
assertEquals("3", ((Element) numChannels).getAttribute("value"));
|
||||
|
||||
Node blackIsZero = numChannels.getNextSibling();
|
||||
assertEquals("BlackIsZero", blackIsZero.getNodeName());
|
||||
assertEquals(0, blackIsZero.getAttributes().getLength());
|
||||
|
||||
// "Compression"
|
||||
Node compression = chroma.getNextSibling();
|
||||
assertEquals("Compression", compression.getNodeName());
|
||||
assertEquals(2, compression.getChildNodes().getLength());
|
||||
|
||||
Node compressionTypeName = compression.getFirstChild();
|
||||
assertEquals("CompressionTypeName", compressionTypeName.getNodeName());
|
||||
assertEquals("Old JPEG", ((Element) compressionTypeName).getAttribute("value"));
|
||||
|
||||
Node lossless = compressionTypeName.getNextSibling();
|
||||
assertEquals("Lossless", lossless.getNodeName());
|
||||
assertEquals("FALSE", ((Element) lossless).getAttribute("value"));
|
||||
|
||||
// "Data"
|
||||
Node data = compression.getNextSibling();
|
||||
assertEquals("Data", data.getNodeName());
|
||||
assertEquals(4, data.getChildNodes().getLength());
|
||||
|
||||
Node planarConfiguration = data.getFirstChild();
|
||||
assertEquals("PlanarConfiguration", planarConfiguration.getNodeName());
|
||||
assertEquals("PixelInterleaved", ((Element) planarConfiguration).getAttribute("value"));
|
||||
|
||||
Node sampleFormat = planarConfiguration.getNextSibling();
|
||||
assertEquals("SampleFormat", sampleFormat.getNodeName());
|
||||
assertEquals("UnsignedIntegral", ((Element) sampleFormat).getAttribute("value"));
|
||||
|
||||
Node bitsPerSample = sampleFormat.getNextSibling();
|
||||
assertEquals("BitsPerSample", bitsPerSample.getNodeName());
|
||||
assertEquals("8 8 8", ((Element) bitsPerSample).getAttribute("value"));
|
||||
|
||||
Node sampleMSB = bitsPerSample.getNextSibling();
|
||||
assertEquals("SampleMSB", sampleMSB.getNodeName());
|
||||
assertEquals("0 0 0", ((Element) sampleMSB).getAttribute("value"));
|
||||
|
||||
// "Dimension"
|
||||
Node dimension = data.getNextSibling();
|
||||
assertEquals("Dimension", dimension.getNodeName());
|
||||
assertEquals(3, dimension.getChildNodes().getLength());
|
||||
|
||||
Node pixelAspectRatio = dimension.getFirstChild();
|
||||
assertEquals("PixelAspectRatio", pixelAspectRatio.getNodeName());
|
||||
assertEquals("1.0", ((Element) pixelAspectRatio).getAttribute("value"));
|
||||
|
||||
Node horizontalPixelSize = pixelAspectRatio.getNextSibling();
|
||||
assertEquals("HorizontalPixelSize", horizontalPixelSize.getNodeName());
|
||||
assertEquals("0.254", ((Element) horizontalPixelSize).getAttribute("value"));
|
||||
|
||||
Node verticalPixelSize = horizontalPixelSize.getNextSibling();
|
||||
assertEquals("VerticalPixelSize", verticalPixelSize.getNodeName());
|
||||
assertEquals("0.254", ((Element) verticalPixelSize).getAttribute("value"));
|
||||
|
||||
// "Document"
|
||||
Node document = dimension.getNextSibling();
|
||||
assertEquals("Document", document.getNodeName());
|
||||
assertEquals(1, document.getChildNodes().getLength());
|
||||
|
||||
Node formatVersion = document.getFirstChild();
|
||||
assertEquals("FormatVersion", formatVersion.getNodeName());
|
||||
assertEquals("6.0", ((Element) formatVersion).getAttribute("value"));
|
||||
|
||||
// "Text"
|
||||
Node text = document.getNextSibling();
|
||||
assertEquals("Text", text.getNodeName());
|
||||
assertEquals(1, text.getChildNodes().getLength());
|
||||
|
||||
// NOTE: Could be multiple "TextEntry" elements, with different "keyword" attributes
|
||||
Node textEntry = text.getFirstChild();
|
||||
assertEquals("TextEntry", textEntry.getNodeName());
|
||||
assertEquals("Software", ((Element) textEntry).getAttribute("keyword"));
|
||||
assertEquals("HP IL v1.1", ((Element) textEntry).getAttribute("value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMetadataNativeFormat() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/quad-lzw.tif");
|
||||
Node root = metadata.getAsTree(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||
|
||||
// Root: "com_sun_media_imageio_plugins_tiff_image_1.0"
|
||||
assertNotNull(root);
|
||||
assertEquals(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME, root.getNodeName());
|
||||
assertEquals(1, root.getChildNodes().getLength());
|
||||
|
||||
// IFD: "TIFFIFD"
|
||||
Node ifd = root.getFirstChild();
|
||||
assertEquals("TIFFIFD", ifd.getNodeName());
|
||||
|
||||
NodeList entries = ifd.getChildNodes();
|
||||
assertEquals(13, entries.getLength());
|
||||
|
||||
String[] stripOffsets = {
|
||||
"8", "150", "292", "434", "576", "718", "860", "1002", "1144", "1286",
|
||||
"1793", "3823", "7580", "12225", "17737", "23978", "30534", "36863", "42975", "49180",
|
||||
"55361", "61470", "67022", "71646", "74255", "75241", "75411", "75553", "75695", "75837",
|
||||
"75979", "76316", "77899", "80466", "84068", "88471", "93623", "99105", "104483", "109663",
|
||||
"114969", "120472", "126083", "131289", "135545", "138810", "140808", "141840", "141982", "142124",
|
||||
"142266", "142408", "142615", "144074", "146327", "149721", "154066", "158927", "164022", "169217",
|
||||
"174409", "179657", "185166", "190684", "196236", "201560", "206064", "209497", "211612", "212419",
|
||||
"212561", "212703", "212845", "212987", "213129", "213271", "213413"
|
||||
};
|
||||
|
||||
String[] stripByteCounts = {
|
||||
"142", "142", "142", "142", "142", "142", "142", "142", "142", "507",
|
||||
"2030", "3757", "4645", "5512", "6241", "6556", "6329", "6112", "6205", "6181",
|
||||
"6109", "5552", "4624", "2609", "986", "170", "142", "142", "142", "142",
|
||||
"337", "1583", "2567", "3602", "4403", "5152", "5482", "5378", "5180", "5306",
|
||||
"5503", "5611", "5206", "4256", "3265", "1998", "1032", "142", "142", "142",
|
||||
"142", "207", "1459", "2253", "3394", "4345", "4861", "5095", "5195", "5192",
|
||||
"5248", "5509", "5518", "5552", "5324", "4504", "3433", "2115", "807", "142",
|
||||
"142", "142", "142", "142", "142", "142", "128"
|
||||
};
|
||||
|
||||
// The 13 entries
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_IMAGE_WIDTH, TIFF.TYPE_SHORT, "512");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_IMAGE_HEIGHT, TIFF.TYPE_SHORT, "384");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_BITS_PER_SAMPLE, TIFF.TYPE_SHORT, "8", "8", "8");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_COMPRESSION, TIFF.TYPE_SHORT, "5");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_PHOTOMETRIC_INTERPRETATION, TIFF.TYPE_SHORT, "2");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_STRIP_OFFSETS, TIFF.TYPE_LONG, stripOffsets);
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_SAMPLES_PER_PIXEL, TIFF.TYPE_SHORT, "3");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_ROWS_PER_STRIP, TIFF.TYPE_LONG, "5");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_STRIP_BYTE_COUNTS, TIFF.TYPE_LONG, stripByteCounts);
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_PLANAR_CONFIGURATION, TIFF.TYPE_SHORT, "1");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_X_POSITION, TIFF.TYPE_RATIONAL, "0");
|
||||
assertSingleNodeWithValue(entries, TIFF.TAG_Y_POSITION, TIFF.TYPE_RATIONAL, "0");
|
||||
assertSingleNodeWithValue(entries, 32995, TIFF.TYPE_SHORT, "0"); // Matteing tag, obsoleted by ExtraSamples tag in TIFF 6.0
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTreeDetached() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
Node nativeTree = metadata.getAsTree(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||
assertNotNull(nativeTree);
|
||||
|
||||
Node nativeTree2 = metadata.getAsTree(TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME);
|
||||
assertNotNull(nativeTree2);
|
||||
|
||||
assertNotSame(nativeTree, nativeTree2);
|
||||
assertNodeEquals("Unmodified trees differs", nativeTree, nativeTree2); // Both not modified
|
||||
|
||||
// Modify one of the trees
|
||||
Node ifdNode = nativeTree2.getFirstChild();
|
||||
ifdNode.removeChild(ifdNode.getFirstChild());
|
||||
IIOMetadataNode tiffField = new IIOMetadataNode("TIFFField");
|
||||
ifdNode.appendChild(tiffField);
|
||||
|
||||
assertNodeNotEquals("Modified tree does not differ", nativeTree, nativeTree2);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTree() throws IOException {
|
||||
TIFFImageMetadata metadata = (TIFFImageMetadata) createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
|
||||
Node nativeTree = metadata.getAsTree(nativeFormat);
|
||||
assertNotNull(nativeTree);
|
||||
|
||||
IIOMetadataNode newTree = new IIOMetadataNode("com_sun_media_imageio_plugins_tiff_image_1.0");
|
||||
IIOMetadataNode ifdNode = new IIOMetadataNode("TIFFIFD");
|
||||
newTree.appendChild(ifdNode);
|
||||
|
||||
createTIFFFieldNode(ifdNode, TIFF.TAG_RESOLUTION_UNIT, TIFF.TYPE_SHORT, TIFFBaseline.RESOLUTION_UNIT_DPI);
|
||||
createTIFFFieldNode(ifdNode, TIFF.TAG_X_RESOLUTION, TIFF.TYPE_RATIONAL, new Rational(300));
|
||||
createTIFFFieldNode(ifdNode, TIFF.TAG_Y_RESOLUTION, TIFF.TYPE_RATIONAL, new Rational(30001, 100));
|
||||
|
||||
metadata.mergeTree(nativeFormat, newTree);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_X_RESOLUTION));
|
||||
assertEquals(new Rational(300), ifd.getEntryById(TIFF.TAG_X_RESOLUTION).getValue());
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_Y_RESOLUTION));
|
||||
assertEquals(new Rational(30001, 100), ifd.getEntryById(TIFF.TAG_Y_RESOLUTION).getValue());
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT));
|
||||
assertEquals(TIFFBaseline.RESOLUTION_UNIT_DPI, ((Number) ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT).getValue()).intValue());
|
||||
|
||||
Node mergedTree = metadata.getAsTree(nativeFormat);
|
||||
NodeList fields = mergedTree.getFirstChild().getChildNodes();
|
||||
|
||||
// Validate there's one and only one resolution unit, x res and y res
|
||||
// Validate resolution unit == 1, x res & y res
|
||||
assertSingleNodeWithValue(fields, TIFF.TAG_RESOLUTION_UNIT, TIFF.TYPE_SHORT, String.valueOf(TIFFBaseline.RESOLUTION_UNIT_DPI));
|
||||
assertSingleNodeWithValue(fields, TIFF.TAG_X_RESOLUTION, TIFF.TYPE_RATIONAL, "300");
|
||||
assertSingleNodeWithValue(fields, TIFF.TAG_Y_RESOLUTION, TIFF.TYPE_RATIONAL, "30001/100");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTreeStandardFormat() throws IOException {
|
||||
TIFFImageMetadata metadata = (TIFFImageMetadata) createMetadata("/tiff/zackthecat.tif");
|
||||
|
||||
String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
|
||||
Node standardTree = metadata.getAsTree(standardFormat);
|
||||
assertNotNull(standardTree);
|
||||
|
||||
IIOMetadataNode newTree = new IIOMetadataNode(standardFormat);
|
||||
IIOMetadataNode dimensionNode = new IIOMetadataNode("Dimension");
|
||||
newTree.appendChild(dimensionNode);
|
||||
|
||||
IIOMetadataNode horizontalPixelSize = new IIOMetadataNode("HorizontalPixelSize");
|
||||
dimensionNode.appendChild(horizontalPixelSize);
|
||||
horizontalPixelSize.setAttribute("value", String.valueOf(300 / 25.4));
|
||||
|
||||
IIOMetadataNode verticalPixelSize = new IIOMetadataNode("VerticalPixelSize");
|
||||
dimensionNode.appendChild(verticalPixelSize);
|
||||
verticalPixelSize.setAttribute("value", String.valueOf(300 / 25.4));
|
||||
|
||||
metadata.mergeTree(standardFormat, newTree);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_X_RESOLUTION));
|
||||
assertEquals(new Rational(300), ifd.getEntryById(TIFF.TAG_X_RESOLUTION).getValue());
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_Y_RESOLUTION));
|
||||
assertEquals(new Rational(300), ifd.getEntryById(TIFF.TAG_Y_RESOLUTION).getValue());
|
||||
|
||||
// Should keep DPI as unit
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT));
|
||||
assertEquals(TIFFBaseline.RESOLUTION_UNIT_DPI, ((Number) ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT).getValue()).intValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeTreeStandardFormatAspectOnly() throws IOException {
|
||||
TIFFImageMetadata metadata = (TIFFImageMetadata) createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
|
||||
Node standardTree = metadata.getAsTree(standardFormat);
|
||||
assertNotNull(standardTree);
|
||||
|
||||
IIOMetadataNode newTree = new IIOMetadataNode(standardFormat);
|
||||
IIOMetadataNode dimensionNode = new IIOMetadataNode("Dimension");
|
||||
newTree.appendChild(dimensionNode);
|
||||
|
||||
IIOMetadataNode aspectRatio = new IIOMetadataNode("PixelAspectRatio");
|
||||
dimensionNode.appendChild(aspectRatio);
|
||||
aspectRatio.setAttribute("value", String.valueOf(3f / 2f));
|
||||
|
||||
metadata.mergeTree(standardFormat, newTree);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_X_RESOLUTION));
|
||||
assertEquals(new Rational(3, 2), ifd.getEntryById(TIFF.TAG_X_RESOLUTION).getValue());
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_Y_RESOLUTION));
|
||||
assertEquals(new Rational(1), ifd.getEntryById(TIFF.TAG_Y_RESOLUTION).getValue());
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT));
|
||||
assertEquals(TIFFBaseline.RESOLUTION_UNIT_NONE, ((Number) ifd.getEntryById(TIFF.TAG_RESOLUTION_UNIT).getValue()).intValue());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testMergeTreeUnsupportedFormat() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = "com_foo_bar_tiff_42";
|
||||
metadata.mergeTree(nativeFormat, new IIOMetadataNode(nativeFormat));
|
||||
}
|
||||
|
||||
@Test(expected = IIOInvalidTreeException.class)
|
||||
public void testMergeTreeFormatMisMatch() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
metadata.mergeTree(nativeFormat, new IIOMetadataNode("com_foo_bar_tiff_42"));
|
||||
}
|
||||
|
||||
@Test(expected = IIOInvalidTreeException.class)
|
||||
public void testMergeTreeInvalid() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
metadata.mergeTree(nativeFormat, new IIOMetadataNode(nativeFormat)); // Requires at least one child node
|
||||
}
|
||||
|
||||
// TODO: Test that failed merge leaves metadata unchanged
|
||||
|
||||
@Test
|
||||
public void testSetFromTreeEmpty() throws IOException {
|
||||
// Read from file, set empty to see that all is cleared
|
||||
TIFFImageMetadata metadata = (TIFFImageMetadata) createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
IIOMetadataNode root = new IIOMetadataNode(nativeFormat);
|
||||
root.appendChild(new IIOMetadataNode("TIFFIFD"));
|
||||
|
||||
metadata.setFromTree(nativeFormat, root);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
assertNotNull(ifd);
|
||||
assertEquals(0, ifd.size());
|
||||
|
||||
Node tree = metadata.getAsTree(nativeFormat);
|
||||
|
||||
assertNotNull(tree);
|
||||
assertNotNull(tree.getFirstChild());
|
||||
assertEquals(1, tree.getChildNodes().getLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFromTree() throws IOException {
|
||||
String softwareString = "12M UberTIFF 1.0";
|
||||
|
||||
TIFFImageMetadata metadata = new TIFFImageMetadata(Collections.<Entry>emptySet());
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
IIOMetadataNode root = new IIOMetadataNode(nativeFormat);
|
||||
|
||||
IIOMetadataNode ifdNode = new IIOMetadataNode("TIFFIFD");
|
||||
root.appendChild(ifdNode);
|
||||
|
||||
createTIFFFieldNode(ifdNode, TIFF.TAG_SOFTWARE, TIFF.TYPE_ASCII, softwareString);
|
||||
|
||||
metadata.setFromTree(nativeFormat, root);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
assertNotNull(ifd);
|
||||
assertEquals(1, ifd.size());
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_SOFTWARE));
|
||||
assertEquals(softwareString, ifd.getEntryById(TIFF.TAG_SOFTWARE).getValue());
|
||||
|
||||
Node tree = metadata.getAsTree(nativeFormat);
|
||||
|
||||
assertNotNull(tree);
|
||||
assertNotNull(tree.getFirstChild());
|
||||
assertEquals(1, tree.getChildNodes().getLength());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetFromTreeStandardFormat() throws IOException {
|
||||
String softwareString = "12M UberTIFF 1.0";
|
||||
String copyrightString = "Copyright (C) TwelveMonkeys, 2015";
|
||||
|
||||
TIFFImageMetadata metadata = new TIFFImageMetadata(Collections.<Entry>emptySet());
|
||||
|
||||
String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
IIOMetadataNode root = new IIOMetadataNode(standardFormat);
|
||||
|
||||
IIOMetadataNode textNode = new IIOMetadataNode("Text");
|
||||
root.appendChild(textNode);
|
||||
|
||||
IIOMetadataNode textEntry = new IIOMetadataNode("TextEntry");
|
||||
textNode.appendChild(textEntry);
|
||||
|
||||
textEntry.setAttribute("keyword", "SOFTWARE"); // Spelling should not matter
|
||||
textEntry.setAttribute("value", softwareString);
|
||||
|
||||
textEntry = new IIOMetadataNode("TextEntry");
|
||||
textNode.appendChild(textEntry);
|
||||
|
||||
textEntry.setAttribute("keyword", "copyright"); // Spelling should not matter
|
||||
textEntry.setAttribute("value", copyrightString);
|
||||
|
||||
metadata.setFromTree(standardFormat, root);
|
||||
|
||||
Directory ifd = metadata.getIFD();
|
||||
assertNotNull(ifd);
|
||||
assertEquals(2, ifd.size());
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_SOFTWARE));
|
||||
assertEquals(softwareString, ifd.getEntryById(TIFF.TAG_SOFTWARE).getValue());
|
||||
|
||||
assertNotNull(ifd.getEntryById(TIFF.TAG_COPYRIGHT));
|
||||
assertEquals(copyrightString, ifd.getEntryById(TIFF.TAG_COPYRIGHT).getValue());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testSetFromTreeUnsupportedFormat() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = "com_foo_bar_tiff_42";
|
||||
metadata.setFromTree(nativeFormat, new IIOMetadataNode(nativeFormat));
|
||||
}
|
||||
|
||||
@Test(expected = IIOInvalidTreeException.class)
|
||||
public void testSetFromTreeFormatMisMatch() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
metadata.setFromTree(nativeFormat, new IIOMetadataNode("com_foo_bar_tiff_42"));
|
||||
}
|
||||
|
||||
@Test(expected = IIOInvalidTreeException.class)
|
||||
public void testSetFromTreeInvalid() throws IOException {
|
||||
IIOMetadata metadata = createMetadata("/tiff/sm_colors_tile.tif");
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
metadata.setFromTree(nativeFormat, new IIOMetadataNode(nativeFormat)); // Requires at least one child node
|
||||
}
|
||||
|
||||
private void assertSingleNodeWithValue(final NodeList fields, final int tag, int type, final String... expectedValue) {
|
||||
String tagNumber = String.valueOf(tag);
|
||||
String typeName = StringUtil.capitalize(TIFF.TYPE_NAMES[type].toLowerCase());
|
||||
|
||||
boolean foundTag = false;
|
||||
|
||||
for (int i = 0; i < fields.getLength(); i++) {
|
||||
Element field = (Element) fields.item(i);
|
||||
|
||||
if (tagNumber.equals(field.getAttribute("number"))) {
|
||||
assertFalse("Duplicate tag " + tagNumber + " found", foundTag);
|
||||
|
||||
assertEquals(1, field.getChildNodes().getLength());
|
||||
Node containerNode = field.getFirstChild();
|
||||
assertEquals("TIFF" + typeName + "s", containerNode.getNodeName());
|
||||
|
||||
NodeList valueNodes = containerNode.getChildNodes();
|
||||
assertEquals("Unexpected number of values for tag " + tagNumber, expectedValue.length, valueNodes.getLength());
|
||||
|
||||
for (int j = 0; j < expectedValue.length; j++) {
|
||||
Element valueNode = (Element) valueNodes.item(j);
|
||||
assertEquals("TIFF" + typeName, valueNode.getNodeName());
|
||||
assertEquals("Unexpected tag " + tagNumber + " value", expectedValue[j], valueNode.getAttribute("value"));
|
||||
}
|
||||
|
||||
foundTag = true;
|
||||
}
|
||||
}
|
||||
|
||||
assertTrue("No tag " + tagNumber + " found", foundTag);
|
||||
}
|
||||
|
||||
// TODO: Test that failed set leaves metadata unchanged
|
||||
|
||||
static void createTIFFFieldNode(final IIOMetadataNode parentIFDNode, int tag, short type, Object value) {
|
||||
IIOMetadataNode fieldNode = new IIOMetadataNode("TIFFField");
|
||||
parentIFDNode.appendChild(fieldNode);
|
||||
|
||||
fieldNode.setAttribute("number", String.valueOf(tag));
|
||||
|
||||
switch (type) {
|
||||
case TIFF.TYPE_ASCII:
|
||||
createTIFFFieldContainerNode(fieldNode, "Ascii", value);
|
||||
break;
|
||||
case TIFF.TYPE_BYTE:
|
||||
createTIFFFieldContainerNode(fieldNode, "Byte", value);
|
||||
break;
|
||||
case TIFF.TYPE_SHORT:
|
||||
createTIFFFieldContainerNode(fieldNode, "Short", value);
|
||||
break;
|
||||
case TIFF.TYPE_RATIONAL:
|
||||
createTIFFFieldContainerNode(fieldNode, "Rational", value);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
static void createTIFFFieldContainerNode(final IIOMetadataNode fieldNode, final String type, final Object value) {
|
||||
IIOMetadataNode containerNode = new IIOMetadataNode("TIFF" + type + "s");
|
||||
fieldNode.appendChild(containerNode);
|
||||
|
||||
IIOMetadataNode valueNode = new IIOMetadataNode("TIFF" + type);
|
||||
valueNode.setAttribute("value", String.valueOf(value));
|
||||
containerNode.appendChild(valueNode);
|
||||
}
|
||||
|
||||
private void assertNodeNotEquals(final String message, final Node expected, final Node actual) {
|
||||
// Lame, lazy implementation...
|
||||
try {
|
||||
assertNodeEquals(message, expected, actual);
|
||||
}
|
||||
catch (AssertionError ignore) {
|
||||
return;
|
||||
}
|
||||
|
||||
fail(message);
|
||||
}
|
||||
|
||||
private void assertNodeEquals(final String message, final Node expected, final Node actual) {
|
||||
assertEquals(message + " class differs", expected.getClass(), actual.getClass());
|
||||
assertEquals(message, expected.getNodeValue(), actual.getNodeValue());
|
||||
|
||||
if (expected instanceof IIOMetadataNode) {
|
||||
IIOMetadataNode expectedIIO = (IIOMetadataNode) expected;
|
||||
IIOMetadataNode actualIIO = (IIOMetadataNode) actual;
|
||||
|
||||
assertEquals(message, expectedIIO.getUserObject(), actualIIO.getUserObject());
|
||||
}
|
||||
|
||||
NodeList expectedChildNodes = expected.getChildNodes();
|
||||
NodeList actualChildNodes = actual.getChildNodes();
|
||||
|
||||
assertEquals(message + " child length differs: " + toString(expectedChildNodes) + " != " + toString(actualChildNodes),
|
||||
expectedChildNodes.getLength(), actualChildNodes.getLength());
|
||||
|
||||
for (int i = 0; i < expectedChildNodes.getLength(); i++) {
|
||||
Node expectedChild = expectedChildNodes.item(i);
|
||||
Node actualChild = actualChildNodes.item(i);
|
||||
|
||||
assertEquals(message + " node name differs", expectedChild.getLocalName(), actualChild.getLocalName());
|
||||
assertNodeEquals(message + "/" + expectedChild.getLocalName(), expectedChild, actualChild);
|
||||
}
|
||||
}
|
||||
|
||||
private String toString(final NodeList list) {
|
||||
if (list.getLength() == 0) {
|
||||
return "[]";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder("[");
|
||||
for (int i = 0; i < list.getLength(); i++) {
|
||||
if (i > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
|
||||
Node node = list.item(i);
|
||||
builder.append(node.getLocalName());
|
||||
}
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
+39
-17
@@ -80,7 +80,22 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-long-strings-sample.tif"), new Dimension(316, 173)), // RGBA, LZW compressed w/predictor
|
||||
new TestData(getClassLoaderResource("/tiff/part.tif"), new Dimension(50, 50)), // Gray/BlackIsZero, uncompressed, striped signed int (SampleFormat 2)
|
||||
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg_no_profile.tif"), new Dimension(150, 63)), // CMYK, JPEG compressed, no ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)) // CMYK, JPEG compressed, with ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/cmyk_jpeg.tif"), new Dimension(100, 100)), // CMYK, JPEG compressed, with ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/grayscale-alpha.tiff"), new Dimension(248, 351)), // Gray + unassociated alpha
|
||||
new TestData(getClassLoaderResource("/tiff/signed-integral-8bit.tif"), new Dimension(439, 167)), // Gray, 8 bit *signed* integral
|
||||
new TestData(getClassLoaderResource("/tiff/floatingpoint-32bit.tif"), new Dimension(300, 100)), // RGB, 32 bit floating point
|
||||
new TestData(getClassLoaderResource("/tiff/general-cmm-error.tif"), new Dimension(1181, 860)), // RGB, LZW compression with broken/incompatible ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-rgba-padded-icc.tif"), new Dimension(19, 11)), // RGBA, LZW compression with padded ICC profile
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-rgba-4444.tif"), new Dimension(64, 64)), // RGBA, LZW compression with UINT 4/4/4/4 + gray 2/2
|
||||
new TestData(getClassLoaderResource("/tiff/lzw-buffer-overflow.tif"), new Dimension(5, 49)), // RGBA, LZW compression, will throw IOOBE if small buffer
|
||||
// CCITT
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_1d.tif"), new Dimension(6, 4)), // B/W, CCITT T4 1D
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_1d_fill.tif"), new Dimension(6, 4)), // B/W, CCITT T4 1D
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_2d.tif"), new Dimension(6, 4)), // B/W, CCITT T4 2D
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_2d_fill.tif"), new Dimension(6, 4)), // B/W, CCITT T4 2D
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group3_2d_lsb2msb.tif"), new Dimension(6, 4)), // B/W, CCITT T4 2D, LSB
|
||||
new TestData(getClassLoaderResource("/tiff/ccitt/group4.tif"), new Dimension(6, 4)), // B/W, CCITT T6 1D
|
||||
new TestData(getClassLoaderResource("/tiff/fivepages-scan-causingerrors.tif"), new Dimension(2480, 3518)) // B/W, CCITT T4
|
||||
);
|
||||
}
|
||||
|
||||
@@ -141,9 +156,8 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
@Test
|
||||
public void testReadOldStyleJPEGGrayscale() throws IOException {
|
||||
TestData testData = new TestData(getClassLoaderResource("/tiff/grayscale-old-style-jpeg.tiff"), new Dimension(600, 600));
|
||||
ImageInputStream stream = testData.getInputStream();
|
||||
|
||||
try {
|
||||
try (ImageInputStream stream = testData.getInputStream()) {
|
||||
TIFFImageReader reader = createReader();
|
||||
reader.setInput(stream);
|
||||
BufferedImage image = reader.read(0);
|
||||
@@ -151,18 +165,13 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
assertNotNull(image);
|
||||
assertEquals(testData.getDimension(0), new Dimension(image.getWidth(), image.getHeight()));
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadIncompatibleICCProfileIgnoredWithWarning() throws IOException {
|
||||
TestData testData = new TestData(getClassLoaderResource("/tiff/rgb-with-embedded-cmyk-icc.tif"), new Dimension(1500, 1500));
|
||||
|
||||
ImageInputStream stream = testData.getInputStream();
|
||||
|
||||
try {
|
||||
try (ImageInputStream stream = testData.getInputStream()) {
|
||||
TIFFImageReader reader = createReader();
|
||||
reader.setInput(stream);
|
||||
|
||||
@@ -175,18 +184,13 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
assertEquals(testData.getDimension(0), new Dimension(image.getWidth(), image.getHeight()));
|
||||
verify(warningListener, atLeastOnce()).warningOccurred(eq(reader), contains("ICC"));
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColorMap8Bit() throws IOException {
|
||||
TestData testData = new TestData(getClassLoaderResource("/tiff/scan-lzw-8bit-colormap.tiff"), new Dimension(2550, 3300));
|
||||
|
||||
ImageInputStream stream = testData.getInputStream();
|
||||
|
||||
try {
|
||||
try (ImageInputStream stream = testData.getInputStream()) {
|
||||
TIFFImageReader reader = createReader();
|
||||
reader.setInput(stream);
|
||||
|
||||
@@ -202,8 +206,26 @@ public class TIFFImageReaderTest extends ImageReaderAbstractTest<TIFFImageReader
|
||||
assertEquals(0xffffffff, image.getRGB(0, 0)); // The pixel at 0, 0 should be white, not black
|
||||
verify(warningListener, atLeastOnce()).warningOccurred(eq(reader), contains("ColorMap"));
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadICCProfile() throws IOException {
|
||||
TestData testData = new TestData(getClassLoaderResource("/tiff/general-cmm-error.tif"), new Dimension(1181, 864));
|
||||
|
||||
try (ImageInputStream stream = testData.getInputStream()) {
|
||||
TIFFImageReader reader = createReader();
|
||||
reader.setInput(stream);
|
||||
|
||||
IIOReadWarningListener warningListener = mock(IIOReadWarningListener.class);
|
||||
reader.addIIOReadWarningListener(warningListener);
|
||||
|
||||
ImageReadParam param = reader.getDefaultReadParam();
|
||||
param.setSourceRegion(new Rectangle(8, 8));
|
||||
BufferedImage image = reader.read(0, param);
|
||||
|
||||
assertNotNull(image);
|
||||
assertEquals(new Dimension(8, 8), new Dimension(image.getWidth(), image.getHeight()));
|
||||
verify(warningListener, atLeastOnce()).warningOccurred(eq(reader), contains("ICC profile"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+219
-12
@@ -28,15 +28,33 @@
|
||||
|
||||
package com.twelvemonkeys.imageio.plugins.tiff;
|
||||
|
||||
import com.twelvemonkeys.imageio.metadata.Directory;
|
||||
import com.twelvemonkeys.imageio.metadata.Entry;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.EXIFReader;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.Rational;
|
||||
import com.twelvemonkeys.imageio.metadata.exif.TIFF;
|
||||
import com.twelvemonkeys.imageio.stream.ByteArrayImageInputStream;
|
||||
import com.twelvemonkeys.imageio.util.ImageWriterAbstractTestCase;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.imageio.IIOImage;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.ImageWriter;
|
||||
import java.awt.*;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.stream.ImageOutputStream;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.twelvemonkeys.imageio.plugins.tiff.TIFFImageMetadataTest.createTIFFFieldNode;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* TIFFImageWriterTest
|
||||
*
|
||||
@@ -55,19 +73,208 @@ public class TIFFImageWriterTest extends ImageWriterAbstractTestCase {
|
||||
|
||||
@Override
|
||||
protected List<? extends RenderedImage> getTestData() {
|
||||
BufferedImage image = new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D graphics = image.createGraphics();
|
||||
try {
|
||||
graphics.setColor(Color.RED);
|
||||
graphics.fillRect(0, 0, 100, 200);
|
||||
graphics.setColor(Color.BLUE);
|
||||
graphics.fillRect(100, 0, 100, 200);
|
||||
graphics.clearRect(200, 0, 100, 200);
|
||||
return Arrays.asList(
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_INT_RGB),
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_INT_ARGB),
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_3BYTE_BGR),
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_4BYTE_ABGR),
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_BYTE_GRAY),
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_USHORT_GRAY),
|
||||
// new BufferedImage(300, 200, BufferedImage.TYPE_BYTE_BINARY), // TODO!
|
||||
new BufferedImage(300, 200, BufferedImage.TYPE_BYTE_INDEXED)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Test write bilevel stays bilevel
|
||||
// TODO: Test write indexed stays indexed
|
||||
|
||||
@Test
|
||||
public void testWriteWithCustomResolutionNative() throws IOException {
|
||||
// Issue 139 Writing TIFF files with custom resolution value
|
||||
Rational resolutionValue = new Rational(1200);
|
||||
int resolutionUnitValue = TIFFBaseline.RESOLUTION_UNIT_CENTIMETER;
|
||||
|
||||
RenderedImage image = getTestData(0);
|
||||
|
||||
ImageWriter writer = createImageWriter();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
||||
writer.setOutput(stream);
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), null);
|
||||
|
||||
IIOMetadataNode customMeta = new IIOMetadataNode(nativeFormat);
|
||||
|
||||
IIOMetadataNode ifd = new IIOMetadataNode("TIFFIFD");
|
||||
customMeta.appendChild(ifd);
|
||||
|
||||
createTIFFFieldNode(ifd, TIFF.TAG_RESOLUTION_UNIT, TIFF.TYPE_SHORT, resolutionUnitValue);
|
||||
createTIFFFieldNode(ifd, TIFF.TAG_X_RESOLUTION, TIFF.TYPE_RATIONAL, resolutionValue);
|
||||
createTIFFFieldNode(ifd, TIFF.TAG_Y_RESOLUTION, TIFF.TYPE_RATIONAL, resolutionValue);
|
||||
|
||||
metadata.mergeTree(nativeFormat, customMeta);
|
||||
|
||||
writer.write(null, new IIOImage(image, null, metadata), null);
|
||||
}
|
||||
finally {
|
||||
graphics.dispose();
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
return Arrays.asList(image);
|
||||
assertTrue("No image data written", buffer.size() > 0);
|
||||
|
||||
Directory ifds = new EXIFReader().read(new ByteArrayImageInputStream(buffer.toByteArray()));
|
||||
|
||||
Entry resolutionUnit = ifds.getEntryById(TIFF.TAG_RESOLUTION_UNIT);
|
||||
assertNotNull(resolutionUnit);
|
||||
assertEquals(resolutionUnitValue, ((Number) resolutionUnit.getValue()).intValue());
|
||||
|
||||
Entry xResolution = ifds.getEntryById(TIFF.TAG_X_RESOLUTION);
|
||||
assertNotNull(xResolution);
|
||||
assertEquals(resolutionValue, xResolution.getValue());
|
||||
|
||||
Entry yResolution = ifds.getEntryById(TIFF.TAG_Y_RESOLUTION);
|
||||
assertNotNull(yResolution);
|
||||
assertEquals(resolutionValue, yResolution.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteWithCustomSoftwareNative() throws IOException {
|
||||
String softwareString = "12M TIFF Test 1.0 (build $foo$)";
|
||||
|
||||
RenderedImage image = getTestData(0);
|
||||
|
||||
ImageWriter writer = createImageWriter();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
||||
writer.setOutput(stream);
|
||||
|
||||
String nativeFormat = TIFFMedataFormat.SUN_NATIVE_IMAGE_METADATA_FORMAT_NAME;
|
||||
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), null);
|
||||
|
||||
IIOMetadataNode customMeta = new IIOMetadataNode(nativeFormat);
|
||||
|
||||
IIOMetadataNode ifd = new IIOMetadataNode("TIFFIFD");
|
||||
customMeta.appendChild(ifd);
|
||||
|
||||
createTIFFFieldNode(ifd, TIFF.TAG_SOFTWARE, TIFF.TYPE_ASCII, softwareString);
|
||||
|
||||
metadata.mergeTree(nativeFormat, customMeta);
|
||||
|
||||
writer.write(null, new IIOImage(image, null, metadata), null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("No image data written", buffer.size() > 0);
|
||||
|
||||
Directory ifds = new EXIFReader().read(new ByteArrayImageInputStream(buffer.toByteArray()));
|
||||
Entry software = ifds.getEntryById(TIFF.TAG_SOFTWARE);
|
||||
assertNotNull(software);
|
||||
assertEquals(softwareString, software.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteWithCustomResolutionStandard() throws IOException {
|
||||
// Issue 139 Writing TIFF files with custom resolution value
|
||||
double resolutionValue = 300 / 25.4; // 300 dpi, 1 inch = 2.54 cm or 25.4 mm
|
||||
int resolutionUnitValue = TIFFBaseline.RESOLUTION_UNIT_CENTIMETER;
|
||||
Rational expectedResolutionValue = new Rational(Math.round(resolutionValue * 10 * TIFFImageMetadata.RATIONAL_SCALE_FACTOR), TIFFImageMetadata.RATIONAL_SCALE_FACTOR);
|
||||
|
||||
RenderedImage image = getTestData(0);
|
||||
|
||||
ImageWriter writer = createImageWriter();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
||||
writer.setOutput(stream);
|
||||
|
||||
String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), null);
|
||||
|
||||
IIOMetadataNode customMeta = new IIOMetadataNode(standardFormat);
|
||||
|
||||
IIOMetadataNode dimension = new IIOMetadataNode("Dimension");
|
||||
customMeta.appendChild(dimension);
|
||||
|
||||
IIOMetadataNode xSize = new IIOMetadataNode("HorizontalPixelSize");
|
||||
dimension.appendChild(xSize);
|
||||
xSize.setAttribute("value", String.valueOf(resolutionValue));
|
||||
|
||||
IIOMetadataNode ySize = new IIOMetadataNode("VerticalPixelSize");
|
||||
dimension.appendChild(ySize);
|
||||
ySize.setAttribute("value", String.valueOf(resolutionValue));
|
||||
|
||||
metadata.mergeTree(standardFormat, customMeta);
|
||||
|
||||
writer.write(null, new IIOImage(image, null, metadata), null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("No image data written", buffer.size() > 0);
|
||||
|
||||
Directory ifds = new EXIFReader().read(new ByteArrayImageInputStream(buffer.toByteArray()));
|
||||
|
||||
Entry resolutionUnit = ifds.getEntryById(TIFF.TAG_RESOLUTION_UNIT);
|
||||
assertNotNull(resolutionUnit);
|
||||
assertEquals(resolutionUnitValue, ((Number) resolutionUnit.getValue()).intValue());
|
||||
|
||||
Entry xResolution = ifds.getEntryById(TIFF.TAG_X_RESOLUTION);
|
||||
assertNotNull(xResolution);
|
||||
assertEquals(expectedResolutionValue, xResolution.getValue());
|
||||
|
||||
Entry yResolution = ifds.getEntryById(TIFF.TAG_Y_RESOLUTION);
|
||||
assertNotNull(yResolution);
|
||||
assertEquals(expectedResolutionValue, yResolution.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteWithCustomSoftwareStandard() throws IOException {
|
||||
String softwareString = "12M TIFF Test 1.0 (build $foo$)";
|
||||
|
||||
RenderedImage image = getTestData(0);
|
||||
|
||||
ImageWriter writer = createImageWriter();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
try (ImageOutputStream stream = ImageIO.createImageOutputStream(buffer)) {
|
||||
writer.setOutput(stream);
|
||||
|
||||
String standardFormat = IIOMetadataFormatImpl.standardMetadataFormatName;
|
||||
IIOMetadata metadata = writer.getDefaultImageMetadata(ImageTypeSpecifier.createFromRenderedImage(image), null);
|
||||
|
||||
IIOMetadataNode customMeta = new IIOMetadataNode(standardFormat);
|
||||
|
||||
IIOMetadataNode dimension = new IIOMetadataNode("Text");
|
||||
customMeta.appendChild(dimension);
|
||||
|
||||
IIOMetadataNode textEntry = new IIOMetadataNode("TextEntry");
|
||||
dimension.appendChild(textEntry);
|
||||
textEntry.setAttribute("keyword", "Software");
|
||||
textEntry.setAttribute("value", softwareString);
|
||||
|
||||
metadata.mergeTree(standardFormat, customMeta);
|
||||
|
||||
writer.write(null, new IIOImage(image, null, metadata), null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
fail(e.getMessage());
|
||||
}
|
||||
|
||||
assertTrue("No image data written", buffer.size() > 0);
|
||||
|
||||
Directory ifds = new EXIFReader().read(new ByteArrayImageInputStream(buffer.toByteArray()));
|
||||
Entry software = ifds.getEntryById(TIFF.TAG_SOFTWARE);
|
||||
assertNotNull(software);
|
||||
assertEquals(softwareString, software.getValueAsString());
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user