mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 04:25:29 -04:00
TMI-136: Better TIFF (IFD) format write support.
This commit is contained in:
parent
998851c9fb
commit
517fc770bd
@ -38,13 +38,14 @@ import com.twelvemonkeys.imageio.metadata.AbstractEntry;
|
|||||||
* @version $Id: EXIFEntry.java,v 1.0 Nov 13, 2009 5:47:35 PM haraldk Exp$
|
* @version $Id: EXIFEntry.java,v 1.0 Nov 13, 2009 5:47:35 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class EXIFEntry extends AbstractEntry {
|
final class EXIFEntry extends AbstractEntry {
|
||||||
|
// TODO: Expose as TIFFEntry
|
||||||
final private short type;
|
final private short type;
|
||||||
|
|
||||||
EXIFEntry(final int identifier, final Object value, final short type) {
|
EXIFEntry(final int identifier, final Object value, final short type) {
|
||||||
super(identifier, value);
|
super(identifier, value);
|
||||||
|
|
||||||
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 TIFF type: %s", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validate that type is applicable to value?
|
// TODO: Validate that type is applicable to value?
|
||||||
@ -114,6 +115,8 @@ final class EXIFEntry extends AbstractEntry {
|
|||||||
return "PlanarConfiguration";
|
return "PlanarConfiguration";
|
||||||
case TIFF.TAG_RESOLUTION_UNIT:
|
case TIFF.TAG_RESOLUTION_UNIT:
|
||||||
return "ResolutionUnit";
|
return "ResolutionUnit";
|
||||||
|
case TIFF.TAG_PAGE_NAME:
|
||||||
|
return "PageName";
|
||||||
case TIFF.TAG_PAGE_NUMBER:
|
case TIFF.TAG_PAGE_NUMBER:
|
||||||
return "PageNumber";
|
return "PageNumber";
|
||||||
case TIFF.TAG_SOFTWARE:
|
case TIFF.TAG_SOFTWARE:
|
||||||
@ -228,6 +231,8 @@ final class EXIFEntry extends AbstractEntry {
|
|||||||
return "DateTimeDigitized";
|
return "DateTimeDigitized";
|
||||||
case EXIF.TAG_IMAGE_NUMBER:
|
case EXIF.TAG_IMAGE_NUMBER:
|
||||||
return "ImageNumber";
|
return "ImageNumber";
|
||||||
|
case EXIF.TAG_MAKER_NOTE:
|
||||||
|
return "MakerNote";
|
||||||
case EXIF.TAG_USER_COMMENT:
|
case EXIF.TAG_USER_COMMENT:
|
||||||
return "UserComment";
|
return "UserComment";
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ import java.io.IOException;
|
|||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -248,9 +249,12 @@ public final class EXIFWriter extends MetadataWriter {
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
case TIFF.TYPE_UNDEFINED:
|
case TIFF.TYPE_UNDEFINED:
|
||||||
case TIFF.TYPE_BYTE:
|
case TIFF.TYPE_BYTE:
|
||||||
|
case TIFF.TYPE_SBYTE:
|
||||||
stream.write((byte[]) value);
|
stream.write((byte[]) value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIFF.TYPE_SHORT:
|
case TIFF.TYPE_SHORT:
|
||||||
|
case TIFF.TYPE_SSHORT:
|
||||||
short[] shorts;
|
short[] shorts;
|
||||||
|
|
||||||
if (value instanceof short[]) {
|
if (value instanceof short[]) {
|
||||||
@ -279,7 +283,9 @@ public final class EXIFWriter extends MetadataWriter {
|
|||||||
|
|
||||||
stream.writeShorts(shorts, 0, shorts.length);
|
stream.writeShorts(shorts, 0, shorts.length);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIFF.TYPE_LONG:
|
case TIFF.TYPE_LONG:
|
||||||
|
case TIFF.TYPE_SLONG:
|
||||||
int[] ints;
|
int[] ints;
|
||||||
|
|
||||||
if (value instanceof int[]) {
|
if (value instanceof int[]) {
|
||||||
@ -298,17 +304,45 @@ public final class EXIFWriter extends MetadataWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stream.writeInts(ints, 0, ints.length);
|
stream.writeInts(ints, 0, ints.length);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TIFF.TYPE_RATIONAL:
|
case TIFF.TYPE_RATIONAL:
|
||||||
|
case TIFF.TYPE_SRATIONAL:
|
||||||
Rational[] rationals = (Rational[]) value;
|
Rational[] rationals = (Rational[]) value;
|
||||||
for (Rational rational : rationals) {
|
for (Rational rational : rationals) {
|
||||||
stream.writeInt((int) rational.numerator());
|
stream.writeInt((int) rational.numerator());
|
||||||
stream.writeInt((int) rational.denominator());
|
stream.writeInt((int) rational.denominator());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: More types
|
break;
|
||||||
|
|
||||||
|
case TIFF.TYPE_FLOAT:
|
||||||
|
float[] floats;
|
||||||
|
|
||||||
|
if (value instanceof float[]) {
|
||||||
|
floats = (float[]) value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Unsupported type for TIFF FLOAT: " + value.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.writeFloats(floats, 0, floats.length);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TIFF.TYPE_DOUBLE:
|
||||||
|
double[] doubles;
|
||||||
|
|
||||||
|
if (value instanceof double[]) {
|
||||||
|
doubles = (double[]) value;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("Unsupported type for TIFF FLOAT: " + value.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
stream.writeDoubles(doubles, 0, doubles.length);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported TIFF type: " + type);
|
throw new IllegalArgumentException("Unsupported TIFF type: " + type);
|
||||||
@ -319,27 +353,36 @@ public final class EXIFWriter extends MetadataWriter {
|
|||||||
// }
|
// }
|
||||||
else {
|
else {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case TIFF.TYPE_UNDEFINED:
|
|
||||||
case TIFF.TYPE_BYTE:
|
case TIFF.TYPE_BYTE:
|
||||||
stream.writeByte((Integer) value);
|
case TIFF.TYPE_SBYTE:
|
||||||
|
case TIFF.TYPE_UNDEFINED:
|
||||||
|
stream.writeByte(((Number) value).intValue());
|
||||||
break;
|
break;
|
||||||
case TIFF.TYPE_ASCII:
|
case TIFF.TYPE_ASCII:
|
||||||
byte[] bytes = ((String) value).getBytes(Charset.forName("UTF-8"));
|
byte[] bytes = ((String) value).getBytes(StandardCharsets.UTF_8);
|
||||||
stream.write(bytes);
|
stream.write(bytes);
|
||||||
stream.write(0);
|
stream.write(0);
|
||||||
break;
|
break;
|
||||||
case TIFF.TYPE_SHORT:
|
case TIFF.TYPE_SHORT:
|
||||||
stream.writeShort((Integer) value);
|
case TIFF.TYPE_SSHORT:
|
||||||
|
stream.writeShort(((Number) value).intValue());
|
||||||
break;
|
break;
|
||||||
case TIFF.TYPE_LONG:
|
case TIFF.TYPE_LONG:
|
||||||
|
case TIFF.TYPE_SLONG:
|
||||||
stream.writeInt(((Number) value).intValue());
|
stream.writeInt(((Number) value).intValue());
|
||||||
break;
|
break;
|
||||||
case TIFF.TYPE_RATIONAL:
|
case TIFF.TYPE_RATIONAL:
|
||||||
|
case TIFF.TYPE_SRATIONAL:
|
||||||
Rational rational = (Rational) value;
|
Rational rational = (Rational) value;
|
||||||
stream.writeInt((int) rational.numerator());
|
stream.writeInt((int) rational.numerator());
|
||||||
stream.writeInt((int) rational.denominator());
|
stream.writeInt((int) rational.denominator());
|
||||||
break;
|
break;
|
||||||
// TODO: More types
|
case TIFF.TYPE_FLOAT:
|
||||||
|
stream.writeFloat(((Number) value).floatValue());
|
||||||
|
break;
|
||||||
|
case TIFF.TYPE_DOUBLE:
|
||||||
|
stream.writeDouble(((Number) value).doubleValue());
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("Unsupported TIFF type: " + type);
|
throw new IllegalArgumentException("Unsupported TIFF type: " + type);
|
||||||
@ -356,11 +399,26 @@ public final class EXIFWriter extends MetadataWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private short getType(final Entry entry) {
|
private short getType(final Entry entry) {
|
||||||
|
// TODO: What a MESS! Rewrite and expose EXIFEntry as TIFFEntry or so...
|
||||||
|
|
||||||
|
// For internal entries use type directly
|
||||||
if (entry instanceof EXIFEntry) {
|
if (entry instanceof EXIFEntry) {
|
||||||
EXIFEntry exifEntry = (EXIFEntry) entry;
|
EXIFEntry exifEntry = (EXIFEntry) entry;
|
||||||
return exifEntry.getType();
|
return exifEntry.getType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For other entries, use name if it matches
|
||||||
|
String typeName = entry.getTypeName();
|
||||||
|
|
||||||
|
if (typeName != null) {
|
||||||
|
for (int i = 1; i < TIFF.TYPE_NAMES.length; i++) {
|
||||||
|
if (typeName.equals(TIFF.TYPE_NAMES[i])) {
|
||||||
|
return (short) i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, fall back to the native Java type
|
||||||
Object value = Validate.notNull(entry.getValue());
|
Object value = Validate.notNull(entry.getValue());
|
||||||
|
|
||||||
boolean array = value.getClass().isArray();
|
boolean array = value.getClass().isArray();
|
||||||
|
@ -95,6 +95,7 @@ public interface TIFF {
|
|||||||
null, null,
|
null, null,
|
||||||
"LONG8", "SLONG8", "IFD8"
|
"LONG8", "SLONG8", "IFD8"
|
||||||
};
|
};
|
||||||
|
/** Length of the corresponding type, in bytes. */
|
||||||
int[] TYPE_LENGTHS = {
|
int[] TYPE_LENGTHS = {
|
||||||
-1,
|
-1,
|
||||||
1, 1, 2, 4, 8,
|
1, 1, 2, 4, 8,
|
||||||
@ -165,6 +166,7 @@ public interface TIFF {
|
|||||||
int TAG_IMAGE_DESCRIPTION = 270;
|
int TAG_IMAGE_DESCRIPTION = 270;
|
||||||
int TAG_MAKE = 271;
|
int TAG_MAKE = 271;
|
||||||
int TAG_MODEL = 272;
|
int TAG_MODEL = 272;
|
||||||
|
int TAG_PAGE_NAME = 285;
|
||||||
int TAG_PAGE_NUMBER = 297;
|
int TAG_PAGE_NUMBER = 297;
|
||||||
int TAG_SOFTWARE = 305;
|
int TAG_SOFTWARE = 305;
|
||||||
int TAG_ARTIST = 315;
|
int TAG_ARTIST = 315;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user