TMI-METADATA: Minor clean-up, preparing for read/write of metadata.

Now uses proper constants for TIFF types.
This commit is contained in:
Harald Kuhr 2013-09-08 14:33:40 +02:00
parent 5531c863cf
commit cdc832623a
5 changed files with 42 additions and 20 deletions

View File

@ -44,7 +44,7 @@ import java.util.Arrays;
public abstract class AbstractEntry implements Entry { public abstract class AbstractEntry implements Entry {
private final Object identifier; private final Object identifier;
private final Object value; // TODO: Might need to be mutable.. private final Object value; // Entries are immutable, directories can be mutated
protected AbstractEntry(final Object identifier, final Object value) { protected AbstractEntry(final Object identifier, final Object value) {
Validate.notNull(identifier, "identifier"); Validate.notNull(identifier, "identifier");
@ -181,10 +181,10 @@ public abstract class AbstractEntry implements Entry {
@Override @Override
public String toString() { public String toString() {
String name = getFieldName(); String name = getFieldName();
String nameStr = name != null ? "/" + name + "" : ""; String nameStr = name != null ? String.format("/%s", name) : "";
String type = getTypeName(); String type = getTypeName();
String typeStr = type != null ? " (" + type + ")" : ""; String typeStr = type != null ? String.format(" (%s)", type) : "";
return String.format("%s%s: %s%s", getNativeIdentifier(), nameStr, getValueAsString(), typeStr); return String.format("%s%s: %s%s", getNativeIdentifier(), nameStr, getValueAsString(), typeStr);
} }

View File

@ -46,6 +46,8 @@ final class EXIFEntry extends AbstractEntry {
if (type < 1 || type > TIFF.TYPE_NAMES.length) { if (type < 1 || type > TIFF.TYPE_NAMES.length) {
throw new IllegalArgumentException(String.format("Illegal EXIF type: %s", type)); throw new IllegalArgumentException(String.format("Illegal EXIF type: %s", type));
} }
// TODO: Validate that type is applicable to value?
this.type = type; this.type = type;
} }

View File

@ -110,7 +110,6 @@ public final class EXIFReader extends MetadataReader {
// Read linked IFDs // Read linked IFDs
if (nextOffset != 0) { if (nextOffset != 0) {
// TODO: This is probably not okay anymore.. Replace recursion with while loop
AbstractCompoundDirectory next = (AbstractCompoundDirectory) readDirectory(pInput, nextOffset); AbstractCompoundDirectory next = (AbstractCompoundDirectory) readDirectory(pInput, nextOffset);
for (int i = 0; i < next.directoryCount(); i++) { for (int i = 0; i < next.directoryCount(); i++) {
ifds.add((IFD) next.getDirectory(i)); ifds.add((IFD) next.getDirectory(i));
@ -298,7 +297,7 @@ public final class EXIFReader extends MetadataReader {
long pos = pInput.getStreamPosition(); long pos = pInput.getStreamPosition();
switch (pType) { switch (pType) {
case 2: // ASCII case TIFF.TYPE_ASCII:
// TODO: This might be UTF-8 or ISO-8859-x, even though spec says NULL-terminated 7 bit ASCII // TODO: This might be UTF-8 or ISO-8859-x, even though spec says NULL-terminated 7 bit ASCII
// TODO: Fail if unknown chars, try parsing with ISO-8859-1 or file.encoding // TODO: Fail if unknown chars, try parsing with ISO-8859-1 or file.encoding
if (pCount == 0) { if (pCount == 0) {
@ -308,17 +307,17 @@ public final class EXIFReader extends MetadataReader {
pInput.readFully(ascii); pInput.readFully(ascii);
int len = ascii[ascii.length - 1] == 0 ? ascii.length - 1 : ascii.length; 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 return StringUtil.decode(ascii, 0, len, "UTF-8"); // UTF-8 is ASCII compatible
case 1: // BYTE case TIFF.TYPE_BYTE:
if (pCount == 1) { if (pCount == 1) {
return pInput.readUnsignedByte(); return pInput.readUnsignedByte();
} }
// else fall through // else fall through
case 6: // SBYTE case TIFF.TYPE_SBYTE:
if (pCount == 1) { if (pCount == 1) {
return pInput.readByte(); return pInput.readByte();
} }
// else fall through // else fall through
case 7: // UNDEFINED case TIFF.TYPE_UNDEFINED:
byte[] bytes = new byte[pCount]; byte[] bytes = new byte[pCount];
pInput.readFully(bytes); pInput.readFully(bytes);
@ -326,11 +325,11 @@ public final class EXIFReader extends MetadataReader {
// binary data and we want to keep that as a byte array for clients to parse futher // binary data and we want to keep that as a byte array for clients to parse futher
return bytes; return bytes;
case 3: // SHORT case TIFF.TYPE_SHORT:
if (pCount == 1) { if (pCount == 1) {
return pInput.readUnsignedShort(); return pInput.readUnsignedShort();
} }
case 8: // SSHORT case TIFF.TYPE_SSHORT:
if (pCount == 1) { if (pCount == 1) {
return pInput.readShort(); return pInput.readShort();
} }
@ -338,21 +337,22 @@ public final class EXIFReader extends MetadataReader {
short[] shorts = new short[pCount]; short[] shorts = new short[pCount];
pInput.readFully(shorts, 0, shorts.length); pInput.readFully(shorts, 0, shorts.length);
if (pType == 3) { if (pType == TIFF.TYPE_SHORT) {
int[] ints = new int[pCount]; int[] ints = new int[pCount];
for (int i = 0; i < pCount; i++) { for (int i = 0; i < pCount; i++) {
ints[i] = shorts[i] & 0xffff; ints[i] = shorts[i] & 0xffff;
} }
return ints; return ints;
} }
return shorts; return shorts;
case 13: // IFD case TIFF.TYPE_IFD:
case 4: // LONG case TIFF.TYPE_LONG:
if (pCount == 1) { if (pCount == 1) {
return pInput.readUnsignedInt(); return pInput.readUnsignedInt();
} }
case 9: // SLONG case TIFF.TYPE_SLONG:
if (pCount == 1) { if (pCount == 1) {
return pInput.readInt(); return pInput.readInt();
} }
@ -360,16 +360,17 @@ public final class EXIFReader extends MetadataReader {
int[] ints = new int[pCount]; int[] ints = new int[pCount];
pInput.readFully(ints, 0, ints.length); pInput.readFully(ints, 0, ints.length);
if (pType == 4 || pType == 13) { if (pType == TIFF.TYPE_LONG || pType == TIFF.TYPE_IFD) {
long[] longs = new long[pCount]; long[] longs = new long[pCount];
for (int i = 0; i < pCount; i++) { for (int i = 0; i < pCount; i++) {
longs[i] = ints[i] & 0xffffffffL; longs[i] = ints[i] & 0xffffffffL;
} }
return longs; return longs;
} }
return ints; return ints;
case 11: // FLOAT case TIFF.TYPE_FLOAT:
if (pCount == 1) { if (pCount == 1) {
return pInput.readFloat(); return pInput.readFloat();
} }
@ -377,7 +378,7 @@ public final class EXIFReader extends MetadataReader {
float[] floats = new float[pCount]; float[] floats = new float[pCount];
pInput.readFully(floats, 0, floats.length); pInput.readFully(floats, 0, floats.length);
return floats; return floats;
case 12: // DOUBLE case TIFF.TYPE_DOUBLE:
if (pCount == 1) { if (pCount == 1) {
return pInput.readDouble(); return pInput.readDouble();
} }
@ -386,7 +387,7 @@ public final class EXIFReader extends MetadataReader {
pInput.readFully(doubles, 0, doubles.length); pInput.readFully(doubles, 0, doubles.length);
return doubles; return doubles;
case 5: // RATIONAL case TIFF.TYPE_RATIONAL:
if (pCount == 1) { if (pCount == 1) {
return createSafeRational(pInput.readUnsignedInt(), pInput.readUnsignedInt()); return createSafeRational(pInput.readUnsignedInt(), pInput.readUnsignedInt());
} }
@ -397,7 +398,7 @@ public final class EXIFReader extends MetadataReader {
} }
return rationals; return rationals;
case 10: // SRATIONAL case TIFF.TYPE_SRATIONAL:
if (pCount == 1) { if (pCount == 1) {
return createSafeRational(pInput.readInt(), pInput.readInt()); return createSafeRational(pInput.readInt(), pInput.readInt());
} }
@ -445,7 +446,7 @@ public final class EXIFReader extends MetadataReader {
return new Rational(numerator, denominator); return new Rational(numerator, denominator);
} }
private int getValueLength(final int pType, final int pCount) { static int getValueLength(final int pType, final int pCount) {
if (pType > 0 && pType <= TIFF.TYPE_LENGTHS.length) { if (pType > 0 && pType <= TIFF.TYPE_LENGTHS.length) {
return TIFF.TYPE_LENGTHS[pType - 1] * pCount; return TIFF.TYPE_LENGTHS[pType - 1] * pCount;
} }

View File

@ -37,8 +37,25 @@ package com.twelvemonkeys.imageio.metadata.exif;
*/ */
@SuppressWarnings("UnusedDeclaration") @SuppressWarnings("UnusedDeclaration")
public interface TIFF { public interface TIFF {
short BYTE_ORDER_MARK_BIG_ENDIAN = ('M' << 8) | 'M';
short BYTE_ORDER_MARK_LITTLE_ENDIAN = ('I' << 8) | 'I';
int TIFF_MAGIC = 42; int TIFF_MAGIC = 42;
short TYPE_BYTE = 1;
short TYPE_ASCII = 2;
short TYPE_SHORT = 3;
short TYPE_LONG = 4;
short TYPE_RATIONAL = 5;
short TYPE_SBYTE = 6;
short TYPE_UNDEFINED = 7;
short TYPE_SSHORT = 8;
short TYPE_SLONG = 9;
short TYPE_SRATIONAL = 10;
short TYPE_FLOAT = 11;
short TYPE_DOUBLE = 12;
short TYPE_IFD = 13;
/* /*
1 = BYTE 8-bit unsigned integer. 1 = BYTE 8-bit unsigned integer.
2 = ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte 2 = ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte

View File

@ -77,6 +77,8 @@ public final class JPEGSegment implements Serializable {
return marker >= 0xFFE0 && marker <= 0xFFEF; return marker >= 0xFFE0 && marker <= 0xFFEF;
} }
// TODO: Consider returning an ImageInputStream and use ByteArrayImageInputStream directly, for less wrapping and better performance
// TODO: BUT: Must find a way to skip padding in/after segment identifier (eg: Exif has null-term + null-pad, ICC_PROFILE has only null-term). Is data always word-aligned?
public InputStream data() { public InputStream data() {
return data != null ? new ByteArrayInputStream(data, offset(), length()) : null; return data != null ? new ByteArrayInputStream(data, offset(), length()) : null;
} }