Massive metadata cleanup, new test cases and bugfix.

This commit is contained in:
Harald Kuhr 2012-01-13 17:16:59 +01:00
parent 529377aa01
commit 84a2e8b10c
55 changed files with 3155 additions and 131 deletions

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Directory> directories = new ArrayList<Directory>();
protected AbstractCompoundDirectory(final Collection<? extends Directory> 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<Entry> iterator() {
return new Iterator<Entry>() {
Iterator<Directory> directoryIterator = directories.iterator();
Iterator<Entry> 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;
}
}

View File

@ -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<Entry> entries = new ArrayList<Entry>();
private final List<Entry> unmodifiable = Collections.unmodifiableList(entries);
protected AbstractDirectory(final Collection<? extends Entry> pEntries) {
if (pEntries != null) {
entries.addAll(pEntries);
protected AbstractDirectory(final Collection<? extends Entry> entries) {
if (entries != null) {
this.entries.addAll(noNullElements(entries));
}
}
@ -70,7 +70,7 @@ public abstract class AbstractDirectory implements Directory {
}
public Iterator<Entry> 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;
}

View File

@ -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);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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();
}

View File

@ -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

View File

@ -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<? extends Entry> entries) {
super(entries);
final class EXIFDirectory extends AbstractCompoundDirectory {
EXIFDirectory(final Collection<? extends Directory> directories) {
super(directories);
}
}

View File

@ -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:

View File

@ -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<Integer> KNOWN_IFDS = Arrays.asList(TIFF.TAG_EXIF_IFD, TIFF.TAG_GPS_IFD, TIFF.TAG_INTEROP_IFD);
static final Collection<Integer> 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<IFD> ifds = new ArrayList<IFD>();
List<Entry> entries = new ArrayList<Entry>();
pInput.seek(pOffset);
int entryCount = pInput.readUnsignedShort();
@ -95,11 +97,12 @@ public final class EXIFReader extends MetadataReader {
// 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()));
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<? extends Entry> pEntries) {
super(pEntries);
}
}

View File

@ -6,6 +6,7 @@ package com.twelvemonkeys.imageio.metadata.exif;
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: Unknown.java,v 1.0 Oct 8, 2010 3:38:45 PM haraldk Exp$
* @see <a href="http://en.wikipedia.org/wiki/There_are_known_knowns">There are known knowns</a>
*/
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;
}

View File

@ -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);
}
}

View File

@ -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<Entry> entries = new ArrayList<Entry>();
Validate.notNull(input, "input");
List<Entry> entries = new ArrayList<Entry>();
// 0x1c identifies start of a tag
while (input.read() == 0x1c) {

View File

@ -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;

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<? extends Entry> entries) {
super(entries);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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());
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Segment>
@Override
public Directory read(final ImageInputStream input) throws IOException {
Validate.notNull(input, "input");
List<PSDEntry> entries = new ArrayList<PSDEntry>();
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;
}
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<? extends Entry> entries) {
this(null, entries);
}
public RDFDescription(String key, Collection<? extends Entry> 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();
}
}

View File

@ -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<String, String> DEFAULT_NS_MAPPING = Collections.unmodifiableMap(new XMPNamespaceMapping());
Map<String, String> DEFAULT_NS_MAPPING = Collections.unmodifiableMap(new XMPNamespaceMapping(true));
Set<String> ELEMENTS = Collections.unmodifiableSet(new XMPNamespaceMapping(false).keySet());
}

View File

@ -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<Entry> entries) {
private final String toolkit;
public XMPDirectory(Collection<? extends Directory> 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 <?xpacket end="w"?>/<?xpacket end="r"?> 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();
}
}

View File

@ -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);
}
}

View File

