diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java index d9b59dc3..9b5170ab 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/AbstractEntry.java @@ -29,6 +29,7 @@ package com.twelvemonkeys.imageio.metadata; import com.twelvemonkeys.lang.Validate; +import com.twelvemonkeys.util.CollectionUtil; import java.lang.reflect.Array; import java.util.Arrays; @@ -83,41 +84,13 @@ public abstract class AbstractEntry implements Entry { public String getValueAsString() { if (valueCount() > 1) { if (valueCount() < 16) { - Class type = value.getClass().getComponentType(); - - if (type.isPrimitive()) { - if (type.equals(boolean.class)) { - return Arrays.toString((boolean[]) value); - } - else if (type.equals(byte.class)) { - return Arrays.toString((byte[]) value); - } - else if (type.equals(char.class)) { - return new String((char[]) value); - } - else if (type.equals(double.class)) { - return Arrays.toString((double[]) value); - } - else if (type.equals(float.class)) { - return Arrays.toString((float[]) value); - } - else if (type.equals(int.class)) { - return Arrays.toString((int[]) value); - } - else if (type.equals(long.class)) { - return Arrays.toString((long[]) value); - } - else if (type.equals(short.class)) { - return Arrays.toString((short[]) value); - } - // Fall through should never happen - } - else { - return Arrays.toString((Object[]) value); - } + return arrayToString(value); + } + else { + String first = arrayToString(CollectionUtil.subArray(value, 0, 4)); + String last = arrayToString(CollectionUtil.subArray(value, valueCount() - 4, 4)); + return String.format("%s ... %s (%d)", first.substring(0, first.length() - 1), last.substring(1), valueCount()); } - - return String.valueOf(value) + " (" + valueCount() + ")"; } if (value != null && value.getClass().isArray() && Array.getLength(value) == 1) { @@ -127,6 +100,44 @@ public abstract class AbstractEntry implements Entry { return String.valueOf(value); } + private static String arrayToString(final Object value) { + Class type = value.getClass().getComponentType(); + + if (type.isPrimitive()) { + if (type.equals(boolean.class)) { + return Arrays.toString((boolean[]) value); + } + else if (type.equals(byte.class)) { + return Arrays.toString((byte[]) value); + } + else if (type.equals(char.class)) { + return new String((char[]) value); + } + else if (type.equals(double.class)) { + return Arrays.toString((double[]) value); + } + else if (type.equals(float.class)) { + return Arrays.toString((float[]) value); + } + else if (type.equals(int.class)) { + return Arrays.toString((int[]) value); + } + else if (type.equals(long.class)) { + return Arrays.toString((long[]) value); + } + else if (type.equals(short.class)) { + return Arrays.toString((short[]) value); + } + else { + // Fall through should never happen + throw new AssertionError("Unknown type: " + type); + } + } + else { + return Arrays.toString((Object[]) value); + } + } + public String getTypeName() { if (value == null) { return null; diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java index bb8e1d0d..0449b4c6 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFEntry.java @@ -72,6 +72,8 @@ final class EXIFEntry extends AbstractEntry { return "ImageWidth"; case TIFF.TAG_IMAGE_HEIGHT: return "ImageHeight"; + case TIFF.TAG_BITS_PER_SAMPLE: + return "BitsPerSample"; case TIFF.TAG_COMPRESSION: return "Compression"; case TIFF.TAG_PHOTOMETRIC_INTERPRETATION: diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java index 966482f3..b7661e19 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/exif/EXIFReader.java @@ -213,6 +213,7 @@ public final class EXIFReader extends MetadataReader { short type = pInput.readShort(); int count = pInput.readInt(); // Number of values + // TODO: Read up what the spec says about value-count == 0, it makes no sense. if (count < 0) { throw new IIOException(String.format("Illegal count %d for tag %s type %s @%08x", count, tagId, type, pInput.getStreamPosition())); } @@ -242,7 +243,7 @@ public final class EXIFReader extends MetadataReader { } } - // TODO: For BigTiff allow size <= 8 + // TODO: For BigTiff allow size > 4 && <= 8 if (valueLength > 0 && valueLength <= 4) { value = readValueInLine(pInput, type, count); pInput.skipBytes(4 - valueLength); diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java index dd2f781b..e0b4677e 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEG.java @@ -36,16 +36,32 @@ package com.twelvemonkeys.imageio.metadata.jpeg; * @version $Id: JPEG.java,v 1.0 11.02.11 15.51 haraldk Exp$ */ public interface JPEG { + /** Start of Image segment marker. */ int SOI = 0xFFD8; + /** End of Image segment marker. */ int EOI = 0xFFD9; + /** Start of Stream segment marker. */ int SOS = 0xFFDA; + // App segment markers (APPn) int APP0 = 0xFFE0; int APP1 = 0xFFE1; int APP2 = 0xFFE2; + int APP3 = 0xFFE3; + int APP4 = 0xFFE4; + int APP5 = 0xFFE5; + int APP6 = 0xFFE6; + int APP7 = 0xFFE7; + int APP8 = 0xFFE8; + int APP9 = 0xFFE9; + int APP10 = 0xFFEA; + int APP11 = 0xFFEB; + int APP12 = 0xFFEC; int APP13 = 0xFFED; int APP14 = 0xFFEE; + int APP15 = 0xFFEF; + // Start of Frame segment markers (SOFn) int SOF0 = 0xFFC0; int SOF1 = 0xFFC1; int SOF2 = 0xFFC2; @@ -59,4 +75,15 @@ public interface JPEG { int SOF13 = 0xFFCD; int SOF14 = 0xFFCE; int SOF15 = 0xFFCF; + + // TODO: Known/Important APPn markers + // "JFIF" APP0 + // "JFXX" APP0 + // "Exif" APP1 + // "ICC_PROFILE" APP2 + // "Adobe" APP14 + + // Possibly + // "http://ns.adobe.com/xap/1.0/" (XMP) + // "Photoshop 3.0" (Contains IPTC) } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtil.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtil.java index e1b089a7..3955397c 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtil.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/jpeg/JPEGSegmentUtil.java @@ -30,6 +30,7 @@ package com.twelvemonkeys.imageio.metadata.jpeg; import com.twelvemonkeys.imageio.metadata.Directory; import com.twelvemonkeys.imageio.metadata.exif.EXIFReader; +import com.twelvemonkeys.imageio.metadata.psd.PSDReader; import com.twelvemonkeys.imageio.metadata.xmp.XMP; import com.twelvemonkeys.imageio.metadata.xmp.XMPReader; @@ -37,8 +38,6 @@ import javax.imageio.IIOException; import javax.imageio.ImageIO; import javax.imageio.stream.ImageInputStream; import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.nio.charset.Charset; import java.util.*; @@ -253,30 +252,11 @@ public final class JPEGSegmentUtil { System.err.println("XMP: " + xmp); } else if ("Photoshop 3.0".equals(segment.identifier())) { - // TODO: It's probably a good idea to move some of the Photoshop ImageResource parsing code - // to the metadata sub project, as it may be contained in other formats (such as JFIF). // TODO: The "Photoshop 3.0" segment contains several image resources, of which one might contain // IPTC metadata. Probably duplicated in the XMP though... - try { - Class cl = Class.forName("com.twelvemonkeys.imageio.plugins.psd.PSDImageResource"); - Method method = cl.getMethod("read", ImageInputStream.class); - method.setAccessible(true); - ImageInputStream stream = ImageIO.createImageInputStream(segment.data()); - - while (true) { - try { - Object photoShop = method.invoke(null, stream); - System.err.println("PhotoShop: " + photoShop); - } - catch (InvocationTargetException e) { - if (e.getTargetException() instanceof EOFException) { - break; - } - } - } - } - catch (Exception ignore) { - } + ImageInputStream stream = ImageIO.createImageInputStream(segment.data()); + Directory psd = new PSDReader().read(stream); + System.err.println("PSD: " + psd); } else if ("ICC_PROFILE".equals(segment.identifier())) { // Skip diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSD.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSD.java new file mode 100644 index 00000000..4a1b95dc --- /dev/null +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSD.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2012, Harald Kuhr + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name "TwelveMonkeys" nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.twelvemonkeys.imageio.metadata.psd; + +/** + * PSD + * + * @author Harald Kuhr + * @author last modified by $Author: haraldk$ + * @version $Id: PSD.java,v 1.0 24.01.12 16:51 haraldk Exp$ + */ +interface PSD { + static final int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M'; + + static final int RES_IPTC_NAA = 0x0404; +} diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java index c76bb6a3..bd444e39 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntry.java @@ -29,6 +29,7 @@ package com.twelvemonkeys.imageio.metadata.psd; import com.twelvemonkeys.imageio.metadata.AbstractEntry; +import com.twelvemonkeys.lang.StringUtil; /** * PhotoshopEntry @@ -38,12 +39,20 @@ import com.twelvemonkeys.imageio.metadata.AbstractEntry; * @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) { + private final String name; + + public PSDEntry(final int resourceId, String name, final Object value) { super(resourceId, value); + this.name = StringUtil.isEmpty(name) ? null : name; } @Override protected String getNativeIdentifier() { return String.format("0x%04x", (Integer) getIdentifier()); } + + @Override + public String getFieldName() { + return name; + } } diff --git a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java index a8ec02f4..a9c9cb92 100644 --- a/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java +++ b/imageio/imageio-metadata/src/main/java/com/twelvemonkeys/imageio/metadata/psd/PSDReader.java @@ -65,14 +65,14 @@ public final class PSDReader extends MetadataReader { try { int type = input.readInt(); - if (type != PSDResource.RESOURCE_TYPE) { + if (type != PSD.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())); + entries.add(new PSDEntry(id, resource.name(), resource.data())); } catch (EOFException e) { @@ -84,9 +84,6 @@ public final class PSDReader extends MetadataReader { } 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(); @@ -122,7 +119,7 @@ public final class PSDReader extends MetadataReader { readData(new SubImageInputStream(input, size)); - // NOTE: This should never happen, however it's safer to keep it here to + // NOTE: This should never happen, however it's safer to keep it here for future compatibility if (input.getStreamPosition() != startPos + size) { input.seek(startPos + size); } @@ -143,6 +140,10 @@ public final class PSDReader extends MetadataReader { return data; } + public String name() { + return name; + } + @Override public String toString() { StringBuilder builder = toStringBuilder(); diff --git a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java index 0a361897..50f9558f 100644 --- a/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java +++ b/imageio/imageio-metadata/src/test/java/com/twelvemonkeys/imageio/metadata/psd/PSDEntryTest.java @@ -41,6 +41,6 @@ import com.twelvemonkeys.imageio.metadata.EntryAbstractTest; public class PSDEntryTest extends EntryAbstractTest { @Override protected Entry createEntry(final Object value) { - return new PSDEntry(0x404, value); + return new PSDEntry(0x404, "", value); } }