Replaced Map.Entry with StandardImageMetadataSupport.TextEntry

This commit is contained in:
Harald Kuhr 2022-10-10 14:15:57 +02:00
parent 7ed5663633
commit b9b1a35408
3 changed files with 97 additions and 37 deletions

View File

@ -6,10 +6,11 @@ import javax.imageio.metadata.IIOMetadataNode;
import java.awt.*; import java.awt.*;
import java.awt.color.*; import java.awt.color.*;
import java.awt.image.*; import java.awt.image.*;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Map; import java.util.Map;
import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.ColorSpaceType.*; import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.ColorSpaceType.*;
@ -42,7 +43,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
protected final String formatVersion; protected final String formatVersion;
protected final SubimageInterpretation subimageInterpretation; 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 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<Map.Entry<String, String>> textEntries; private final Collection<TextEntry> textEntries;
protected StandardImageMetadataSupport(Builder builder) { protected StandardImageMetadataSupport(Builder builder) {
notNull(builder, "builder"); notNull(builder, "builder");
@ -98,7 +99,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
private String formatVersion; private String formatVersion;
private SubimageInterpretation subimageInterpretation; private SubimageInterpretation subimageInterpretation;
private Calendar documentCreationTime; // TODO: This field should be a LocalDateTime or other java.time type private Calendar documentCreationTime; // TODO: This field should be a LocalDateTime or other java.time type
private final Collection<Map.Entry<String, String>> textEntries = new ArrayList<>(); private final Collection<TextEntry> textEntries = new ArrayList<>();
protected Builder(ImageTypeSpecifier type) { protected Builder(ImageTypeSpecifier type) {
this.type = notNull(type, "type"); this.type = notNull(type, "type");
@ -193,10 +194,21 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
} }
public Builder withTextEntries(Map<String, String> entries) { public Builder withTextEntries(Map<String, String> entries) {
return withTextEntries(notNull(entries, "entries").entrySet()); return withTextEntries(toTextEntries(notNull(entries, "entries").entrySet()));
} }
public Builder withTextEntries(Collection<Map.Entry<String, String>> entries) { private Collection<TextEntry> toTextEntries(Collection<Map.Entry<String, String>> entries) {
TextEntry[] result = new TextEntry[entries.size()];
int i = 0;
for (Map.Entry<String, String> entry : entries) {
result[i++] = new TextEntry(entry.getKey(), entry.getValue());
}
return Arrays.asList(result);
}
public Builder withTextEntries(Collection<TextEntry> entries) {
this.textEntries.addAll(notNull(entries, "entries")); this.textEntries.addAll(notNull(entries, "entries"));
return this; return this;
@ -204,7 +216,7 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
public Builder withTextEntry(String keyword, String value) { public Builder withTextEntry(String keyword, String value) {
if (value != null && !value.isEmpty()) { 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; return this;
@ -389,6 +401,28 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
throw new IllegalArgumentException("Unknown ColorSpace type: " + colorSpace); throw new IllegalArgumentException("Unknown ColorSpace type: " + colorSpace);
} }
protected static final class TextEntry {
static final List<String> 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 @Override
protected IIOMetadataNode getStandardCompressionNode() { protected IIOMetadataNode getStandardCompressionNode() {
if (compressionName == null) { if (compressionName == null) {
@ -547,11 +581,22 @@ public class StandardImageMetadataSupport extends AbstractMetadata {
// DocumentName, ImageDescription, Make, Model, PageName, Software, Artist, HostComputer, InkNames, Copyright: // DocumentName, ImageDescription, Make, Model, PageName, Software, Artist, HostComputer, InkNames, Copyright:
// /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value. // /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value.
for (Map.Entry<String, String> entry : textEntries) { for (TextEntry entry : textEntries) {
IIOMetadataNode textEntryNode = new IIOMetadataNode("TextEntry"); IIOMetadataNode textEntryNode = new IIOMetadataNode("TextEntry");
textNode.appendChild(textEntryNode); textNode.appendChild(textEntryNode);
textEntryNode.setAttribute("keyword", entry.getKey()); if (entry.keyword != null) {
textEntryNode.setAttribute("value", entry.getValue()); 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; return textNode;

View File

@ -4,6 +4,7 @@ import com.twelvemonkeys.imageio.StandardImageMetadataSupport.ColorSpaceType;
import com.twelvemonkeys.imageio.StandardImageMetadataSupport.ImageOrientation; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.ImageOrientation;
import com.twelvemonkeys.imageio.StandardImageMetadataSupport.PlanarConfiguration; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.PlanarConfiguration;
import com.twelvemonkeys.imageio.StandardImageMetadataSupport.SubimageInterpretation; import com.twelvemonkeys.imageio.StandardImageMetadataSupport.SubimageInterpretation;
import com.twelvemonkeys.imageio.StandardImageMetadataSupport.TextEntry;
import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers; import com.twelvemonkeys.imageio.util.ImageTypeSpecifiers;
import org.junit.Test; import org.junit.Test;
@ -12,7 +13,6 @@ import org.w3c.dom.NodeList;
import javax.imageio.metadata.IIOMetadata; import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataNode; import javax.imageio.metadata.IIOMetadataNode;
import java.awt.image.*; import java.awt.image.*;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Collection; import java.util.Collection;
@ -22,10 +22,7 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.builder; import static com.twelvemonkeys.imageio.StandardImageMetadataSupport.builder;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class StandardImageMetadataSupportTest { public class StandardImageMetadataSupportTest {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
@ -53,6 +50,7 @@ public class StandardImageMetadataSupportTest {
public void builderValid() { public void builderValid() {
IIOMetadata metadata = builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB)) IIOMetadata metadata = builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_ARGB))
.build(); .build();
assertNotNull(metadata); assertNotNull(metadata);
} }
@ -198,11 +196,12 @@ public class StandardImageMetadataSupportTest {
@Test @Test
public void withTextValuesList() { public void withTextValuesList() {
List<Entry<String, String>> entries = Arrays.<Entry<String, String>>asList( List<TextEntry> entries = Arrays.asList(
new SimpleEntry<>((String) null, "foo"), // No key allowed new TextEntry(null, "foo"), // No key allowed
new SimpleEntry<>("foo", "bar"), new TextEntry("foo", "bar"),
new SimpleEntry<>("bar", "xyzzy"), new TextEntry("bar", "xyzzy"),
new SimpleEntry<>("bar", "nothing happens...") // Duplicates allowed 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)) StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY))
@ -216,11 +215,25 @@ public class StandardImageMetadataSupportTest {
assertEquals(entries.size(), textEntries.getLength()); assertEquals(entries.size(), textEntries.getLength());
for (int i = 0; i < entries.size(); i++) { for (int i = 0; i < entries.size(); i++) {
Entry<String, String> entry = entries.get(i); TextEntry entry = entries.get(i);
IIOMetadataNode textEntry = (IIOMetadataNode) textEntries.item(i); IIOMetadataNode textEntry = (IIOMetadataNode) textEntries.item(i);
assertEquals(entry.getKey(), textEntry.getAttribute("keyword")); assertAttributeEqualOrAbsent(entry.keyword, textEntry, "keyword");
assertEquals(entry.getValue(), textEntry.getAttribute("value"));
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));
} }
} }
@ -238,6 +251,7 @@ public class StandardImageMetadataSupportTest {
StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)) StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY))
.withColorSpaceType(value) .withColorSpaceType(value)
.build(); .build();
assertNotNull(metadata); assertNotNull(metadata);
IIOMetadataNode documentNode = metadata.getStandardChromaNode(); IIOMetadataNode documentNode = metadata.getStandardChromaNode();
@ -258,6 +272,7 @@ public class StandardImageMetadataSupportTest {
StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR)) StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_3BYTE_BGR))
.withPlanarConfiguration(value) .withPlanarConfiguration(value)
.build(); .build();
assertNotNull(metadata); assertNotNull(metadata);
IIOMetadataNode documentNode = metadata.getStandardDataNode(); IIOMetadataNode documentNode = metadata.getStandardDataNode();
@ -278,6 +293,7 @@ public class StandardImageMetadataSupportTest {
StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY)) StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY))
.withOrientation(value) .withOrientation(value)
.build(); .build();
assertNotNull(metadata); assertNotNull(metadata);
IIOMetadataNode documentNode = metadata.getStandardDimensionNode(); IIOMetadataNode documentNode = metadata.getStandardDimensionNode();
@ -302,6 +318,7 @@ public class StandardImageMetadataSupportTest {
StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB)) StandardImageMetadataSupport metadata = (StandardImageMetadataSupport) builder(ImageTypeSpecifiers.createFromBufferedImageType(BufferedImage.TYPE_INT_RGB))
.withSubimageInterpretation(value) .withSubimageInterpretation(value)
.build(); .build();
assertNotNull(metadata); assertNotNull(metadata);
IIOMetadataNode documentNode = metadata.getStandardDocumentNode(); IIOMetadataNode documentNode = metadata.getStandardDocumentNode();

View File

@ -35,10 +35,8 @@ import com.twelvemonkeys.imageio.StandardImageMetadataSupport;
import javax.imageio.ImageTypeSpecifier; import javax.imageio.ImageTypeSpecifier;
import java.awt.image.*; import java.awt.image.*;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.AbstractMap.SimpleImmutableEntry;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import static com.twelvemonkeys.imageio.plugins.iff.IFF.*; import static com.twelvemonkeys.imageio.plugins.iff.IFF.*;
import static com.twelvemonkeys.imageio.plugins.iff.IFFUtil.toChunkStr; import static com.twelvemonkeys.imageio.plugins.iff.IFFUtil.toChunkStr;
@ -119,15 +117,15 @@ final class IFFImageMetadata extends StandardImageMetadataSupport {
} }
} }
private static List<Map.Entry<String, String>> textEntries(Form header) { private static List<TextEntry> textEntries(Form header) {
if (header.meta.isEmpty()) { if (header.meta.isEmpty()) {
return emptyList(); return emptyList();
} }
List<Map.Entry<String, String>> text = new ArrayList<>(); List<TextEntry> text = new ArrayList<>();
for (GenericChunk chunk : header.meta) { for (GenericChunk chunk : header.meta) {
text.add(new SimpleImmutableEntry<>(toChunkStr(chunk.chunkId), text.add(new TextEntry(toChunkStr(chunk.chunkId),
new String(chunk.data, chunk.chunkId == IFF.CHUNK_UTF8 ? StandardCharsets.UTF_8 : StandardCharsets.US_ASCII))); new String(chunk.data, chunk.chunkId == IFF.CHUNK_UTF8 ? StandardCharsets.UTF_8:StandardCharsets.US_ASCII)));
} }
return text; return text;