From b9b1a354087faafc6f80bca510a03556a3aaeedf Mon Sep 17 00:00:00 2001 From: Harald Kuhr Date: Mon, 10 Oct 2022 14:15:57 +0200 Subject: [PATCH] Replaced Map.Entry with StandardImageMetadataSupport.TextEntry --- .../imageio/StandardImageMetadataSupport.java | 63 ++++++++++++++++--- .../StandardImageMetadataSupportTest.java | 61 +++++++++++------- .../imageio/plugins/iff/IFFImageMetadata.java | 10 ++- 3 files changed, 97 insertions(+), 37 deletions(-) diff --git a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/StandardImageMetadataSupport.java b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/StandardImageMetadataSupport.java index 99c89fc7..9b6793ec 100644 --- a/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/StandardImageMetadataSupport.java +++ b/imageio/imageio-core/src/main/java/com/twelvemonkeys/imageio/StandardImageMetadataSupport.java @@ -6,10 +6,11 @@ import javax.imageio.metadata.IIOMetadataNode; import java.awt.*; import java.awt.color.*; import java.awt.image.*; -import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; +import java.util.List; import java.util.Map; import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.ColorSpaceType.*; @@ -42,7 +43,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata { protected final String formatVersion; protected final SubimageInterpretation subimageInterpretation; private final Calendar documentCreationTime; // TODO: This field should be a LocalDateTime or other java.time type, Consider a long timestamp + TimeZone to avoid messing up the API... - private final Collection> textEntries; + private final Collection textEntries; protected StandardImageMetadataSupport(Builder builder) { notNull(builder, "builder"); @@ -98,7 +99,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata { private String formatVersion; private SubimageInterpretation subimageInterpretation; private Calendar documentCreationTime; // TODO: This field should be a LocalDateTime or other java.time type - private final Collection> textEntries = new ArrayList<>(); + private final Collection textEntries = new ArrayList<>(); protected Builder(ImageTypeSpecifier type) { this.type = notNull(type, "type"); @@ -193,10 +194,21 @@ public class StandardImageMetadataSupport extends AbstractMetadata { } public Builder withTextEntries(Map entries) { - return withTextEntries(notNull(entries, "entries").entrySet()); + return withTextEntries(toTextEntries(notNull(entries, "entries").entrySet())); } - public Builder withTextEntries(Collection> entries) { + private Collection toTextEntries(Collection> entries) { + TextEntry[] result = new TextEntry[entries.size()]; + + int i = 0; + for (Map.Entry entry : entries) { + result[i++] = new TextEntry(entry.getKey(), entry.getValue()); + } + + return Arrays.asList(result); + } + + public Builder withTextEntries(Collection entries) { this.textEntries.addAll(notNull(entries, "entries")); return this; @@ -204,7 +216,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata { public Builder withTextEntry(String keyword, String value) { if (value != null && !value.isEmpty()) { - this.textEntries.add(new SimpleImmutableEntry<>(notNull(keyword, "keyword"), value)); + this.textEntries.add(new TextEntry(notNull(keyword, "keyword"), value)); } return this; @@ -389,6 +401,28 @@ public class StandardImageMetadataSupport extends AbstractMetadata { throw new IllegalArgumentException("Unknown ColorSpace type: " + colorSpace); } + protected static final class TextEntry { + static final List COMPRESSIONS = Arrays.asList("none", "lzw", "zip", "bzip", "other"); + + final String keyword; + final String value; + final String language; + final String encoding; + final String compression; + + public TextEntry(final String keyword, final String value) { + this(keyword, value, null, null, null); + } + + public TextEntry(final String keyword, final String value, final String language, final String encoding, final String compression) { + this.keyword = keyword; + this.value = notNull(value, "value"); + this.language = language; + this.encoding = encoding; + this.compression = isTrue(compression == null || COMPRESSIONS.contains(compression), compression, String.format("Unknown compression: %s (expected: %s)", compression, COMPRESSIONS)); + } + } + @Override protected IIOMetadataNode getStandardCompressionNode() { if (compressionName == null) { @@ -547,11 +581,22 @@ public class StandardImageMetadataSupport extends AbstractMetadata { // DocumentName, ImageDescription, Make, Model, PageName, Software, Artist, HostComputer, InkNames, Copyright: // /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value. - for (Map.Entry entry : textEntries) { + for (TextEntry entry : textEntries) { IIOMetadataNode textEntryNode = new IIOMetadataNode("TextEntry"); textNode.appendChild(textEntryNode); - textEntryNode.setAttribute("keyword", entry.getKey()); - textEntryNode.setAttribute("value", entry.getValue()); + if (entry.keyword != null) { + textEntryNode.setAttribute("keyword", entry.keyword); + } + textEntryNode.setAttribute("value", entry.value); + if (entry.language != null) { + textEntryNode.setAttribute("language", entry.language); + } + if (entry.encoding != null) { + textEntryNode.setAttribute("encoding", entry.encoding); + } + if (entry.compression != null) { + textEntryNode.setAttribute("compression", entry.compression); + } } return textNode; diff --git a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/StandardImageMetadataSupportTest.java b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/StandardImageMetadataSupportTest.java index 8e02c312..efb41a9f 100644 --- a/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/StandardImageMetadataSupportTest.java +++ b/imageio/imageio-core/src/test/java/com/twelvemonkeys/imageio/StandardImageMetadataSupportTest.java @@ -4,6 +4,7 @@ import com.twelvemonkeys.imageio.StandardImageMetadataSupport.ColorSpaceType; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.ImageOrientation; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.PlanarConfiguration; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.SubimageInterpretation; +import com.twelvemonkeys.imageio.StandardImageMetadataSupport.TextEntry; import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers; import org.junit.Test; @@ -12,7 +13,6 @@ import org.w3c.dom.NodeList; import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadataNode; import java.awt.image.*; -import java.util.AbstractMap.SimpleEntry; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; @@ -22,10 +22,7 @@ import java.util.Map; import java.util.Map.Entry; import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.builder; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; public class StandardImageMetadataSupportTest { @Test(expected = IllegalArgumentException.class) @@ -52,7 +49,8 @@ public class StandardImageMetadataSupportTest { @Test public void builderValid() { IIOMetadata metadata = builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB)) - .build(); + .build(); + assertNotNull(metadata); } @@ -198,11 +196,12 @@ public class StandardImageMetadataSupportTest { @Test public void withTextValuesList() { - List> entries = Arrays.>asList( - new SimpleEntry<>((String) null, "foo"), // No key allowed - new SimpleEntry<>("foo", "bar"), - new SimpleEntry<>("bar", "xyzzy"), - new SimpleEntry<>("bar", "nothing happens...") // Duplicates allowed + List entries = Arrays.asList( + new TextEntry(null, "foo"), // No key allowed + new TextEntry("foo", "bar"), + new TextEntry("bar", "xyzzy"), + new TextEntry("bar", "nothing happens..."), // Duplicates allowed + new TextEntry("everything", "válüè", "unknown", "UTF-8", "zip") ); StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)) @@ -216,11 +215,25 @@ public class StandardImageMetadataSupportTest { assertEquals(entries.size(), textEntries.getLength()); for (int i = 0; i < entries.size(); i++) { - Entry entry = entries.get(i); + TextEntry entry = entries.get(i); IIOMetadataNode textEntry = (IIOMetadataNode) textEntries.item(i); - assertEquals(entry.getKey(), textEntry.getAttribute("keyword")); - assertEquals(entry.getValue(), textEntry.getAttribute("value")); + assertAttributeEqualOrAbsent(entry.keyword, textEntry, "keyword"); + + assertEquals(entry.value, textEntry.getAttribute("value")); + + assertAttributeEqualOrAbsent(entry.language, textEntry, "language"); + assertAttributeEqualOrAbsent(entry.encoding, textEntry, "encoding"); + assertAttributeEqualOrAbsent(entry.compression, textEntry, "compression"); + } + } + + private static void assertAttributeEqualOrAbsent(final String expectedValue, IIOMetadataNode node, final String attribute) { + if (expectedValue != null) { + assertEquals(expectedValue, node.getAttribute(attribute)); + } + else { + assertFalse(node.hasAttribute(attribute)); } } @@ -236,8 +249,9 @@ public class StandardImageMetadataSupportTest { for (ColorSpaceType value : ColorSpaceType.values()) { StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)) - .withColorSpaceType(value) - .build(); + .withColorSpaceType(value) + .build(); + assertNotNull(metadata); IIOMetadataNode documentNode = metadata.getStandardChromaNode(); @@ -256,8 +270,9 @@ public class StandardImageMetadataSupportTest { for (PlanarConfiguration value : PlanarConfiguration.values()) { StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)) - .withPlanarConfiguration(value) - .build(); + .withPlanarConfiguration(value) + .build(); + assertNotNull(metadata); IIOMetadataNode documentNode = metadata.getStandardDataNode(); @@ -276,8 +291,9 @@ public class StandardImageMetadataSupportTest { for (ImageOrientation value : ImageOrientation.values()) { StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)) - .withOrientation(value) - .build(); + .withOrientation(value) + .build(); + assertNotNull(metadata); IIOMetadataNode documentNode = metadata.getStandardDimensionNode(); @@ -300,8 +316,9 @@ public class StandardImageMetadataSupportTest { for (SubimageInterpretation value : SubimageInterpretation.values()) { StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB)) - .withSubimageInterpretation(value) - .build(); + .withSubimageInterpretation(value) + .build(); + assertNotNull(metadata); IIOMetadataNode documentNode = metadata.getStandardDocumentNode(); diff --git a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageMetadata.java b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageMetadata.java index 007513af..59ea7abd 100644 --- a/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageMetadata.java +++ b/imageio/imageio-iff/src/main/java/com/twelvemonkeys/imageio/plugins/iff/IFFImageMetadata.java @@ -35,10 +35,8 @@ import com.twelvemonkeys.imageio.StandardImageMetadataSupport; import javax.imageio.ImageTypeSpecifier; import java.awt.image.*; import java.nio.charset.StandardCharsets; -import java.util.AbstractMap.SimpleImmutableEntry; import java.util.ArrayList; import java.util.List; -import java.util.Map; import static com.twelvemonkeys.imageio.plugins.iff.IFF.*; import static com.twelvemonkeys.imageio.plugins.iff.IFFUtil.toChunkStr; @@ -119,15 +117,15 @@ final class IFFImageMetadata extends StandardImageMetadataSupport { } } - private static List> textEntries(Form header) { + private static List textEntries(Form header) { if (header.meta.isEmpty()) { return emptyList(); } - List> text = new ArrayList<>(); + List text = new ArrayList<>(); for (GenericChunk chunk : header.meta) { - text.add(new SimpleImmutableEntry<>(toChunkStr(chunk.chunkId), - new String(chunk.data, chunk.chunkId == IFF.CHUNK_UTF8 ? StandardCharsets.UTF_8 : StandardCharsets.US_ASCII))); + text.add(new TextEntry(toChunkStr(chunk.chunkId), + new String(chunk.data, chunk.chunkId == IFF.CHUNK_UTF8 ? StandardCharsets.UTF_8:StandardCharsets.US_ASCII))); } return text;