diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectory.java new file mode 100644 index 00000000..6cd35e0b --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectory.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2012, 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; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import static com.twelvemonkeys.lang.Validate.noNullElements; + +/** + * AbstractCompoundDirectory + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: AbstractCompoundDirectory.java,v 1.0 02.01.12 12:43 haraldk Exp$ + */ +public abstract class AbstractCompoundDirectory extends AbstractDirectory implements CompoundDirectory { + private final List directories = new ArrayList(); + + protected AbstractCompoundDirectory(final Collection directories) { + super(null); + + if (directories != null) { + this.directories.addAll(noNullElements(directories)); + } + } + + public Directory getDirectory(int index) { + return directories.get(index); + } + + public int directoryCount() { + return directories.size(); + } + + @Override + public Entry getEntryById(final Object identifier) { + for (Directory directory : directories) { + Entry entry = directory.getEntryById(identifier); + + if (entry != null) { + return entry; + } + } + + return null; + } + + @Override + public Entry getEntryByFieldName(final String fieldName) { + for (Directory directory : directories) { + Entry entry = directory.getEntryByFieldName(fieldName); + + if (entry != null) { + return entry; + } + } + + return null; + } + + @Override + public Iterator iterator() { + return new Iterator() { + Iterator directoryIterator = directories.iterator(); + Iterator current; + + public boolean hasNext() { + return current != null && current.hasNext() || directoryIterator.hasNext() && (current = directoryIterator.next().iterator()).hasNext(); + } + + public Entry next() { + hasNext(); + + return current.next(); + } + + public void remove() { + current.remove(); + } + }; + } + + // TODO: Define semantics, or leave to subclasses? + // Add to first/last directory? + // Introduce a "current" directory? And a way to advance/go back + // Remove form the first directory that contains entry? + @Override + public boolean add(final Entry entry) { + throw new UnsupportedOperationException("Directory is read-only"); + } + + @Override + public boolean remove(final Object entry) { + throw new UnsupportedOperationException("Directory is read-only"); + } + + @Override + public boolean isReadOnly() { + return true; + } + + @Override + public int size() { + int size = 0; + + for (Directory directory : directories) { + size += directory.size(); + } + + return size; + } + + @Override + public String toString() { + return String.format("%s%s", getClass().getSimpleName(), directories.toString()); + } + + @Override + public int hashCode() { + int hash = 0; + + for (Directory ifd : directories) { + hash ^= ifd.hashCode(); + } + + return hash; + } + + @Override + public boolean equals(Object pOther) { + if (pOther == this) { + return true; + } + if (pOther == null) { + return false; + } + if (pOther.getClass() != getClass()) { + return false; + } + + CompoundDirectory other = (CompoundDirectory) pOther; + + if (directoryCount() != other.directoryCount()) { + return false; + } + + for (int i = 0; i < directoryCount(); i++) { + if (!getDirectory(i).equals(other.getDirectory(i))) { + return false; + } + } + + return true; + } +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractDirectory.java index e1c7a2ab..93cf0c0f 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractDirectory.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractDirectory.java @@ -28,10 +28,9 @@ package com.twelvemonkeys.imageio.metadata; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; +import java.util.*; + +import static com.twelvemonkeys.lang.Validate.noNullElements; /** * AbstractDirectory @@ -42,10 +41,11 @@ import java.util.List; */ public abstract class AbstractDirectory implements Directory { private final List entries = new ArrayList(); + private final List unmodifiable = Collections.unmodifiableList(entries); - protected AbstractDirectory(final Collection pEntries) { - if (pEntries != null) { - entries.addAll(pEntries); + protected AbstractDirectory(final Collection entries) { + if (entries != null) { + this.entries.addAll(noNullElements(entries)); } } @@ -70,7 +70,7 @@ public abstract class AbstractDirectory implements Directory { } public Iterator iterator() { - return entries.iterator(); + return isReadOnly() ? unmodifiable.iterator() : entries.iterator(); } /** @@ -127,7 +127,7 @@ public abstract class AbstractDirectory implements Directory { return true; } - if (getClass() != pOther.getClass()) { + if (pOther == null || getClass() != pOther.getClass()) { return false; } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java index f15bf729..d9b59dc3 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java @@ -56,6 +56,17 @@ public abstract class AbstractEntry implements Entry { return identifier; } + /** + * Returns a format-native identifier. + * For example {@code "2:00"} for IPTC "Record Version" field, or {@code "0x040c"} for PSD "Thumbnail" resource. + * This default implementation simply returns {@code String.valueOf(getIdentifier())}. + * + * @return a format-native identifier. + */ + protected String getNativeIdentifier() { + return String.valueOf(getIdentifier()); + } + /** * Returns {@code null}, meaning unknown or undefined. * @@ -109,7 +120,7 @@ public abstract class AbstractEntry implements Entry { return String.valueOf(value) + " (" + valueCount() + ")"; } - if (value.getClass().isArray() && Array.getLength(value) == 1) { + if (value != null && value.getClass().isArray() && Array.getLength(value) == 1) { return String.valueOf(Array.get(value, 0)); } @@ -137,7 +148,7 @@ public abstract class AbstractEntry implements Entry { @Override public int hashCode() { - return identifier.hashCode() + 31 * value.hashCode(); + return identifier.hashCode() + (value != null ? 31 * value.hashCode() : 0); } @Override @@ -164,6 +175,6 @@ public abstract class AbstractEntry implements Entry { String type = getTypeName(); String typeStr = type != null ? " (" + type + ")" : ""; - return String.format("%s%s: %s%s", getIdentifier(), nameStr, getValueAsString(), typeStr); + return String.format("%s%s: %s%s", getNativeIdentifier(), nameStr, getValueAsString(), typeStr); } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/CompoundDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/CompoundDirectory.java new file mode 100644 index 00000000..7bde3ae2 --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/CompoundDirectory.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, 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; + +/** + * CompoundDirectory + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: CompoundDirectory.java,v 1.0 02.01.12 12:37 haraldk Exp$ + */ +public interface CompoundDirectory extends Directory { + Directory getDirectory(int index); + + int directoryCount(); +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/Entry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/Entry.java index 8681382e..ce7c6074 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/Entry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/Entry.java @@ -39,7 +39,7 @@ public interface Entry { // "tag" identifier from spec Object getIdentifier(); - // Human readable "tag" (field) name from sepc + // Human readable "tag" (field) name from spec String getFieldName(); // The internal "tag" value as stored in the stream, may be a Directory diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectory.java index 332ae6fd..1ac2a027 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectory.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectory.java @@ -28,8 +28,8 @@ package com.twelvemonkeys.imageio.metadata.exif; -import com.twelvemonkeys.imageio.metadata.AbstractDirectory; -import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.AbstractCompoundDirectory; +import com.twelvemonkeys.imageio.metadata.Directory; import java.util.Collection; @@ -40,8 +40,8 @@ import java.util.Collection; * @author last modified by $Author: haraldk$ * @version $Id: EXIFDirectory.java,v 1.0 Nov 11, 2009 5:02:59 PM haraldk Exp$ */ -final class EXIFDirectory extends AbstractDirectory { - EXIFDirectory(final Collection entries) { - super(entries); +final class EXIFDirectory extends AbstractCompoundDirectory { + EXIFDirectory(final Collection directories) { + super(directories); } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java index d40d29c8..bb8e1d0d 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java @@ -43,9 +43,9 @@ final class EXIFEntry extends AbstractEntry { EXIFEntry(final int identifier, final Object value, final short type) { super(identifier, value); -// if (type < 1 || type > TIFF.TYPE_NAMES.length) { -// throw new IllegalArgumentException(String.format("Illegal EXIF type: %s", type)); -// } + if (type < 1 || type > TIFF.TYPE_NAMES.length) { + throw new IllegalArgumentException(String.format("Illegal EXIF type: %s", type)); + } this.type = type; } @@ -74,12 +74,20 @@ final class EXIFEntry extends AbstractEntry { return "ImageHeight"; case TIFF.TAG_COMPRESSION: return "Compression"; + case TIFF.TAG_PHOTOMETRIC_INTERPRETATION: + return "PhotometricInterpretation"; + case TIFF.TAG_IMAGE_DESCRIPTION: + return "ImageDescription"; case TIFF.TAG_ORIENTATION: return "Orientation"; + case TIFF.TAG_SAMPLES_PER_PIXELS: + return "SamplesPerPixels"; case TIFF.TAG_X_RESOLUTION: return "XResolution"; case TIFF.TAG_Y_RESOLUTION: return "YResolution"; + case TIFF.TAG_PLANAR_CONFIGURATION: + return "PlanarConfiguration"; case TIFF.TAG_RESOLUTION_UNIT: return "ResolutionUnit"; case TIFF.TAG_JPEG_INTERCHANGE_FORMAT: diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java index e5ef402e..966482f3 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java @@ -28,10 +28,12 @@ package com.twelvemonkeys.imageio.metadata.exif; +import com.twelvemonkeys.imageio.metadata.AbstractCompoundDirectory; import com.twelvemonkeys.imageio.metadata.Directory; import com.twelvemonkeys.imageio.metadata.Entry; import com.twelvemonkeys.imageio.metadata.MetadataReader; import com.twelvemonkeys.lang.StringUtil; +import com.twelvemonkeys.lang.Validate; import javax.imageio.IIOException; import javax.imageio.ImageIO; @@ -40,10 +42,7 @@ import java.io.File; import java.io.IOException; import java.nio.ByteOrder; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * EXIFReader @@ -53,10 +52,12 @@ import java.util.List; * @version $Id: EXIFReader.java,v 1.0 Nov 13, 2009 5:42:51 PM haraldk Exp$ */ public final class EXIFReader extends MetadataReader { - static final Collection KNOWN_IFDS = Arrays.asList(TIFF.TAG_EXIF_IFD, TIFF.TAG_GPS_IFD, TIFF.TAG_INTEROP_IFD); + static final Collection KNOWN_IFDS = Collections.unmodifiableCollection(Arrays.asList(TIFF.TAG_EXIF_IFD, TIFF.TAG_GPS_IFD, TIFF.TAG_INTEROP_IFD)); @Override public Directory read(final ImageInputStream input) throws IOException { + Validate.notNull(input, "input"); + byte[] bom = new byte[2]; input.readFully(bom); @@ -82,7 +83,8 @@ public final class EXIFReader extends MetadataReader { return readDirectory(input, directoryOffset); } - private EXIFDirectory readDirectory(final ImageInputStream pInput, final long pOffset) throws IOException { + private Directory readDirectory(final ImageInputStream pInput, final long pOffset) throws IOException { + List ifds = new ArrayList(); List entries = new ArrayList(); pInput.seek(pOffset); int entryCount = pInput.readUnsignedShort(); @@ -92,14 +94,15 @@ public final class EXIFReader extends MetadataReader { } long nextOffset = pInput.readUnsignedInt(); - + // Read linked IFDs if (nextOffset != 0) { - EXIFDirectory next = readDirectory(pInput, nextOffset); - - for (Entry entry : next) { - entries.add(entry); - } + // TODO: This is probably not okay anymore.. Replace recursion with while loop + Directory next = readDirectory(pInput, nextOffset); + ifds.add((IFD) ((AbstractCompoundDirectory) next).getDirectory(0)); +// for (Entry entry : next) { +// entries.add(entry); +// } } // TODO: Make what sub-IFDs to parse optional? Or leave this to client code? At least skip the non-TIFF data? @@ -113,7 +116,9 @@ public final class EXIFReader extends MetadataReader { ) ); - return new EXIFDirectory(entries); + ifds.add(0, new IFD(entries)); + + return new EXIFDirectory(ifds); } // private Directory readForeignMetadata(final MetadataReader reader, final byte[] bytes) throws IOException { @@ -161,7 +166,7 @@ public final class EXIFReader extends MetadataReader { directory = new CompoundDocument(new ByteArrayInputStream((byte[]) entry.getValue())).getRootEntry(); } else*/ if (KNOWN_IFDS.contains(tagId)) { - directory = readDirectory(input, getPointerOffset(entry)); + directory = ((AbstractCompoundDirectory) readDirectory(input, getPointerOffset(entry))).getDirectory(0); } else { continue; @@ -273,9 +278,11 @@ public final class EXIFReader extends MetadataReader { switch (pType) { case 2: // ASCII // TODO: This might be UTF-8 or ISO-8859-x, even though spec says ASCII + // TODO: Fail if unknown chars, try parsing with ISO-8859-1 or file.encoding byte[] ascii = new byte[pCount]; pInput.readFully(ascii); - return StringUtil.decode(ascii, 0, ascii.length, "UTF-8"); // UTF-8 is ASCII compatible + int len = ascii[ascii.length - 1] == 0 ? ascii.length - 1 : ascii.length; + return StringUtil.decode(ascii, 0, len, "UTF-8"); // UTF-8 is ASCII compatible case 1: // BYTE if (pCount == 1) { return pInput.readUnsignedByte(); @@ -399,10 +406,8 @@ public final class EXIFReader extends MetadataReader { return longs; default: - // Spec says skip unknown values: - // TODO: Rather just return null, UNKNOWN_TYPE or new Unknown(type, count, offset) for value? + // Spec says skip unknown values return new Unknown(pType, pCount, pos); -// throw new IIOException(String.format("Unknown EXIF type '%s' at pos %d", pType, pInput.getStreamPosition())); } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/IFD.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/IFD.java new file mode 100644 index 00000000..0340517d --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/IFD.java @@ -0,0 +1,47 @@ +/* + * 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.exif; + +import com.twelvemonkeys.imageio.metadata.AbstractDirectory; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * IFD + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: IFD.java,v 1.0 23.12.11 16:24 haraldk Exp$ + */ +final class IFD extends AbstractDirectory { + protected IFD(final Collection pEntries) { + super(pEntries); + } +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/Unknown.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/Unknown.java index dc5fb965..0fd8b7db 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/Unknown.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/Unknown.java @@ -6,6 +6,7 @@ package com.twelvemonkeys.imageio.metadata.exif; * @author Harald Kuhr * @author last modified by $Author: haraldk$ * @version $Id: Unknown.java,v 1.0 Oct 8, 2010 3:38:45 PM haraldk Exp$ + * @see There are known knowns */ final class Unknown { private final short type; @@ -24,8 +25,8 @@ final class Unknown { } @Override - public boolean equals(Object other) { - if (other != null && other.getClass() == getClass()){ + public boolean equals(final Object other) { + if (other != null && other.getClass() == getClass()) { Unknown unknown = (Unknown) other; return pos == unknown.pos && type == unknown.type && count == unknown.count; } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntry.java index 2f14cd47..be129c3e 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntry.java @@ -45,6 +45,8 @@ class IPTCEntry extends AbstractEntry { @Override public String getFieldName() { switch ((Integer) getIdentifier()) { + case IPTC.TAG_RECORD_VERSION: + return "RecordVersion"; case IPTC.TAG_SOURCE: return "Source"; // TODO: More tags... @@ -52,4 +54,10 @@ class IPTCEntry extends AbstractEntry { return null; } + + @Override + protected String getNativeIdentifier() { + int identifier = (Integer) getIdentifier(); + return String.format("%d:%02d", identifier >> 8, identifier & 0xff); + } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReader.java index 22dfb3bb..a9fad969 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReader.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReader.java @@ -32,6 +32,7 @@ import com.twelvemonkeys.imageio.metadata.Directory; import com.twelvemonkeys.imageio.metadata.Entry; import com.twelvemonkeys.imageio.metadata.MetadataReader; import com.twelvemonkeys.lang.StringUtil; +import com.twelvemonkeys.lang.Validate; import javax.imageio.IIOException; import javax.imageio.stream.ImageInputStream; @@ -62,7 +63,9 @@ public final class IPTCReader extends MetadataReader { @Override public Directory read(final ImageInputStream input) throws IOException { - final List entries = new ArrayList(); + Validate.notNull(input, "input"); + + List entries = new ArrayList(); // 0x1c identifies start of a tag while (input.read() == 0x1c) { diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java index bdc8726d..dd2f781b 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java @@ -43,6 +43,7 @@ public interface JPEG { int APP0 = 0xFFE0; int APP1 = 0xFFE1; int APP2 = 0xFFE2; + int APP13 = 0xFFED; int APP14 = 0xFFEE; int SOF0 = 0xFFC0; diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectory.java new file mode 100644 index 00000000..cd9af244 --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectory.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.AbstractDirectory; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * PhotoshopDirectory + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopDirectory.java,v 1.0 04.01.12 11:58 haraldk Exp$ + */ +final class PSDDirectory extends AbstractDirectory { + public PSDDirectory(final Collection entries) { + super(entries); + } +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java new file mode 100644 index 00000000..c76bb6a3 --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.AbstractEntry; + +/** + * PhotoshopEntry + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopEntry.java,v 1.0 04.01.12 11:58 haraldk Exp$ + */ +class PSDEntry extends AbstractEntry { + public PSDEntry(final int resourceId, final Object value) { + super(resourceId, value); + } + + @Override + protected String getNativeIdentifier() { + return String.format("0x%04x", (Integer) getIdentifier()); + } +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java new file mode 100644 index 00000000..a8ec02f4 --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.MetadataReader; +import com.twelvemonkeys.imageio.stream.SubImageInputStream; +import com.twelvemonkeys.lang.StringUtil; +import com.twelvemonkeys.lang.Validate; + +import javax.imageio.IIOException; +import javax.imageio.stream.ImageInputStream; +import java.io.DataInput; +import java.io.EOFException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * PhotoshopReader + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopReader.java,v 1.0 04.01.12 11:56 haraldk Exp$ + */ +public final class PSDReader extends MetadataReader { + + // TODO: Add constructor to allow optional parsing of resources + // TODO: Maybe this should be modelled more like the JPEG segment parsing, as it's all binary data... + // - Segment/SegmentReader + List + + @Override + public Directory read(final ImageInputStream input) throws IOException { + Validate.notNull(input, "input"); + + List entries = new ArrayList(); + + while (true) { + try { + int type = input.readInt(); + + if (type != PSDResource.RESOURCE_TYPE) { + throw new IIOException(String.format("Wrong image resource type, expected '8BIM': '%08x'", type)); + } + + short id = input.readShort(); + + PSDResource resource = new PSDResource(id, input); + entries.add(new PSDEntry(id, resource.data())); + + } + catch (EOFException e) { + break; + } + } + + return new PSDDirectory(entries); + } + + protected static class PSDResource { + static final int RES_IPTC_NAA = 0x0404; + static final int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M'; + + static String readPascalString(final DataInput pInput) throws IOException { + int length = pInput.readUnsignedByte(); + + if (length == 0) { + return ""; + } + + byte[] bytes = new byte[length]; + pInput.readFully(bytes); + + return StringUtil.decode(bytes, 0, bytes.length, "ASCII"); + } + + final short id; + final String name; + final long size; + + byte[] data; + + PSDResource(final short resourceId, final ImageInputStream input) throws IOException { + id = resourceId; + + name = readPascalString(input); + + // Skip pad + int nameSize = name.length() + 1; + if (nameSize % 2 != 0) { + input.readByte(); + } + + size = input.readUnsignedInt(); + long startPos = input.getStreamPosition(); + + readData(new SubImageInputStream(input, size)); + + // NOTE: This should never happen, however it's safer to keep it here to + if (input.getStreamPosition() != startPos + size) { + input.seek(startPos + size); + } + + // Data is even-padded (word aligned) + if (size % 2 != 0) { + input.read(); + } + } + + protected void readData(final ImageInputStream pInput) throws IOException { + // TODO: This design is ugly, as subclasses readData is invoked BEFORE their respective constructor... + data = new byte[(int) size]; + pInput.readFully(data); + } + + public final byte[] data() { + return data; + } + + @Override + public String toString() { + StringBuilder builder = toStringBuilder(); + + builder.append(", data length: "); + builder.append(size); + builder.append("]"); + + return builder.toString(); + } + + protected StringBuilder toStringBuilder() { + StringBuilder builder = new StringBuilder(getClass().getSimpleName()); + + builder.append("[ID: 0x"); + builder.append(Integer.toHexString(id)); + if (name != null && name.trim().length() != 0) { + builder.append(", name: \""); + builder.append(name); + builder.append("\""); + } + + return builder; + } + } + +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescription.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescription.java new file mode 100644 index 00000000..2e6c7eda --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescription.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2012, 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.xmp; + +import com.twelvemonkeys.imageio.metadata.AbstractDirectory; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** +* RDFDescription +* +* @author Harald Kuhr +* @author last modified by $Author: haraldk$ +* @version $Id: RDFDescription.java,v 1.0 Nov 17, 2009 9:38:58 PM haraldk Exp$ +*/ +final class RDFDescription extends AbstractDirectory { + private final String namespace; + + // TODO: Store size of root directory, to allow serializing + // TODO: XMPDirectory, maybe not even an AbstractDirectory + // - Keeping the Document would allow for easier serialization + // TODO: Or use direct SAX parsing + public RDFDescription(Collection entries) { + this(null, entries); + } + + public RDFDescription(String key, Collection entries) { + super(entries); + + namespace = key; + } + + @Override + public String toString() { + return namespace != null ? + super.toString().replaceAll("^RDFDescription\\[", String.format("%s[%s|%s, ", getClass().getSimpleName(), XMP.DEFAULT_NS_MAPPING.get(namespace), namespace)) : + super.toString(); + } +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMP.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMP.java index d36cc6c4..c624afe6 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMP.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMP.java @@ -30,6 +30,7 @@ package com.twelvemonkeys.imageio.metadata.xmp; import java.util.Collections; import java.util.Map; +import java.util.Set; /** * XMP @@ -59,6 +60,10 @@ public interface XMP { String NS_XAP_MM = "http://ns.adobe.com/xap/1.0/mm/"; + String NS_X = "adobe:ns:meta/"; + /** Contains the mapping from URI to default namespace prefix. */ - Map DEFAULT_NS_MAPPING = Collections.unmodifiableMap(new XMPNamespaceMapping()); + Map DEFAULT_NS_MAPPING = Collections.unmodifiableMap(new XMPNamespaceMapping(true)); + + Set ELEMENTS = Collections.unmodifiableSet(new XMPNamespaceMapping(false).keySet()); } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectory.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectory.java index 484a5cf9..565f7d76 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectory.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectory.java @@ -28,10 +28,10 @@ package com.twelvemonkeys.imageio.metadata.xmp; -import com.twelvemonkeys.imageio.metadata.AbstractDirectory; -import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.AbstractCompoundDirectory; +import com.twelvemonkeys.imageio.metadata.Directory; -import java.util.List; +import java.util.Collection; /** * XMPDirectory @@ -40,12 +40,30 @@ import java.util.List; * @author last modified by $Author: haraldk$ * @version $Id: XMPDirectory.java,v 1.0 Nov 17, 2009 9:38:58 PM haraldk Exp$ */ -final class XMPDirectory extends AbstractDirectory { - // TODO: Store size of root directory, to allow serializing +final class XMPDirectory extends AbstractCompoundDirectory { + // TODO: Allow lookup of directories by namespace? + // TODO: Allow merge/sync/comparison with IPTC/EXIF/TIFF metadata + // TODO: Store size of root directory, to allow easy serializing (see isReadOnly comment) // TODO: XMPDirectory, maybe not even an AbstractDirectory // - Keeping the Document would allow for easier serialization // TODO: Or use direct SAX parsing - public XMPDirectory(List entries) { + private final String toolkit; + + public XMPDirectory(Collection entries, String toolkit) { super(entries); + + this.toolkit = toolkit; + } + + // TODO: Expose x:xmptk (getXMPToolkit(): String) + /*public*/ String getWriterToolkit() { + return toolkit; + } + + @Override + public boolean isReadOnly() { + // TODO: Depend on / for writable/read-only respectively? + // Spec says allow writing (even if "r"), if the container format is understood (ie. single file, known format, update checksums etc) + return super.isReadOnly(); } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntry.java index 98163b69..c4c7f1da 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntry.java @@ -40,6 +40,7 @@ import com.twelvemonkeys.imageio.metadata.AbstractEntry; final class XMPEntry extends AbstractEntry { private final String fieldName; + // TODO: Rewrite to use namespace + field instead of identifier (for the nativeIdentifier) method public XMPEntry(final String identifier, final Object pValue) { this(identifier, null, pValue); } @@ -49,6 +50,13 @@ final class XMPEntry extends AbstractEntry { this.fieldName = fieldName; } + @Override + protected String getNativeIdentifier() { + String identifier = (String) getIdentifier(); + String namespace = fieldName != null && identifier.endsWith(fieldName) ? XMP.DEFAULT_NS_MAPPING.get(identifier.substring(0, identifier.length() - fieldName.length())) : null; + return namespace != null ? namespace + ":" + fieldName : identifier; + } + @SuppressWarnings({"SuspiciousMethodCalls"}) @Override public String getFieldName() { @@ -60,6 +68,6 @@ final class XMPEntry extends AbstractEntry { String type = getTypeName(); String typeStr = type != null ? " (" + type + ")" : ""; - return String.format("%s: %s%s", getIdentifier(), getValueAsString(), typeStr); + return String.format("%s: %s%s", getNativeIdentifier(), getValueAsString(), typeStr); } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPNamespaceMapping.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPNamespaceMapping.java index 0170acb3..af1729c9 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPNamespaceMapping.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPNamespaceMapping.java @@ -38,8 +38,12 @@ import java.util.HashMap; * @version $Id: XMPNamespaceMapping.java,v 1.0 Nov 17, 2009 6:35:21 PM haraldk Exp$ */ final class XMPNamespaceMapping extends HashMap { - public XMPNamespaceMapping() { - put(XMP.NS_RDF, "rdf"); + public XMPNamespaceMapping(boolean includeNonElements) { + if (includeNonElements) { + put(XMP.NS_RDF, "rdf"); + put(XMP.NS_X, "x"); + } + put(XMP.NS_DC, "dc"); put(XMP.NS_EXIF, "exif"); put(XMP.NS_PHOTOSHOP, "photoshop"); diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReader.java index 2e470822..e43d7557 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReader.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReader.java @@ -32,6 +32,7 @@ import com.twelvemonkeys.imageio.metadata.Directory; import com.twelvemonkeys.imageio.metadata.Entry; import com.twelvemonkeys.imageio.metadata.MetadataReader; import com.twelvemonkeys.imageio.util.IIOUtil; +import com.twelvemonkeys.lang.Validate; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; @@ -55,17 +56,13 @@ import java.util.*; * @version $Id: XMPReader.java,v 1.0 Nov 14, 2009 11:04:30 PM haraldk Exp$ */ public final class XMPReader extends MetadataReader { + // See http://www.scribd.com/doc/56852716/XMPSpecificationPart1 + + // TODO: Types? Probably defined in XMP/RDF XML schema. Or are we happy that everything is a string? + @Override public Directory read(final ImageInputStream input) throws IOException { -// pInput.mark(); -// -// BufferedReader reader = new BufferedReader(new InputStreamReader(IIOUtil.createStreamAdapter(pInput), Charset.forName("UTF-8"))); -// String line; -// while ((line = reader.readLine()) != null) { -// System.out.println(line); -// } -// -// pInput.reset(); + Validate.notNull(input, "input"); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); @@ -80,14 +77,11 @@ public final class XMPReader extends MetadataReader { // XMLSerializer serializer = new XMLSerializer(System.err, System.getProperty("file.encoding")); // serializer.serialize(document); - - // Each rdf:Description is a Directory (but we can't really rely on that structure.. it's only convention) - // - Each element inside the rdf:Desc is an Entry - + String toolkit = getToolkit(document); Node rdfRoot = document.getElementsByTagNameNS(XMP.NS_RDF, "RDF").item(0); NodeList descriptions = document.getElementsByTagNameNS(XMP.NS_RDF, "Description"); - return parseDirectories(rdfRoot, descriptions); + return parseDirectories(rdfRoot, descriptions, toolkit); } catch (SAXException e) { throw new IIOException(e.getMessage(), e); @@ -97,7 +91,19 @@ public final class XMPReader extends MetadataReader { } } - private XMPDirectory parseDirectories(final Node pParentNode, NodeList pNodes) { + private String getToolkit(Document document) { + NodeList xmpmeta = document.getElementsByTagNameNS(XMP.NS_X, "xmpmeta"); + + if (xmpmeta == null || xmpmeta.getLength() <= 0) { + return null; + } + + Node toolkit = xmpmeta.item(0).getAttributes().getNamedItemNS(XMP.NS_X, "xmptk"); + + return toolkit != null ? toolkit.getNodeValue() : null; + } + + private XMPDirectory parseDirectories(final Node pParentNode, NodeList pNodes, String toolkit) { Map> subdirs = new LinkedHashMap>(); for (Node desc : asIterable(pNodes)) { @@ -105,6 +111,9 @@ public final class XMPReader extends MetadataReader { continue; } + // Support attribute short-hand syntax + parseAttributesForKnownElements(subdirs, desc); + for (Node node : asIterable(desc.getChildNodes())) { if (node.getNodeType() != Node.ELEMENT_NODE) { continue; @@ -121,6 +130,7 @@ public final class XMPReader extends MetadataReader { Node parseType = node.getAttributes().getNamedItemNS(XMP.NS_RDF, "parseType"); if (parseType != null && "Resource".equals(parseType.getNodeValue())) { + // See: http://www.w3.org/TR/REC-rdf-syntax/#section-Syntax-parsetype-resource List entries = new ArrayList(); for (Node child : asIterable(node.getChildNodes())) { @@ -130,60 +140,119 @@ public final class XMPReader extends MetadataReader { entries.add(new XMPEntry(child.getNamespaceURI() + child.getLocalName(), child.getLocalName(), getChildTextValue(child))); } - value = new XMPDirectory(entries); + + value = new RDFDescription(entries); } else { - // TODO: Support alternative RDF syntax (short-form), using attributes on desc -// NamedNodeMap attributes = node.getAttributes(); -// -// for (Node attr : asIterable(attributes)) { -// System.out.println("attr.getNodeName(): " + attr.getNodeName()); -// System.out.println("attr.getNodeValue(): " + attr.getNodeValue()); -// } + // TODO: This method contains loads of duplication an should be cleaned up... + // Support attribute short-hand syntax + Map> subsubdirs = new LinkedHashMap>(); - value = getChildTextValue(node); + parseAttributesForKnownElements(subsubdirs, node); + + if (!subsubdirs.isEmpty()) { + List entries = new ArrayList(); + + for (Map.Entry> entry : subsubdirs.entrySet()) { + entries.addAll(entry.getValue()); + } + + value = new RDFDescription(entries); + } + else { + value = getChildTextValue(node); + } } - XMPEntry entry = new XMPEntry(node.getNamespaceURI() + node.getLocalName(), node.getLocalName(), value); - dir.add(entry); + dir.add(new XMPEntry(node.getNamespaceURI() + node.getLocalName(), node.getLocalName(), value)); } } - // TODO: Consider flattening the somewhat artificial directory structure - List entries = new ArrayList(); + List entries = new ArrayList(); + // TODO: Should we still allow asking for a subdirectory by item id? for (Map.Entry> entry : subdirs.entrySet()) { - entries.add(new XMPEntry(entry.getKey(), new XMPDirectory(entry.getValue()))); + entries.add(new RDFDescription(entry.getKey(), entry.getValue())); } - return new XMPDirectory(entries); + return new XMPDirectory(entries, toolkit); } - private Object getChildTextValue(Node node) { - Object value; - Node child = node.getFirstChild(); + private void parseAttributesForKnownElements(Map> subdirs, Node desc) { + // NOTE: NamedNodeMap does not have any particular order... + NamedNodeMap attributes = desc.getAttributes(); - String strVal = null; - if (child != null) { - strVal = child.getNodeValue(); + for (Node attr : asIterable(attributes)) { + if (!XMP.ELEMENTS.contains(attr.getNamespaceURI())) { + continue; + } + + List dir = subdirs.get(attr.getNamespaceURI()); + + if (dir == null) { + dir = new ArrayList(); + subdirs.put(attr.getNamespaceURI(), dir); + } + + dir.add(new XMPEntry(attr.getNamespaceURI() + attr.getLocalName(), attr.getLocalName(), attr.getNodeValue())); + } + } + + private Object getChildTextValue(final Node node) { + for (Node child : asIterable(node.getChildNodes())) { + if (XMP.NS_RDF.equals(child.getNamespaceURI()) && "Alt".equals(child.getLocalName())) { + // Support for -> return a Map (keyed on xml:lang?) + Map alternatives = new LinkedHashMap(); + for (Node alternative : asIterable(child.getChildNodes())) { + if (XMP.NS_RDF.equals(alternative.getNamespaceURI()) && "li".equals(alternative.getLocalName())) { + //return getChildTextValue(alternative); + NamedNodeMap attributes = alternative.getAttributes(); + Node key = attributes.getNamedItem("xml:lang"); + + alternatives.put(key.getTextContent(), getChildTextValue(alternative)); + } + } + + return alternatives; + } + else if (XMP.NS_RDF.equals(child.getNamespaceURI()) && ("Seq".equals(child.getLocalName()) || "Bag".equals(child.getLocalName()))) { + // Support for -> return array + // Support for -> return array/unordered collection (how can a serialized collection not have order?) + List seq = new ArrayList(); + + for (Node sequence : asIterable(child.getChildNodes())) { + if (XMP.NS_RDF.equals(sequence.getNamespaceURI()) && "li".equals(sequence.getLocalName())) { + Object value = getChildTextValue(sequence); + seq.add(value); + } + } + + // TODO: Strictly a bag should not be a list, but there's no Bag type (or similar) in Java. + // Consider something like Google collections Multiset or Apache commons Bag (the former seems more well-defined) + // Note: Collection does not have defined equals() semantics, and so using + // Collections.unmodifiableCollection() doesn't work for comparing values (uses Object.equals()) + return Collections.unmodifiableList(seq); + } } - value = strVal != null ? strVal.trim() : ""; - return value; + Node child = node.getFirstChild(); + String strVal = child != null ? child.getNodeValue() : null; + + return strVal != null ? strVal.trim() : ""; } private Iterable asIterable(final NamedNodeMap pNodeList) { return new Iterable() { public Iterator iterator() { return new Iterator() { - private int mIndex; + private int index; public boolean hasNext() { - return pNodeList != null && pNodeList.getLength() > mIndex; + return pNodeList != null && pNodeList.getLength() > index; } public Node next() { - return pNodeList.item(mIndex++); + return pNodeList.item(index++); } public void remove() { @@ -198,14 +267,14 @@ public final class XMPReader extends MetadataReader { return new Iterable() { public Iterator iterator() { return new Iterator() { - private int mIndex; + private int index; public boolean hasNext() { - return pNodeList != null && pNodeList.getLength() > mIndex; + return pNodeList != null && pNodeList.getLength() > index; } public Node next() { - return pNodeList.item(mIndex++); + return pNodeList.item(index++); } public void remove() { @@ -215,5 +284,4 @@ public final class XMPReader extends MetadataReader { } }; } - } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScanner.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScanner.java index 07f2b2fa..93f941c0 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScanner.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScanner.java @@ -140,8 +140,8 @@ public final class XMPScanner { // UTF 32 BIG endian cs = Charset.forName("UTF-32BE"); } - else if (bom[0] == (byte) 0xFF && bom[1] == (byte) 0xFE && bom[2] == 0x00 && bom[3] == 0x00) { - // TODO: FixMe.. + else if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == 0x00 && bom[3] == (byte) 0xFF && stream.read() == 0xFE) { + stream.skipBytes(2); // Alignment // NOTE: 32-bit character set not supported by default // UTF 32 little endian cs = Charset.forName("UTF-32LE"); @@ -220,8 +220,6 @@ public final class XMPScanner { return -1l; } - //static public XMPDirectory parse(input); - public static void main(final String[] pArgs) throws IOException { ImageInputStream stream = ImageIO.createImageInputStream(new File(pArgs[0])); @@ -236,8 +234,5 @@ public final class XMPScanner { } stream.close(); -// else { -// System.err.println("XMP not found"); -// } } } diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectoryTest.java new file mode 100644 index 00000000..23b783af --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractCompoundDirectoryTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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; + +import java.util.Collection; + +/** + * AbstractCompoundDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: AbstractCompoundDirectoryTest.java,v 1.0 02.01.12 15:07 haraldk Exp$ + */ +public class AbstractCompoundDirectoryTest extends CompoundDirectoryAbstractTest { + @Override + protected CompoundDirectory createCompoundDirectory(final Collection directories) { + return new AbstractCompoundDirectory(directories) {}; + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractDirectoryTest.java new file mode 100644 index 00000000..64de19ea --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractDirectoryTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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; + +import java.util.Collection; + +/** + * AbstractDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: AbstractDirectoryTest.java,v 1.0 02.01.12 15:07 haraldk Exp$ + */ +public class AbstractDirectoryTest extends DirectoryAbstractTest { + @Override + protected Directory createDirectory(final Collection entries) { + return new AbstractDirectory(entries) {}; + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractEntryTest.java new file mode 100644 index 00000000..08cff7dd --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/AbstractEntryTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2012, 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; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * AbstractEntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: AbstractEntryTest.java,v 1.0 02.01.12 17:22 haraldk Exp$ + */ +public class AbstractEntryTest extends EntryAbstractTest { + @Override + protected final Entry createEntry(final Object value) { + return createEntry("foo", value); + } + + private AbstractEntry createEntry(final String identifier, final Object value) { + return new AbstractEntry(identifier, value) {}; + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateEntryNullId() { + createEntry(null, new Object()); + } + + @Test + public void testAbstractEntry() { + Object value = new Object(); + Entry entry = createEntry("foo", value); + + assertEquals("foo", entry.getIdentifier()); + assertNull(entry.getFieldName()); + assertSame(value, entry.getValue()); + assertNotNull(entry.getValueAsString()); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/CompoundDirectoryAbstractTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/CompoundDirectoryAbstractTest.java new file mode 100644 index 00000000..1a58dba7 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/CompoundDirectoryAbstractTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2012, 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; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; + +/** + * CompoundDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: CompoundDirectoryTest.java,v 1.0 02.01.12 15:07 haraldk Exp$ + */ +public abstract class CompoundDirectoryAbstractTest extends DirectoryAbstractTest { + protected abstract CompoundDirectory createCompoundDirectory(Collection directories); + + // Override by subclasses that require special kind of directory + protected Directory createSingleDirectory(final Collection entries) { + return new TestDirectory(entries); + } + + @Override + protected final Directory createDirectory(final Collection entries) { + // A compound directory should behave like a normal directory + return createCompoundDirectory(Collections.singleton(createSingleDirectory(entries))); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateNullDirectories() { + createCompoundDirectory(Collections.singleton(null)); + } + + @Test + public void testSingle() { + Directory only = createSingleDirectory(null); + + CompoundDirectory directory = createCompoundDirectory(Collections.singleton(only)); + + assertEquals(1, directory.directoryCount()); + assertSame(only, directory.getDirectory(0)); + } + + @Test + public void testMultiple() { + Directory one = createSingleDirectory(null); + Directory two = createSingleDirectory(null); + Directory three = createSingleDirectory(null); + + CompoundDirectory directory = createCompoundDirectory(Arrays.asList(one, two, three)); + + assertEquals(3, directory.directoryCount()); + assertSame(one, directory.getDirectory(0)); + assertSame(two, directory.getDirectory(1)); + assertSame(three, directory.getDirectory(2)); + } + + @Test + public void testEntries() { + Directory one = createSingleDirectory(null); + Directory two = createSingleDirectory(null); + Directory three = createSingleDirectory(null); + + CompoundDirectory directory = createCompoundDirectory(Arrays.asList(one, two, three)); + + assertEquals(3, directory.directoryCount()); + assertSame(one, directory.getDirectory(0)); + assertSame(two, directory.getDirectory(1)); + assertSame(three, directory.getDirectory(2)); + } + + @Test(expected = IndexOutOfBoundsException.class) + public void testOutOfBounds() { + Directory only = createSingleDirectory(null); + CompoundDirectory directory = createCompoundDirectory(Collections.singleton(only)); + + directory.getDirectory(directory.directoryCount()); + } + + protected static final class TestDirectory extends AbstractDirectory { + public TestDirectory(final Collection entries) { + super(entries); + } + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/DirectoryAbstractTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/DirectoryAbstractTest.java new file mode 100644 index 00000000..44bac310 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/DirectoryAbstractTest.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2012, 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; + +import com.twelvemonkeys.lang.ObjectAbstractTestCase; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; + +/** + * DirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: DirectoryTest.java,v 1.0 02.01.12 15:07 haraldk Exp$ + */ +public abstract class DirectoryAbstractTest extends ObjectAbstractTestCase { + + @Override + protected Object makeObject() { + return createDirectory(Collections.singleton(createEntry("entry", null))); + } + + protected abstract Directory createDirectory(Collection entries); + + // Override by subclasses that requires special type of entries + protected Entry createEntry(final String identifier, final Object value) { + return new TestEntry(identifier, value); + } + + @Test + public void testCreateNull() { + Directory directory = createDirectory(null); + + assertEquals(0, directory.size()); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateNullEntries() { + createDirectory(Collections.singleton(null)); + } + + @Test + public void testSingleEntry() { + Entry entry = createEntry("foo", new Object()); + Directory directory = createDirectory(Collections.singleton(entry)); + + assertEquals(1, directory.size()); + assertSame(entry, directory.getEntryById("foo")); + } + + @Test + public void testNonExistentEntry() { + Entry entry = createEntry("foo", new Object()); + Directory directory = createDirectory(Collections.singleton(entry)); + assertNull(directory.getEntryById("bar")); + } + + @Test + public void testMultipleEntries() { + Entry one = createEntry("foo", new Object()); + Entry two = createEntry("bar", new Object()); + + Directory directory = createDirectory(Arrays.asList(one, two)); + + assertEquals(2, directory.size()); + + assertSame(one, directory.getEntryById("foo")); + assertSame(two, directory.getEntryById("bar")); + } + + @Test + public void testEmptyIterator() { + Directory directory = createDirectory(null); + + assertEquals(0, directory.size()); + + assertFalse(directory.iterator().hasNext()); + } + + @Test + public void testSingleIterator() { + Entry one = createEntry("foo", new Object()); + + Directory directory = createDirectory(Arrays.asList(one)); + + int count = 0; + for (Entry entry : directory) { + assertSame(one, entry); + count++; + } + + assertEquals(1, count); + } + + @Test + public void testIteratorMutability() { + Entry one = createEntry("foo", new Object()); + Entry two = createEntry("bar", new Object()); + + Directory directory = createDirectory(Arrays.asList(one, two)); + + assertEquals(2, directory.size()); + + Iterator entries = directory.iterator(); + if (!directory.isReadOnly()) { + while (entries.hasNext()) { + entries.next(); + entries.remove(); + } + + assertEquals(0, directory.size()); + } + else { + while (entries.hasNext()) { + try { + entries.next(); + entries.remove(); + fail("Expected UnsupportedOperationException"); + } + catch (UnsupportedOperationException expected) { + } + } + + assertEquals(2, directory.size()); + } + } + + @Test + public void testMultipleIterator() { + Entry one = createEntry("foo", new Object()); + Entry two = createEntry("bar", new Object()); + Entry three = createEntry("baz", new Object()); + + List all = Arrays.asList(one, two, three); + Directory directory = createDirectory(all); + + // Test that each element is contained, and only once + List entries = new ArrayList(all); + + int count = 0; + for (Entry entry : directory) { + assertTrue(entries.contains(entry)); + assertTrue(entries.remove(entry)); + + count++; + } + + assertTrue(entries.isEmpty()); + assertEquals(3, count); + } + + protected static class TestEntry extends AbstractEntry { + public TestEntry(final String identifier, final Object value) { + super(identifier, value); + } + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/EntryAbstractTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/EntryAbstractTest.java new file mode 100644 index 00000000..c98a6546 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/EntryAbstractTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012, 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; + +import com.twelvemonkeys.lang.ObjectAbstractTestCase; +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * EntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: EntryTest.java,v 1.0 02.01.12 17:33 haraldk Exp$ + */ +public abstract class EntryAbstractTest extends ObjectAbstractTestCase { + @Override + protected Object makeObject() { + return createEntry(new Object()); + } + + protected abstract Entry createEntry(Object value); + + @Test + public void testCreateEntryNullValue() { + Entry foo = createEntry(null); + + assertNotNull(foo.getIdentifier()); + assertEquals(null, foo.getValue()); + + assertEquals("null", foo.getValueAsString()); + } + + @Test + public void testEntryStringValue() { + Entry foo = createEntry("bar"); + + assertNotNull(foo.getIdentifier()); + assertEquals("bar", foo.getValue()); + assertEquals("bar", foo.getValueAsString()); + } + + @Test + public void testEntryValue() { + Entry foo = createEntry(77); + + assertNotNull(foo.getIdentifier()); + assertEquals(77, foo.getValue()); + assertEquals("77", foo.getValueAsString()); + } + + @Test + public void testNullValueHashCode() { + Entry foo = createEntry(null); + + // Doesn't really matter, as long as it doesn't throw NPE, but this should hold for all entries + assertNotSame(0, foo.hashCode()); + } + + @Test + public void testArrayValueHashCode() { + // Doesn't really matter, as long as it doesn't throw NPE, but this should hold for all entries + assertNotSame(0, createEntry(new int[0]).hashCode()); + assertNotSame(0, createEntry(new int[1]).hashCode()); + } + + @Test + public void testArrayValue() { + int[] array = {42, -1, 77, 99, 55}; + Entry foo = createEntry(array); + + assertEquals(5, foo.valueCount()); + assertArrayEquals(array, (int[]) foo.getValue()); + + // Not strictly necessary, but nice + assertEquals(Arrays.toString(array), foo.getValueAsString()); + } + + @Test + public void testCharArrayValue() { + char[] array = {'f', '0', '0'}; + Entry foo = createEntry(array); + + assertEquals(3, foo.valueCount()); + assertArrayEquals(array, (char[]) foo.getValue()); + + // Not strictly necessary, but nice + assertEquals("f00", foo.getValueAsString()); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/MetadataReaderAbstractTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/MetadataReaderAbstractTest.java new file mode 100644 index 00000000..6f220006 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/MetadataReaderAbstractTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2012, 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; + +import com.twelvemonkeys.imageio.stream.URLImageInputStreamSpi; +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.junit.Test; +import org.junit.internal.matchers.TypeSafeMatcher; + +import javax.imageio.ImageIO; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * ReaderAbstractTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: ReaderAbstractTest.java,v 1.0 04.01.12 09:40 haraldk Exp$ + */ +public abstract class MetadataReaderAbstractTest { + static { + IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi()); + } + + protected final URL getResource(final String name) throws IOException { + return getClass().getResource(name); + } + + protected final ImageInputStream getDataAsIIS() throws IOException { + return ImageIO.createImageInputStream(getData()); + } + + protected abstract InputStream getData() throws IOException; + + protected abstract MetadataReader createReader(); + + @Test(expected = IllegalArgumentException.class) + public void testReadNull() throws IOException { + createReader().read(null); + } + + @Test + public void testRead() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + assertNotNull(directory); + } + + protected final Matcher hasValue(final Object value) { + return new EntryHasValue(value); + } + + private static class EntryHasValue extends TypeSafeMatcher { + private final Object value; + + public EntryHasValue(final Object value) { + this.value = value; + } + + @Override + public boolean matchesSafely(final Entry entry) { + return entry != null && (value == null ? entry.getValue() == null : valueEquals(value, entry.getValue())); + } + + private static boolean valueEquals(final Object expected, final Object actual) { + return expected.getClass().isArray() ? arrayEquals(expected, actual) : expected.equals(actual); + } + + private static boolean arrayEquals(final Object expected, final Object actual) { + Class componentType = expected.getClass().getComponentType(); + + if (actual == null || !actual.getClass().isArray() || actual.getClass().getComponentType() != componentType) { + return false; + } + + return componentType.isPrimitive() ? primitiveArrayEquals(componentType, expected, actual) : Arrays.equals((Object[]) expected, (Object[]) actual); + } + + private static boolean primitiveArrayEquals(Class componentType, Object expected, Object actual) { + if (componentType == boolean.class) { + return Arrays.equals((boolean[]) expected, (boolean[]) actual); + } + else if (componentType == byte.class) { + return Arrays.equals((byte[]) expected, (byte[]) actual); + } + else if (componentType == char.class) { + return Arrays.equals((char[]) expected, (char[]) actual); + } + else if (componentType == double.class) { + return Arrays.equals((double[]) expected, (double[]) actual); + } + else if (componentType == float.class) { + return Arrays.equals((float[]) expected, (float[]) actual); + } + else if (componentType == int.class) { + return Arrays.equals((int[]) expected, (int[]) actual); + } + else if (componentType == long.class) { + return Arrays.equals((long[]) expected, (long[]) actual); + } + else if (componentType == short.class) { + return Arrays.equals((short[]) expected, (short[]) actual); + } + + throw new AssertionError("Unsupported type:" + componentType); + } + + public void describeTo(final Description description) { + description.appendText("has value "); + description.appendValue(value); + } + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectoryTest.java new file mode 100644 index 00000000..bc583c44 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFDirectoryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.exif; + +import com.twelvemonkeys.imageio.metadata.CompoundDirectory; +import com.twelvemonkeys.imageio.metadata.CompoundDirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Directory; + +import java.util.Collection; + +/** + * EXIFDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: EXIFDirectoryTest.java,v 1.0 02.01.12 16:41 haraldk Exp$ + */ +public class EXIFDirectoryTest extends CompoundDirectoryAbstractTest { + @Override + protected CompoundDirectory createCompoundDirectory(Collection directories) { + return new EXIFDirectory(directories); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntryTest.java new file mode 100644 index 00000000..bc34b811 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntryTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2012, 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.exif; + +import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.EntryAbstractTest; +import org.junit.Test; + +/** + * EXIFEntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: EXIFEntryTest.java,v 1.0 02.01.12 17:35 haraldk Exp$ + */ +public class EXIFEntryTest 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); + } + + @Test(expected = IllegalArgumentException.class) + public void testCreateEXIFEntryIllegalType() { + createEXIFEntry(0, null, -1); + } + + // TODO: TIFF/EXIF specific tests +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReaderTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReaderTest.java new file mode 100644 index 00000000..f7d55011 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReaderTest.java @@ -0,0 +1,134 @@ +/* + * 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.exif; + +import com.twelvemonkeys.imageio.metadata.CompoundDirectory; +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest; +import org.junit.Test; + +import javax.imageio.ImageIO; +import java.io.IOException; +import java.io.InputStream; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +/** + * EXIFReaderTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: EXIFReaderTest.java,v 1.0 23.12.11 13:50 haraldk Exp$ + */ +public class EXIFReaderTest extends MetadataReaderAbstractTest { + @Override + protected InputStream getData() throws IOException { + return getResource("/exif/exif-jpeg-segment.bin").openStream(); + } + + @Override + protected EXIFReader createReader() { + return new EXIFReader(); + } + + @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)); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/IFDTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/IFDTest.java new file mode 100644 index 00000000..6d49f46a --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/IFDTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.exif; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.DirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * IFDTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: IFDTest.java,v 1.0 02.01.12 16:42 haraldk Exp$ + */ +public class IFDTest extends DirectoryAbstractTest { + @Override + protected Directory createDirectory(final Collection entries) { + return new IFD(entries); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/UnknownTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/UnknownTest.java new file mode 100644 index 00000000..06239ba9 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/exif/UnknownTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012, 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.exif; + +import com.twelvemonkeys.lang.ObjectAbstractTestCase; + +/** + * UnknownTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: UnknownTest.java,v 1.0 03.01.12 17:21 haraldk Exp$ + */ +public class UnknownTest extends ObjectAbstractTestCase { + @Override + protected Object makeObject() { + return new Unknown((short) 42, 77, (long) (Math.random() * (long) Integer.MAX_VALUE)); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCDirectoryTest.java new file mode 100644 index 00000000..4b7e82cc --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCDirectoryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.iptc; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.DirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * IPTCDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: IPTCDirectoryTest.java,v 1.0 03.01.12 09:40 haraldk Exp$ + */ +public class IPTCDirectoryTest extends DirectoryAbstractTest { + @Override + protected Directory createDirectory(final Collection entries) { + return new IPTCDirectory(entries); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntryTest.java new file mode 100644 index 00000000..860f422d --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCEntryTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 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.iptc; + +import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.EntryAbstractTest; + +/** + * IPTCEntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: IPTCEntryTest.java,v 1.0 03.01.12 09:39 haraldk Exp$ + */ +public class IPTCEntryTest extends EntryAbstractTest { + @Override + protected Entry createEntry(Object value) { + return new IPTCEntry(IPTC.TAG_BY_LINE, value); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReaderTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReaderTest.java new file mode 100644 index 00000000..8a68fab3 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/iptc/IPTCReaderTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, 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.iptc; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest; +import org.junit.Test; + +import javax.imageio.ImageIO; +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.Assert.*; + +/** + * IPTCReaderTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: IPTCReaderTest.java,v 1.0 04.01.12 09:43 haraldk Exp$ + */ +public class IPTCReaderTest extends MetadataReaderAbstractTest { + @Override + protected InputStream getData() throws IOException { + return getResource("/iptc/iptc-jpeg-segment.bin").openStream(); + } + + @Override + protected IPTCReader createReader() { + return new IPTCReader(); + } + + @Test + public void testDirectoryContent() throws IOException { + Directory directory = createReader().read(ImageIO.createImageInputStream(getData())); + + assertEquals(4, directory.size()); + + assertThat(directory.getEntryById(IPTC.TAG_RECORD_VERSION), hasValue(2)); // Mandatory + assertThat(directory.getEntryById(IPTC.TAG_CAPTION), hasValue("Picture 71146")); + assertThat(directory.getEntryById(IPTC.TAG_DATE_CREATED), hasValue("20080701")); + + // Weirdness: An undefined tag 2:56/0x0238 ?? + // Looks like it should be 2:60/TAG_TIME_CREATED, but doesn't match the time in the corresponding XMP/EXIF tags + assertThat(directory.getEntryById(IPTC.APPLICATION_RECORD | 56), hasValue("155029+0100")); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtilTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtilTest.java index fa847c2c..2a69d8b1 100644 --- a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtilTest.java +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtilTest.java @@ -58,8 +58,6 @@ public class JPEGSegmentUtilTest { IIORegistry.getDefaultInstance().registerServiceProvider(new URLImageInputStreamSpi()); } - // TODO: Test the JPEGSegment class?! - protected ImageInputStream getData(final String name) throws IOException { return ImageIO.createImageInputStream(getClass().getResource(name)); } @@ -97,7 +95,7 @@ public class JPEGSegmentUtilTest { @Test public void testReadAPP13Photoshop() throws IOException { - List segments = JPEGSegmentUtil.readSegments(getData("/jpeg/ts_open_300dpi.jpg"), 0xFFED, "Photoshop 3.0"); + List segments = JPEGSegmentUtil.readSegments(getData("/jpeg/ts_open_300dpi.jpg"), JPEG.APP13, "Photoshop 3.0"); assertEquals(1, segments.size()); JPEGSegment segment = segments.get(0); diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectoryTest.java new file mode 100644 index 00000000..5cf4e846 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDDirectoryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.DirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * PhotoshopDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopDirectoryTest.java,v 1.0 04.01.12 12:01 haraldk Exp$ + */ +public class PSDDirectoryTest extends DirectoryAbstractTest { + @Override + protected Directory createDirectory(final Collection entries) { + return new PSDDirectory(entries); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java new file mode 100644 index 00000000..0a361897 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.EntryAbstractTest; + +/** + * PhotoshopEntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopEntryTest.java,v 1.0 04.01.12 12:00 haraldk Exp$ + */ +public class PSDEntryTest extends EntryAbstractTest { + @Override + protected Entry createEntry(final Object value) { + return new PSDEntry(0x404, value); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDReaderTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDReaderTest.java new file mode 100644 index 00000000..90ca64fb --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDReaderTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012, 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.psd; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.MetadataReaderAbstractTest; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; + +import static org.junit.Assert.*; + +/** + * PhotoshopReaderTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PhotoshopReaderTest.java,v 1.0 04.01.12 12:01 haraldk Exp$ + */ +public class PSDReaderTest extends MetadataReaderAbstractTest { + @Override + protected InputStream getData() throws IOException { + return getResource("/psd/psd-jpeg-segment.bin").openStream(); + } + + @Override + protected PSDReader createReader() { + return new PSDReader(); + } + + @Test + public void testPhotoshopDirectoryContents() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertEquals(23, directory.size()); + + assertNotNull(directory.getEntryById(0x0404)); + assertNotNull(directory.getEntryById(0x0425)); + assertNotNull(directory.getEntryById(0x03ea)); + assertNotNull(directory.getEntryById(0x03e9)); + assertNotNull(directory.getEntryById(0x03ed)); + assertNotNull(directory.getEntryById(0x0426)); + + // TODO: More + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescriptionTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescriptionTest.java new file mode 100644 index 00000000..c4adc532 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/RDFDescriptionTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.xmp; + +import com.twelvemonkeys.imageio.metadata.Directory; +import com.twelvemonkeys.imageio.metadata.DirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Entry; + +import java.util.Collection; + +/** + * XMPDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: XMPDirectoryTest.java,v 1.0 03.01.12 09:42 haraldk Exp$ + */ +public class RDFDescriptionTest extends DirectoryAbstractTest { + @Override + protected Directory createDirectory(final Collection entries) { + return new RDFDescription(entries); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectoryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectoryTest.java new file mode 100644 index 00000000..883c0550 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPDirectoryTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 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.xmp; + +import com.twelvemonkeys.imageio.metadata.CompoundDirectory; +import com.twelvemonkeys.imageio.metadata.CompoundDirectoryAbstractTest; +import com.twelvemonkeys.imageio.metadata.Directory; + +import java.util.Collection; + +/** + * XMPDirectoryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: XMPDirectoryTest.java,v 1.0 03.01.12 09:42 haraldk Exp$ + */ +public class XMPDirectoryTest extends CompoundDirectoryAbstractTest { + @Override + protected CompoundDirectory createCompoundDirectory(final Collection directories) { + return new XMPDirectory(directories, null); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntryTest.java new file mode 100644 index 00000000..176561c5 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPEntryTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 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.xmp; + +import com.twelvemonkeys.imageio.metadata.Entry; +import com.twelvemonkeys.imageio.metadata.EntryAbstractTest; + +/** + * XMPEntryTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: XMPEntryTest.java,v 1.0 03.01.12 09:41 haraldk Exp$ + */ +public class XMPEntryTest extends EntryAbstractTest { + @Override + protected Entry createEntry(Object value) { + return new XMPEntry(XMP.NS_XAP + ":foo", value); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReaderTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReaderTest.java new file mode 100644 index 00000000..b66b2bd9 --- /dev/null +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPReaderTest.java @@ -0,0 +1,470 @@ +/* + * Copyright (c) 2012, 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.xmp; + +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 org.junit.Test; + +import javax.imageio.ImageIO; +import javax.imageio.stream.ImageInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.junit.Assert.*; + +/** + * XMPReaderTest + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: XMPReaderTest.java,v 1.0 04.01.12 10:47 haraldk Exp$ + */ +public class XMPReaderTest extends MetadataReaderAbstractTest { + + @Override + protected InputStream getData() throws IOException { + return getResource("/xmp/xmp-jpeg-example.xml").openStream(); + } + + private ImageInputStream getResourceAsIIS(final String name) throws IOException { + return ImageIO.createImageInputStream(getResource(name)); + } + + @Override + protected XMPReader createReader() { + return new XMPReader(); + } + + @Test + public void testDirectoryContent() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertEquals(29, directory.size()); + + // photoshop|http://ns.adobe.com/photoshop/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/DateCreated"), hasValue("2008-07-01")); + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/ColorMode"), hasValue("4")); + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/ICCProfile"), hasValue("U.S. Web Coated (SWOP) v2")); + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/History"), hasValue("")); + + // xapMM|http://ns.adobe.com/xap/1.0/mm/ + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DocumentID"), hasValue("uuid:54A8D5F8654711DD9226A85E1241887A")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/InstanceID"), hasValue("uuid:54A8D5F9654711DD9226A85E1241887A")); + + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DerivedFrom"), hasValue( + new RDFDescription(Arrays.asList( + // stRef|http://ns.adobe.com/xap/1.0/sType/ResourceRef# + new XMPEntry("http://ns.adobe.com/xap/1.0/sType/ResourceRef#instanceID", "instanceID", "uuid:3B52F3610F49DD118831FCA29C13B8DE"), + new XMPEntry("http://ns.adobe.com/xap/1.0/sType/ResourceRef#documentID", "documentID", "uuid:3A52F3610F49DD118831FCA29C13B8DE") + )) + )); + + // dc|http://purl.org/dc/elements/1.1/ + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/description"), hasValue(Collections.singletonMap("x-default", "Picture 71146"))); + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/format"), hasValue("image/jpeg")); + + // tiff|http://ns.adobe.com/tiff/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/ImageWidth"), hasValue("3601")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/ImageLength"), hasValue("4176")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/BitsPerSample"), hasValue(Arrays.asList("8", "8", "8"))); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/Compression"), hasValue("1")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/PhotometricInterpretation"), hasValue("2")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/SamplesPerPixel"), hasValue("3")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/PlanarConfiguration"), hasValue("1")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/XResolution"), hasValue("3000000/10000")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/YResolution"), hasValue("3000000/10000")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/ResolutionUnit"), hasValue("2")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/Orientation"), hasValue("1")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/NativeDigest"), hasValue("256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;C21EE6D33E4CCA3712ECB1F5E9031A49")); + + // xap|http://ns.adobe.com/xap/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/ModifyDate"), hasValue("2008-08-06T12:43:05+10:00")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/CreatorTool"), hasValue("Adobe Photoshop CS2 Macintosh")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/CreateDate"), hasValue("2008-08-06T12:43:05+10:00")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/MetadataDate"), hasValue("2008-08-06T12:43:05+10:00")); + + // exif|http://ns.adobe.com/exif/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/ColorSpace"), hasValue("-1")); // SIC + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/PixelXDimension"), hasValue("3601")); + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("4176")); + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;297AD344CC15F29D5283460ED026368F")); + } + + @Test + public void testCompoundDirectory() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + assertEquals(6, compound.directoryCount()); + + int size = 0; + for (int i = 0; i < compound.directoryCount(); i++) { + Directory sub = compound.getDirectory(i); + assertNotNull(sub); + size += sub.size(); + } + + assertEquals(directory.size(), size); + } + + @Test + public void testCompoundDirectoryContentPhotoshop() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // photoshop|http://ns.adobe.com/photoshop/1.0/ + Directory photoshop = compound.getDirectory(0); + assertEquals(4, photoshop.size()); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/DateCreated"), hasValue("2008-07-01")); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/ColorMode"), hasValue("4")); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/ICCProfile"), hasValue("U.S. Web Coated (SWOP) v2")); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/History"), hasValue("")); + + } + + @Test + public void testCompoundDirectoryContentMM() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // xapMM|http://ns.adobe.com/xap/1.0/mm/ + Directory mm = compound.getDirectory(1); + assertEquals(3, mm.size()); + assertThat(mm.getEntryById("http://ns.adobe.com/xap/1.0/mm/DocumentID"), hasValue("uuid:54A8D5F8654711DD9226A85E1241887A")); + assertThat(mm.getEntryById("http://ns.adobe.com/xap/1.0/mm/InstanceID"), hasValue("uuid:54A8D5F9654711DD9226A85E1241887A")); + assertThat(mm.getEntryById("http://ns.adobe.com/xap/1.0/mm/DerivedFrom"), hasValue( + new RDFDescription(Arrays.asList( + // stRef|http://ns.adobe.com/xap/1.0/sType/ResourceRef# + new XMPEntry("http://ns.adobe.com/xap/1.0/sType/ResourceRef#instanceID", "instanceID", "uuid:3B52F3610F49DD118831FCA29C13B8DE"), + new XMPEntry("http://ns.adobe.com/xap/1.0/sType/ResourceRef#documentID", "documentID", "uuid:3A52F3610F49DD118831FCA29C13B8DE") + )) + )); + + } + + @Test + public void testCompoundDirectoryContentDC() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // dc|http://purl.org/dc/elements/1.1/ + Directory dc = compound.getDirectory(2); + assertEquals(2, dc.size()); + assertThat(dc.getEntryById("http://purl.org/dc/elements/1.1/description"), hasValue(Collections.singletonMap("x-default", "Picture 71146"))); + assertThat(dc.getEntryById("http://purl.org/dc/elements/1.1/format"), hasValue("image/jpeg")); + + } + + @Test + public void testCompoundDirectoryContentTIFF() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // tiff|http://ns.adobe.com/tiff/1.0/ + Directory tiff = compound.getDirectory(3); + assertEquals(12, tiff.size()); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/ImageWidth"), hasValue("3601")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/ImageLength"), hasValue("4176")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/BitsPerSample"), hasValue(Arrays.asList("8", "8", "8"))); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/Compression"), hasValue("1")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/PhotometricInterpretation"), hasValue("2")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/SamplesPerPixel"), hasValue("3")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/PlanarConfiguration"), hasValue("1")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/XResolution"), hasValue("3000000/10000")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/YResolution"), hasValue("3000000/10000")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/ResolutionUnit"), hasValue("2")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/Orientation"), hasValue("1")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/NativeDigest"), hasValue("256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;C21EE6D33E4CCA3712ECB1F5E9031A49")); + } + + @Test + public void testCompoundDirectoryContentXAP() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // xap|http://ns.adobe.com/xap/1.0/ + Directory xap = compound.getDirectory(4); + assertEquals(4, xap.size()); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/ModifyDate"), hasValue("2008-08-06T12:43:05+10:00")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/CreatorTool"), hasValue("Adobe Photoshop CS2 Macintosh")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/CreateDate"), hasValue("2008-08-06T12:43:05+10:00")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/MetadataDate"), hasValue("2008-08-06T12:43:05+10:00")); + } + + @Test + public void testCompoundDirectoryContentEXIF() throws IOException { + Directory directory = createReader().read(getDataAsIIS()); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // exif|http://ns.adobe.com/exif/1.0/ + Directory exif = compound.getDirectory(5); + assertEquals(4, exif.size()); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/ColorSpace"), hasValue("-1")); // SIC. Same as unsigned short 65535, meaning "uncalibrated"? + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelXDimension"), hasValue("3601")); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("4176")); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;297AD344CC15F29D5283460ED026368F")); + } + + @Test + public void testRDFBag() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-bag-example.xml")); + + assertEquals(1, directory.size()); + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/subject"), hasValue(Arrays.asList("XMP", "metadata", "ISO standard"))); // Order does not matter + } + + @Test + public void testRDFSeq() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-seq-example.xml")); + + assertEquals(1, directory.size()); + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/subject"), hasValue(Arrays.asList("XMP", "metadata", "ISO standard"))); + } + + @Test + public void testRDFAlt() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-alt-example.xml")); + + assertEquals(1, directory.size()); + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/subject"), hasValue(new HashMap() {{ + put("x-default", "One"); + put("en-us", "One"); + put("de", "Ein"); + put("no-nb", "En"); + }})); + } + + @Test + public void testRDFAttributeSyntax() throws IOException { + // Alternate RDF syntax, using attribute values instead of nested tags + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertEquals(20, directory.size()); + + // dc|http://purl.org/dc/elements/1.1/ + assertThat(directory.getEntryById("http://purl.org/dc/elements/1.1/format"), hasValue("image/jpeg")); + + // xap|http://ns.adobe.com/xap/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/ModifyDate"), hasValue("2008-07-16T14:44:49-07:00")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/CreatorTool"), hasValue("Adobe Photoshop CS3 Windows")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/CreateDate"), hasValue("2008-07-16T14:44:49-07:00")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/MetadataDate"), hasValue("2008-07-16T14:44:49-07:00")); + + // tiff|http://ns.adobe.com/tiff/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/Orientation"), hasValue("1")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/XResolution"), hasValue("720000/10000")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/YResolution"), hasValue("720000/10000")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/ResolutionUnit"), hasValue("2")); + assertThat(directory.getEntryById("http://ns.adobe.com/tiff/1.0/NativeDigest"), hasValue("256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;C08D8E93274C4BEE83E86CF999955A87")); + + // exif|http://ns.adobe.com/exif/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/ColorSpace"), hasValue("-1")); // SIC. Same as unsigned short 65535, meaning "uncalibrated"? + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/PixelXDimension"), hasValue("426")); + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("550")); + assertThat(directory.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA")); + + // photoshop|http://ns.adobe.com/photoshop/1.0/ + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/ColorMode"), hasValue("1")); + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/ICCProfile"), hasValue("Dot Gain 20%")); + assertThat(directory.getEntryById("http://ns.adobe.com/photoshop/1.0/History"), hasValue("")); + + // xapMM|http://ns.adobe.com/xap/1.0/mm/ + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DocumentID"), hasValue("uuid:6DCA50CC7D53DD119F20F5A7EA4C9BEC")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/InstanceID"), hasValue("uuid:6ECA50CC7D53DD119F20F5A7EA4C9BEC")); + + // Custom test, as NamedNodeMap does not preserve order (tests can't rely on XML impl specifics) + Entry derivedFrom = directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DerivedFrom"); + assertNotNull(derivedFrom); + assertThat(derivedFrom.getValue(), instanceOf(RDFDescription.class)); + + // stRef|http://ns.adobe.com/xap/1.0/sType/ResourceRef# + RDFDescription stRef = (RDFDescription) derivedFrom.getValue(); + assertThat(stRef.getEntryById("http://ns.adobe.com/xap/1.0/sType/ResourceRef#instanceID"), hasValue("uuid:74E1C905B405DD119306A1902BA5AA28")); + assertThat(stRef.getEntryById("http://ns.adobe.com/xap/1.0/sType/ResourceRef#documentID"), hasValue("uuid:7A6C79768005DD119306A1902BA5AA28")); + } + + @Test + public void testRDFAttributeSyntaxCompound() throws IOException { + // Alternate RDF syntax, using attribute values instead of nested tags + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + assertEquals(6, compound.directoryCount()); + + int size = 0; + for (int i = 0; i < compound.directoryCount(); i++) { + Directory sub = compound.getDirectory(i); + assertNotNull(sub); + size += sub.size(); + } + + assertEquals(directory.size(), size); + } + + private Directory getDirectoryByNS(final CompoundDirectory compound, final String namespace) { + for (int i = 0; i < compound.directoryCount(); i++) { + Directory candidate = compound.getDirectory(i); + + Iterator entries = candidate.iterator(); + if (entries.hasNext()) { + Entry entry = entries.next(); + if (entry.getIdentifier() instanceof String && ((String) entry.getIdentifier()).startsWith(namespace)) { + return candidate; + } + } + } + + return null; + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentPhotoshop() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // photoshop|http://ns.adobe.com/photoshop/1.0/ + Directory photoshop = getDirectoryByNS(compound, XMP.NS_PHOTOSHOP); + + assertEquals(3, photoshop.size()); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/ColorMode"), hasValue("1")); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/ICCProfile"), hasValue("Dot Gain 20%")); + assertThat(photoshop.getEntryById("http://ns.adobe.com/photoshop/1.0/History"), hasValue("")); + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentMM() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // xapMM|http://ns.adobe.com/xap/1.0/mm/ + Directory mm = getDirectoryByNS(compound, XMP.NS_XAP_MM); + assertEquals(3, mm.size()); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DocumentID"), hasValue("uuid:6DCA50CC7D53DD119F20F5A7EA4C9BEC")); + assertThat(directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/InstanceID"), hasValue("uuid:6ECA50CC7D53DD119F20F5A7EA4C9BEC")); + + // Custom test, as NamedNodeMap does not preserve order (tests can't rely on XML impl specifics) + Entry derivedFrom = directory.getEntryById("http://ns.adobe.com/xap/1.0/mm/DerivedFrom"); + assertNotNull(derivedFrom); + assertThat(derivedFrom.getValue(), instanceOf(RDFDescription.class)); + + // stRef|http://ns.adobe.com/xap/1.0/sType/ResourceRef# + RDFDescription stRef = (RDFDescription) derivedFrom.getValue(); + assertThat(stRef.getEntryById("http://ns.adobe.com/xap/1.0/sType/ResourceRef#instanceID"), hasValue("uuid:74E1C905B405DD119306A1902BA5AA28")); + assertThat(stRef.getEntryById("http://ns.adobe.com/xap/1.0/sType/ResourceRef#documentID"), hasValue("uuid:7A6C79768005DD119306A1902BA5AA28")); + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentDC() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // dc|http://purl.org/dc/elements/1.1/ + Directory dc = getDirectoryByNS(compound, XMP.NS_DC); + assertEquals(1, dc.size()); + + assertThat(dc.getEntryById("http://purl.org/dc/elements/1.1/format"), hasValue("image/jpeg")); + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentTIFF() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // tiff|http://ns.adobe.com/tiff/1.0/ + Directory tiff = getDirectoryByNS(compound, XMP.NS_TIFF); + assertEquals(5, tiff.size()); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/Orientation"), hasValue("1")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/XResolution"), hasValue("720000/10000")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/YResolution"), hasValue("720000/10000")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/ResolutionUnit"), hasValue("2")); + assertThat(tiff.getEntryById("http://ns.adobe.com/tiff/1.0/NativeDigest"), hasValue("256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;C08D8E93274C4BEE83E86CF999955A87")); + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentXAP() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // xap|http://ns.adobe.com/xap/1.0/ + Directory xap = getDirectoryByNS(compound, XMP.NS_XAP); + assertEquals(4, xap.size()); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/ModifyDate"), hasValue("2008-07-16T14:44:49-07:00")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/CreatorTool"), hasValue("Adobe Photoshop CS3 Windows")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/CreateDate"), hasValue("2008-07-16T14:44:49-07:00")); + assertThat(xap.getEntryById("http://ns.adobe.com/xap/1.0/MetadataDate"), hasValue("2008-07-16T14:44:49-07:00")); + } + + @Test + public void testRDFAttributeSyntaxCompoundDirectoryContentEXIF() throws IOException { + Directory directory = createReader().read(getResourceAsIIS("/xmp/rdf-attribute-shorthand.xml")); + + assertThat(directory, instanceOf(CompoundDirectory.class)); + CompoundDirectory compound = (CompoundDirectory) directory; + + // exif|http://ns.adobe.com/exif/1.0/ + Directory exif = getDirectoryByNS(compound, XMP.NS_EXIF); + assertEquals(4, exif.size()); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/ColorSpace"), hasValue("-1")); // SIC. Same as unsigned short 65535, meaning "uncalibrated"? + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelXDimension"), hasValue("426")); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/PixelYDimension"), hasValue("550")); + assertThat(exif.getEntryById("http://ns.adobe.com/exif/1.0/NativeDigest"), hasValue("36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;A7F21D25E2C562F152B2C4ECC9E534DA")); + } +} diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScannerTestCase.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScannerTestCase.java index 4115998a..450d4d8b 100644 --- a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScannerTestCase.java +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/xmp/XMPScannerTestCase.java @@ -1,6 +1,6 @@ package com.twelvemonkeys.imageio.metadata.xmp; -import junit.framework.TestCase; +import org.junit.Test; import java.io.*; import java.nio.charset.UnsupportedCharsetException; @@ -8,6 +8,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.Random; +import static org.junit.Assert.*; + /** * XMPScannerTestCase * @@ -15,8 +17,7 @@ import java.util.Random; * @author last modified by $Author: haraldk$ * @version $Id: XMPScannerTestCase.java,v 1.0 Nov 13, 2009 3:59:43 PM haraldk Exp$ */ -public class XMPScannerTestCase extends TestCase { - +public class XMPScannerTestCase { static final String XMP = "" + "\n"+ @@ -33,11 +34,11 @@ public class XMPScannerTestCase extends TestCase { "" + ""; - final Random mRandom = new Random(4934638567l); + final Random random = new Random(4934638567l); private InputStream createRandomStream(final int pLength) { byte[] bytes = new byte[pLength]; - mRandom.nextBytes(bytes); + random.nextBytes(bytes); return new ByteArrayInputStream(bytes); } @@ -60,6 +61,7 @@ public class XMPScannerTestCase extends TestCase { } } + @Test public void testScanForUTF8() throws IOException { InputStream stream = createXMPStream(XMP, "UTF-8"); @@ -68,7 +70,8 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } - public void testScanForUTF8singleQuote() throws IOException { + @Test + public void testScanForUTF8SingleQuote() throws IOException { InputStream stream = createXMPStream(XMP.replace("\"", "'"), "UTF-8"); Reader reader = XMPScanner.scanForXMPPacket(stream); @@ -76,6 +79,7 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } + @Test public void testScanForUTF16BE() throws IOException { InputStream stream = createXMPStream(XMP, "UTF-16BE"); @@ -84,7 +88,8 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } - public void testScanForUTF16BEsingleQuote() throws IOException { + @Test + public void testScanForUTF16BESingleQuote() throws IOException { InputStream stream = createXMPStream(XMP.replace("\"", "'"), "UTF-16BE"); Reader reader = XMPScanner.scanForXMPPacket(stream); @@ -92,6 +97,7 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } + @Test public void testScanForUTF16LE() throws IOException { InputStream stream = createXMPStream(XMP, "UTF-16LE"); @@ -100,7 +106,8 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } - public void testScanForUTF16LEsingleQuote() throws IOException { + @Test + public void testScanForUTF16LESingleQuote() throws IOException { InputStream stream = createXMPStream(XMP.replace("\"", "'"), "UTF-16LE"); Reader reader = XMPScanner.scanForXMPPacket(stream); @@ -108,20 +115,31 @@ public class XMPScannerTestCase extends TestCase { assertNotNull(reader); } - // TODO: Default Java installation on OS X don't seem to have UTF-32 installed. Hmmm.. -// public void testUTF32BE() throws IOException { -// InputStream stream = createXMPStream("UTF-32BE"); -// -// Reader reader = XMPScanner.scanForXMPPacket(stream); -// -// assertNotNull(reader); -// } -// -// public void testUTF32LE() throws IOException { -// InputStream stream = createXMPStream("UTF-32LE"); -// -// Reader reader = XMPScanner.scanForXMPPacket(stream); -// -// assertNotNull(reader); -// } + @Test + public void testUTF32BE() throws IOException { + try { + InputStream stream = createXMPStream(XMP, "UTF-32BE"); + + Reader reader = XMPScanner.scanForXMPPacket(stream); + + assertNotNull(reader); + } + catch (UnsupportedCharsetException ignore) { + System.err.println("Warning: Unsupported charset. Test skipped. " + ignore); + } + } + + @Test + public void testUTF32LE() throws IOException { + try { + InputStream stream = createXMPStream(XMP, "UTF-32LE"); + + Reader reader = XMPScanner.scanForXMPPacket(stream); + + assertNotNull(reader); + } + catch (UnsupportedCharsetException ignore) { + System.err.println("Warning: Unsupported charset. Test skipped. " + ignore); + } + } } diff --git a/imageio/imageio-metadata/src/test/resources/exif/exif-jpeg-segment.bin b/imageio/imageio-metadata/src/test/resources/exif/exif-jpeg-segment.bin new file mode 100644 index 00000000..1e8f482b Binary files /dev/null and b/imageio/imageio-metadata/src/test/resources/exif/exif-jpeg-segment.bin differ diff --git a/imageio/imageio-metadata/src/test/resources/iptc/iptc-jpeg-segment.bin b/imageio/imageio-metadata/src/test/resources/iptc/iptc-jpeg-segment.bin new file mode 100644 index 00000000..fc9d6173 Binary files /dev/null and b/imageio/imageio-metadata/src/test/resources/iptc/iptc-jpeg-segment.bin differ diff --git a/imageio/imageio-metadata/src/test/resources/psd/psd-jpeg-segment.bin b/imageio/imageio-metadata/src/test/resources/psd/psd-jpeg-segment.bin new file mode 100644 index 00000000..ebaeece3 Binary files /dev/null and b/imageio/imageio-metadata/src/test/resources/psd/psd-jpeg-segment.bin differ diff --git a/imageio/imageio-metadata/src/test/resources/xmp/rdf-alt-example.xml b/imageio/imageio-metadata/src/test/resources/xmp/rdf-alt-example.xml new file mode 100644 index 00000000..54c681b2 --- /dev/null +++ b/imageio/imageio-metadata/src/test/resources/xmp/rdf-alt-example.xml @@ -0,0 +1,13 @@ + + + + + + One + One + Ein + En + + + + diff --git a/imageio/imageio-metadata/src/test/resources/xmp/rdf-attribute-shorthand.xml b/imageio/imageio-metadata/src/test/resources/xmp/rdf-attribute-shorthand.xml new file mode 100644 index 00000000..6c1306ca --- /dev/null +++ b/imageio/imageio-metadata/src/test/resources/xmp/rdf-attribute-shorthand.xml @@ -0,0 +1,32 @@ + + + + + + + + \ No newline at end of file diff --git a/imageio/imageio-metadata/src/test/resources/xmp/rdf-bag-example.xml b/imageio/imageio-metadata/src/test/resources/xmp/rdf-bag-example.xml new file mode 100644 index 00000000..193fb660 --- /dev/null +++ b/imageio/imageio-metadata/src/test/resources/xmp/rdf-bag-example.xml @@ -0,0 +1,12 @@ + + + + + + XMP + metadata + ISO standard + + + + diff --git a/imageio/imageio-metadata/src/test/resources/xmp/rdf-seq-example.xml b/imageio/imageio-metadata/src/test/resources/xmp/rdf-seq-example.xml new file mode 100644 index 00000000..c1112e92 --- /dev/null +++ b/imageio/imageio-metadata/src/test/resources/xmp/rdf-seq-example.xml @@ -0,0 +1,12 @@ + + + + + + XMP + metadata + ISO standard + + + + diff --git a/imageio/imageio-metadata/src/test/resources/xmp/xmp-jpeg-example.xml b/imageio/imageio-metadata/src/test/resources/xmp/xmp-jpeg-example.xml new file mode 100644 index 00000000..b3f3e412 --- /dev/null +++ b/imageio/imageio-metadata/src/test/resources/xmp/xmp-jpeg-example.xml @@ -0,0 +1,187 @@ + + + + + 2008-07-01 + 4 + U.S. Web Coated (SWOP) v2 + + + + uuid:54A8D5F8654711DD9226A85E1241887A + uuid:54A8D5F9654711DD9226A85E1241887A + + uuid:3B52F3610F49DD118831FCA29C13B8DE + uuid:3A52F3610F49DD118831FCA29C13B8DE + + + + + + Picture 71146 + + + image/jpeg + + + 3601 + 4176 + + + 8 + 8 + 8 + + + 1 + 2 + 3 + 1 + 3000000/10000 + 3000000/10000 + 2 + 1 + 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;C21EE6D33E4CCA3712ECB1F5E9031A49 + + + 2008-08-06T12:43:05+10:00 + Adobe Photoshop CS2 Macintosh + 2008-08-06T12:43:05+10:00 + 2008-08-06T12:43:05+10:00 + + + -1 + 3601 + 4176 + 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;297AD344CC15F29D5283460ED026368F + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file