@ -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<String, String> {
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");

View File

@ -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<String, List<Entry>> subdirs = new LinkedHashMap<String, List<Entry>>();
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<Entry> entries = new ArrayList<Entry>();
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<String, List<Entry>> subsubdirs = new LinkedHashMap<String, List<Entry>>();
value = getChildTextValue(node);
parseAttributesForKnownElements(subsubdirs, node);
if (!subsubdirs.isEmpty()) {
List<Entry> entries = new ArrayList<Entry>();
for (Map.Entry<String, List<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<Entry> entries = new ArrayList<Entry>();
List<Directory> entries = new ArrayList<Directory>();
// TODO: Should we still allow asking for a subdirectory by item id?
for (Map.Entry<String, List<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<String, List<Entry>> 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<Entry> dir = subdirs.get(attr.getNamespaceURI());
if (dir == null) {
dir = new ArrayList<Entry>();
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 <rdf:Alt><rdf:li> -> return a Map<String, Object> (keyed on xml:lang?)
Map<String, Object> alternatives = new LinkedHashMap<String, Object>();
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 <rdf:Seq><rdf:li> -> return array
// Support for <rdf:Bag><rdf:li> -> return array/unordered collection (how can a serialized collection not have order?)
List<Object> seq = new ArrayList<Object>();
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<? extends Node> asIterable(final NamedNodeMap pNodeList) {
return new Iterable<Node>() {
public Iterator<Node> iterator() {
return new Iterator<Node>() {
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<Node>() {
public Iterator<Node> iterator() {
return new Iterator<Node>() {
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 {
}
};
}
}

View File

@ -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");
// }
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Directory> directories) {
return new AbstractCompoundDirectory(directories) {};
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> entries) {
return new AbstractDirectory(entries) {};
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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());
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Directory> directories);
// Override by subclasses that require special kind of directory
protected Directory createSingleDirectory(final Collection<Entry> entries) {
return new TestDirectory(entries);
}
@Override
protected final Directory createDirectory(final Collection<Entry> entries) {
// A compound directory should behave like a normal directory
return createCompoundDirectory(Collections.<Directory>singleton(createSingleDirectory(entries)));
}
@Test(expected = IllegalArgumentException.class)
public void testCreateNullDirectories() {
createCompoundDirectory(Collections.<Directory>singleton(null));
}
@Test
public void testSingle() {
Directory only = createSingleDirectory(null);
CompoundDirectory directory = createCompoundDirectory(Collections.<Directory>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.<Directory>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.<Directory>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.<Directory>singleton(only));
directory.getDirectory(directory.directoryCount());
}
protected static final class TestDirectory extends AbstractDirectory {
public TestDirectory(final Collection<Entry> entries) {
super(entries);
}
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> 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.<Entry>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<Entry> 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<Entry> all = Arrays.asList(one, two, three);
Directory directory = createDirectory(all);
// Test that each element is contained, and only once
List<Entry> entries = new ArrayList<Entry>(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);
}
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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());
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> hasValue(final Object value) {
return new EntryHasValue(value);
}
private static class EntryHasValue extends TypeSafeMatcher<Entry> {
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);
}
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: EXIFDirectoryTest.java,v 1.0 02.01.12 16:41 haraldk Exp$
*/
public class EXIFDirectoryTest extends CompoundDirectoryAbstractTest {
@Override
protected CompoundDirectory createCompoundDirectory(Collection<Directory> directories) {
return new EXIFDirectory(directories);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: EXIFEntryTest.java,v 1.0 02.01.12 17:35 haraldk Exp$
*/
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
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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));
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> entries) {
return new IFD(entries);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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));
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> entries) {
return new IPTCDirectory(entries);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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"));
}
}

View File

@ -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<JPEGSegment> segments = JPEGSegmentUtil.readSegments(getData("/jpeg/ts_open_300dpi.jpg"), 0xFFED, "Photoshop 3.0");
List<JPEGSegment> segments = JPEGSegmentUtil.readSegments(getData("/jpeg/ts_open_300dpi.jpg"), JPEG.APP13, "Photoshop 3.0");
assertEquals(1, segments.size());
JPEGSegment segment = segments.get(0);

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> entries) {
return new PSDDirectory(entries);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Entry> entries) {
return new RDFDescription(entries);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<Directory> directories) {
return new XMPDirectory(directories, null);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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);
}
}

View File

@ -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 <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @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<String, String>() {{
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<Entry> 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"));
}
}

View File

@ -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 =
"<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>" +
"<x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"Adobe XMP Core 4.1-c036 46.276720, Fri Nov 13 2009 15:59:43 \">\n"+
@ -33,11 +34,11 @@ public class XMPScannerTestCase extends TestCase {
"</x:xmpmeta>" +
"<?xpacket end=\"w\"?>";
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);
}
}
}

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description rdf:about="">
<dc:subject>
<rdf:Alt>
<rdf:li xml:lang="x-default">One</rdf:li>
<rdf:li xml:lang="en-us">One</rdf:li>
<rdf:li xml:lang="de">Ein</rdf:li>
<rdf:li xml:lang="no-nb">En</rdf:li>
</rdf:Alt>
</dc:subject>
</rdf:Description>
</rdf:RDF>

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 4.1-c036 46.276720, Mon Feb 19 2007 22:40:08 ">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xap="http://ns.adobe.com/xap/1.0/" xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
xmlns:tiff="http://ns.adobe.com/tiff/1.0/" xmlns:exif="http://ns.adobe.com/exif/1.0/"
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/"
dc:format="image/jpeg"
xap:CreatorTool="Adobe Photoshop CS3 Windows"
xap:CreateDate="2008-07-16T14:44:49-07:00"
xap:ModifyDate="2008-07-16T14:44:49-07:00"
xap:MetadataDate="2008-07-16T14:44:49-07:00"
xapMM:DocumentID="uuid:6DCA50CC7D53DD119F20F5A7EA4C9BEC"
xapMM:InstanceID="uuid:6ECA50CC7D53DD119F20F5A7EA4C9BEC"
tiff:Orientation="1"
tiff:XResolution="720000/10000"
tiff:YResolution="720000/10000"
tiff:ResolutionUnit="2"
tiff:NativeDigest="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:PixelXDimension="426"
exif:PixelYDimension="550"
exif:ColorSpace="-1"
exif:NativeDigest="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:ColorMode="1"
photoshop:ICCProfile="Dot Gain 20%"
photoshop:History="">
<xapMM:DerivedFrom stRef:instanceID="uuid:74E1C905B405DD119306A1902BA5AA28"
stRef:documentID="uuid:7A6C79768005DD119306A1902BA5AA28"/>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description rdf:about="">
<dc:subject>
<rdf:Bag>
<rdf:li>XMP</rdf:li>
<rdf:li>metadata</rdf:li>
<rdf:li>ISO standard</rdf:li>
</rdf:Bag>
</dc:subject>
</rdf:Description>
</rdf:RDF>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
<rdf:Description rdf:about="">
<dc:subject>
<rdf:Seq>
<rdf:li>XMP</rdf:li>
<rdf:li>metadata</rdf:li>
<rdf:li>ISO standard</rdf:li>
</rdf:Seq>
</dc:subject>
</rdf:Description>
</rdf:RDF>

View File

@ -0,0 +1,187 @@
<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="3.1.1-111">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about=""
xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
<photoshop:DateCreated>2008-07-01</photoshop:DateCreated>
<photoshop:ColorMode>4</photoshop:ColorMode>
<photoshop:ICCProfile>U.S. Web Coated (SWOP) v2</photoshop:ICCProfile>
<photoshop:History/>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xapMM="http://ns.adobe.com/xap/1.0/mm/"
xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
<xapMM:DocumentID>uuid:54A8D5F8654711DD9226A85E1241887A</xapMM:DocumentID>
<xapMM:InstanceID>uuid:54A8D5F9654711DD9226A85E1241887A</xapMM:InstanceID>
<xapMM:DerivedFrom rdf:parseType="Resource">
<stRef:instanceID>uuid:3B52F3610F49DD118831FCA29C13B8DE</stRef:instanceID>
<stRef:documentID>uuid:3A52F3610F49DD118831FCA29C13B8DE</stRef:documentID>
</xapMM:DerivedFrom>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:dc="http://purl.org/dc/elements/1.1/">
<dc:description>
<rdf:Alt>
<rdf:li xml:lang="x-default">Picture 71146</rdf:li>
</rdf:Alt>
</dc:description>
<dc:format>image/jpeg</dc:format>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:tiff="http://ns.adobe.com/tiff/1.0/">
<tiff:ImageWidth>3601</tiff:ImageWidth>
<tiff:ImageLength>4176</tiff:ImageLength>
<tiff:BitsPerSample>
<rdf:Seq>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
<rdf:li>8</rdf:li>
</rdf:Seq>
</tiff:BitsPerSample>
<tiff:Compression>1</tiff:Compression>
<tiff:PhotometricInterpretation>2</tiff:PhotometricInterpretation>
<tiff:SamplesPerPixel>3</tiff:SamplesPerPixel>
<tiff:PlanarConfiguration>1</tiff:PlanarConfiguration>
<tiff:XResolution>3000000/10000</tiff:XResolution>
<tiff:YResolution>3000000/10000</tiff:YResolution>
<tiff:ResolutionUnit>2</tiff:ResolutionUnit>
<tiff:Orientation>1</tiff:Orientation>
<tiff:NativeDigest>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</tiff:NativeDigest>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:xap="http://ns.adobe.com/xap/1.0/">
<xap:ModifyDate>2008-08-06T12:43:05+10:00</xap:ModifyDate>
<xap:CreatorTool>Adobe Photoshop CS2 Macintosh</xap:CreatorTool>
<xap:CreateDate>2008-08-06T12:43:05+10:00</xap:CreateDate>
<xap:MetadataDate>2008-08-06T12:43:05+10:00</xap:MetadataDate>
</rdf:Description>
<rdf:Description rdf:about=""
xmlns:exif="http://ns.adobe.com/exif/1.0/">
<exif:ColorSpace>-1</exif:ColorSpace>
<exif:PixelXDimension>3601</exif:PixelXDimension>
<exif:PixelYDimension>4176</exif:PixelYDimension>
<exif:NativeDigest>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</exif:NativeDigest>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>
<?xpacket end="w"?>