mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 11:35:29 -04:00
Work in progress for PSD metadata support:
- Changes to native format spec - Implemented more of native format - Added several more resource type implementations - IPTC metadata support
This commit is contained in:
parent
bf5c6e9d47
commit
54cf727dee
@ -225,11 +225,11 @@ interface PSD {
|
|||||||
|
|
||||||
// 03f8
|
// 03f8
|
||||||
/** Color transfer functions */
|
/** Color transfer functions */
|
||||||
int RES_COLOR_TRANSFER_FUNCITON = 0x03f8;
|
int RES_COLOR_TRANSFER_FUNCTION = 0x03f8;
|
||||||
|
|
||||||
// 03f9
|
// 03f9
|
||||||
/** Duotone transfer functions */
|
/** Duotone transfer functions */
|
||||||
int RES_DUOTONE_TRANSFER_FUNCITON = 0x03f9;
|
int RES_DUOTONE_TRANSFER_FUNCTOON = 0x03f9;
|
||||||
|
|
||||||
// 03fa
|
// 03fa
|
||||||
/** Duotone image information */
|
/** Duotone image information */
|
||||||
@ -385,7 +385,7 @@ interface PSD {
|
|||||||
* (Photoshop 5.0) Unicode Alpha Names
|
* (Photoshop 5.0) Unicode Alpha Names
|
||||||
* Unicode string (4 bytes length followed by string).
|
* Unicode string (4 bytes length followed by string).
|
||||||
*/
|
*/
|
||||||
int RES_UNICODE_ALPHA_NAME = 0x0415;
|
int RES_UNICODE_ALPHA_NAMES = 0x0415;
|
||||||
|
|
||||||
// 1046
|
// 1046
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDGridAndGuideInfo
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDGridAndGuideInfo.java,v 1.0 Nov 7, 2009 8:46:13 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDGridAndGuideInfo extends PSDImageResource {
|
||||||
|
/* Grid & guide header */
|
||||||
|
//typedef struct {
|
||||||
|
// guint32 fVersion; /* Version - always 1 for PS */
|
||||||
|
// guint32 fGridCycleV; /* Vertical grid size */
|
||||||
|
// guint32 fGridCycleH; /* Horizontal grid size */
|
||||||
|
// guint32 fGuideCount; /* Number of guides */
|
||||||
|
//} GuideHeader;
|
||||||
|
|
||||||
|
/* Guide resource block */
|
||||||
|
//typedef struct {
|
||||||
|
// guint32 fLocation; /* Guide position in Pixels * 100 */
|
||||||
|
// gchar fDirection; /* Guide orientation */
|
||||||
|
//} GuideResource;
|
||||||
|
|
||||||
|
int mVersion;
|
||||||
|
int mGridCycleVertical;
|
||||||
|
int mGridCycleHorizontal;
|
||||||
|
int mGuideCount;
|
||||||
|
|
||||||
|
GuideResource[] mGuides;
|
||||||
|
|
||||||
|
PSDGridAndGuideInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
mVersion = pInput.readInt();
|
||||||
|
mGridCycleVertical = pInput.readInt();
|
||||||
|
mGridCycleHorizontal = pInput.readInt();
|
||||||
|
mGuideCount = pInput.readInt();
|
||||||
|
|
||||||
|
mGuides = new GuideResource[mGuideCount];
|
||||||
|
|
||||||
|
for (GuideResource guide : mGuides) {
|
||||||
|
guide.mLocation = pInput.readInt();
|
||||||
|
guide.mDirection = pInput.readByte();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class GuideResource {
|
||||||
|
int mLocation;
|
||||||
|
byte mDirection; // 0: vertical, 1: horizontal
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,418 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
|
import javax.imageio.IIOException;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.CharBuffer;
|
||||||
|
import java.nio.charset.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDIPTCData
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDIPTCData.java,v 1.0 Nov 7, 2009 9:52:14 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDIPTCData extends PSDImageResource {
|
||||||
|
// TODO: Refactor to be more like PSDEXIF1Data...
|
||||||
|
// TODO: Extract IPTC/EXIF/XMP metadata extraction/parsing to separate module(s)
|
||||||
|
Directory mDirectory;
|
||||||
|
|
||||||
|
PSDIPTCData(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
mDirectory = Directory.read(pInput, mSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = toStringBuilder();
|
||||||
|
builder.append(", ").append(mDirectory);
|
||||||
|
builder.append("]");
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Entry {
|
||||||
|
private int mTagId;
|
||||||
|
private String mValue;
|
||||||
|
|
||||||
|
public Entry(int pTagId, String pValue) {
|
||||||
|
mTagId = pTagId;
|
||||||
|
mValue = pValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return (mTagId >> 8) + ":" + (mTagId & 0xff) + ": " + mValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Directory implements Iterable<Entry> {
|
||||||
|
private static final int ENCODING_UNKNOWN = -1;
|
||||||
|
private static final int ENCODING_UNSPECIFIED = 0;
|
||||||
|
private static final int ENCODING_UTF_8 = 0x1b2547;
|
||||||
|
|
||||||
|
private int mEncoding = ENCODING_UNSPECIFIED;
|
||||||
|
final List<Entry> mEntries = new ArrayList<Entry>();
|
||||||
|
|
||||||
|
private Directory() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Directory" + mEntries.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry> iterator() {
|
||||||
|
return mEntries.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Directory read(final ImageInputStream pInput, final long pSize) throws IOException {
|
||||||
|
Directory directory = new Directory();
|
||||||
|
|
||||||
|
final long streamEnd = pInput.getStreamPosition() + pSize;
|
||||||
|
|
||||||
|
// For each tag
|
||||||
|
while (pInput.getStreamPosition() < streamEnd) {
|
||||||
|
// Identifies start of a tag
|
||||||
|
byte b = pInput.readByte();
|
||||||
|
if (b != 0x1c) {
|
||||||
|
throw new IIOException("Corrupt IPTC stream segment");
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need at least four bytes left to read a tag
|
||||||
|
if (pInput.getStreamPosition() + 4 >= streamEnd) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int directoryType = pInput.readUnsignedByte();
|
||||||
|
int tagType = pInput.readUnsignedByte();
|
||||||
|
int tagByteCount = pInput.readUnsignedShort();
|
||||||
|
|
||||||
|
if (pInput.getStreamPosition() + tagByteCount > streamEnd) {
|
||||||
|
throw new IIOException("Data for tag extends beyond end of IPTC segment: " + (tagByteCount + pInput.getStreamPosition() - streamEnd));
|
||||||
|
}
|
||||||
|
|
||||||
|
directory.processTag(pInput, directoryType, tagType, tagByteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
return directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void processTag(ImageInputStream pInput, int directoryType, int tagType, int tagByteCount) throws IOException {
|
||||||
|
int tagIdentifier = (directoryType << 8) | tagType;
|
||||||
|
|
||||||
|
String str = null;
|
||||||
|
switch (tagIdentifier) {
|
||||||
|
case IPTC.TAG_CODED_CHARACTER_SET:
|
||||||
|
// TODO: Use this encoding!?
|
||||||
|
// TODO: Move somewhere else?
|
||||||
|
mEncoding = parseEncoding(pInput, tagByteCount);
|
||||||
|
return;
|
||||||
|
case IPTC.TAG_RECORD_VERSION:
|
||||||
|
// short
|
||||||
|
str = Integer.toString(pInput.readUnsignedShort());
|
||||||
|
break;
|
||||||
|
// case IPTC.TAG_RELEASE_DATE:
|
||||||
|
// case IPTC.TAG_EXPIRATION_DATE:
|
||||||
|
// case IPTC.TAG_REFERENCE_DATE:
|
||||||
|
// case IPTC.TAG_DATE_CREATED:
|
||||||
|
// case IPTC.TAG_DIGITAL_CREATION_DATE:
|
||||||
|
// // Date object
|
||||||
|
// Date date = parseISO8601DatePart(pInput, tagByteCount);
|
||||||
|
// if (date != null) {
|
||||||
|
// directory.setDate(tagIdentifier, date);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// case IPTC.TAG_RELEASE_TIME:
|
||||||
|
// case IPTC.TAG_EXPIRATION_TIME:
|
||||||
|
// case IPTC.TAG_TIME_CREATED:
|
||||||
|
// case IPTC.TAG_DIGITAL_CREATION_TIME:
|
||||||
|
// // NOTE: Spec says fields should be sent in order, so this is okay
|
||||||
|
// date = getDateForTime(directory, tagIdentifier);
|
||||||
|
//
|
||||||
|
// Date time = parseISO8601TimePart(pInput, tagByteCount, date);
|
||||||
|
// if (time != null) {
|
||||||
|
// directory.setDate(tagIdentifier, time);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip non-Application fields, as they are typically not human readable
|
||||||
|
if (directoryType << 8 != IPTC.APPLICATION_RECORD) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we don't have a value, treat it as a string
|
||||||
|
if (str == null) {
|
||||||
|
if (tagByteCount < 1) {
|
||||||
|
str = "(No value)";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
str = String.format("\"%s\"", parseString(pInput, tagByteCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mEntries.add(new Entry(tagIdentifier, str));
|
||||||
|
|
||||||
|
// if (directory.containsTag(tagIdentifier)) {
|
||||||
|
// // TODO: Does that REALLY help for performance?!
|
||||||
|
// // this fancy string[] business avoids using an ArrayList for performance reasons
|
||||||
|
// String[] oldStrings;
|
||||||
|
// String[] newStrings;
|
||||||
|
// try {
|
||||||
|
// oldStrings = directory.getStringArray(tagIdentifier);
|
||||||
|
// }
|
||||||
|
// catch (MetadataException e) {
|
||||||
|
// oldStrings = null;
|
||||||
|
// }
|
||||||
|
// if (oldStrings == null) {
|
||||||
|
// newStrings = new String[1];
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// newStrings = new String[oldStrings.length + 1];
|
||||||
|
// System.arraycopy(oldStrings, 0, newStrings, 0, oldStrings.length);
|
||||||
|
// }
|
||||||
|
// newStrings[newStrings.length - 1] = str;
|
||||||
|
// directory.setStringArray(tagIdentifier, newStrings);
|
||||||
|
// }
|
||||||
|
// else {
|
||||||
|
// directory.setString(tagIdentifier, str);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// private Date getDateForTime(final Directory directory, final int tagIdentifier) {
|
||||||
|
// int dateTag;
|
||||||
|
//
|
||||||
|
// switch (tagIdentifier) {
|
||||||
|
// case IPTC.TAG_RELEASE_TIME:
|
||||||
|
// dateTag = IPTC.TAG_RELEASE_DATE;
|
||||||
|
// break;
|
||||||
|
// case IPTC.TAG_EXPIRATION_TIME:
|
||||||
|
// dateTag = IPTC.TAG_EXPIRATION_DATE;
|
||||||
|
// break;
|
||||||
|
// case IPTC.TAG_TIME_CREATED:
|
||||||
|
// dateTag = IPTC.TAG_DATE_CREATED;
|
||||||
|
// break;
|
||||||
|
// case IPTC.TAG_DIGITAL_CREATION_TIME:
|
||||||
|
// dateTag = IPTC.TAG_DIGITAL_CREATION_DATE;
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// return new Date(0l);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return directory.containsTag(dateTag) ? directory.getDate(dateTag) : new Date(0l);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
private int parseEncoding(final ImageInputStream pInput, int tagByteCount) throws IOException {
|
||||||
|
return tagByteCount == 3
|
||||||
|
&& (pInput.readUnsignedByte() << 16 | pInput.readUnsignedByte() << 8 | pInput.readUnsignedByte()) == ENCODING_UTF_8
|
||||||
|
? ENCODING_UTF_8 : ENCODING_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private Date parseISO8601TimePart(final ImageInputStream pInputStream, int tagByteCount, final Date date) throws IOException {
|
||||||
|
// // ISO 8601: HHMMSS±HHMM
|
||||||
|
// if (tagByteCount >= 11) {
|
||||||
|
// String timeStr = parseString(pInputStream, tagByteCount);
|
||||||
|
// try {
|
||||||
|
// int hour = Integer.parseInt(timeStr.substring(0, 2));
|
||||||
|
// int minute = Integer.parseInt(timeStr.substring(2, 4));
|
||||||
|
// int second = Integer.parseInt(timeStr.substring(4, 6));
|
||||||
|
// String tzOffset = timeStr.substring(6, 11);
|
||||||
|
//
|
||||||
|
// TimeZone zone = new SimpleTimeZone(Integer.parseInt(tzOffset.charAt(0) == '+' ? tzOffset.substring(1) : tzOffset), tzOffset);
|
||||||
|
//
|
||||||
|
// GregorianCalendar calendar = new GregorianCalendar(zone);
|
||||||
|
// calendar.setTime(date);
|
||||||
|
//
|
||||||
|
// calendar.add(Calendar.HOUR_OF_DAY, hour);
|
||||||
|
// calendar.add(Calendar.MINUTE, minute);
|
||||||
|
// calendar.add(Calendar.SECOND, second);
|
||||||
|
//
|
||||||
|
// return calendar.getTime();
|
||||||
|
// }
|
||||||
|
// catch (NumberFormatException e) {
|
||||||
|
// // fall through and we'll store whatever was there as a String
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// private Date parseISO8601DatePart(final ImageInputStream pInputStream, int tagByteCount) throws IOException {
|
||||||
|
// // ISO 8601: CCYYMMDD
|
||||||
|
// if (tagByteCount >= 8) {
|
||||||
|
// String dateStr = parseString(pInputStream, tagByteCount);
|
||||||
|
// try {
|
||||||
|
// int year = Integer.parseInt(dateStr.substring(0, 4));
|
||||||
|
// int month = Integer.parseInt(dateStr.substring(4, 6)) - 1;
|
||||||
|
// int day = Integer.parseInt(dateStr.substring(6, 8));
|
||||||
|
// GregorianCalendar calendar = new GregorianCalendar(year, month, day);
|
||||||
|
// return calendar.getTime();
|
||||||
|
// }
|
||||||
|
// catch (NumberFormatException e) {
|
||||||
|
// // fall through and we'll store whatever was there as a String
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// TODO: Pass encoding as parameter? Use if specified
|
||||||
|
private String parseString(final ImageInputStream pInput, int length) throws IOException {
|
||||||
|
// NOTE: The IPTC "spec" says ISO 646 or ISO 2022 encoding. UTF-8 contains all 646 characters, but not 2022.
|
||||||
|
// This is however close to what libiptcdata does, see: http://libiptcdata.sourceforge.net/docs/iptc-i18n.html
|
||||||
|
// First try to decode using UTF-8 (which seems to be the de-facto standard)
|
||||||
|
String str;
|
||||||
|
Charset charset = Charset.forName("UTF-8");
|
||||||
|
CharsetDecoder decoder = charset.newDecoder();
|
||||||
|
CharBuffer chars;
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
pInput.readFully(data);
|
||||||
|
try {
|
||||||
|
// Will fail fast on illegal UTF-8-sequences
|
||||||
|
chars = decoder.onMalformedInput(CodingErrorAction.REPORT)
|
||||||
|
.onUnmappableCharacter(CodingErrorAction.REPORT)
|
||||||
|
.decode(ByteBuffer.wrap(data));
|
||||||
|
str = chars.toString();
|
||||||
|
}
|
||||||
|
catch (CharacterCodingException notUTF8) {
|
||||||
|
if (mEncoding == ENCODING_UTF_8) {
|
||||||
|
throw new IIOException("Wrong encoding of IPTC data, explicitly set to UTF-8 in DataSet 1:90", notUTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to use ISO-8859-1
|
||||||
|
// This will not fail, but may may create wrong fallback-characters
|
||||||
|
str = StringUtil.decode(data, 0, data.length, "ISO8859_1");
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static interface IPTC {
|
||||||
|
static final int ENVELOPE_RECORD = 1 << 8;
|
||||||
|
static final int APPLICATION_RECORD = 2 << 8;
|
||||||
|
|
||||||
|
static final int TAG_CODED_CHARACTER_SET = ENVELOPE_RECORD | 90;
|
||||||
|
|
||||||
|
/** 2:00 Record Version (mandatory) */
|
||||||
|
public static final int TAG_RECORD_VERSION = APPLICATION_RECORD; // 0x0200
|
||||||
|
// /** 2:03 Object Type Reference */
|
||||||
|
// public static final int TAG_OBJECT_TYPE_REFERENCE = APPLICATION_RECORD | 3;
|
||||||
|
// /** 2:04 Object Attribute Reference (repeatable) */
|
||||||
|
// public static final int TAG_OBJECT_ATTRIBUTE_REFERENCE = APPLICATION_RECORD | 4;
|
||||||
|
// /** 2:05 Object Name */
|
||||||
|
// public static final int TAG_OBJECT_NAME = APPLICATION_RECORD | 5; // 0x0205
|
||||||
|
// /** 2:07 Edit Status */
|
||||||
|
// public static final int TAG_EDIT_STATUS = APPLICATION_RECORD | 7;
|
||||||
|
// /** 2:08 Editorial Update */
|
||||||
|
// public static final int TAG_EDITORIAL_UPDATE = APPLICATION_RECORD | 8;
|
||||||
|
// /** 2:10 Urgency */
|
||||||
|
// public static final int TAG_URGENCY = APPLICATION_RECORD | 10;
|
||||||
|
// /** 2:12 Subect Reference (repeatable) */
|
||||||
|
// public static final int TAG_SUBJECT_REFERENCE = APPLICATION_RECORD | 12;
|
||||||
|
// /** 2:15 Category */
|
||||||
|
// public static final int TAG_CATEGORY = APPLICATION_RECORD | 15; // 0x020f
|
||||||
|
// /** 2:20 Supplemental Category (repeatable) */
|
||||||
|
// public static final int TAG_SUPPLEMENTAL_CATEGORIES = APPLICATION_RECORD | 20;
|
||||||
|
// /** 2:22 Fixture Identifier */
|
||||||
|
// public static final int TAG_FIXTURE_IDENTIFIER = APPLICATION_RECORD | 22;
|
||||||
|
// /** 2:25 Keywords (repeatable) */
|
||||||
|
// public static final int TAG_KEYWORDS = APPLICATION_RECORD | 25;
|
||||||
|
// /** 2:26 Content Locataion Code (repeatable) */
|
||||||
|
// public static final int TAG_CONTENT_LOCATION_CODE = APPLICATION_RECORD | 26;
|
||||||
|
// /** 2:27 Content Locataion Name (repeatable) */
|
||||||
|
// public static final int TAG_CONTENT_LOCATION_NAME = APPLICATION_RECORD | 27;
|
||||||
|
// /** 2:30 Release Date */
|
||||||
|
// public static final int TAG_RELEASE_DATE = APPLICATION_RECORD | 30;
|
||||||
|
// /** 2:35 Release Time */
|
||||||
|
// public static final int TAG_RELEASE_TIME = APPLICATION_RECORD | 35;
|
||||||
|
// /** 2:37 Expiration Date */
|
||||||
|
// public static final int TAG_EXPIRATION_DATE = APPLICATION_RECORD | 37;
|
||||||
|
// /** 2:38 Expiration Time */
|
||||||
|
// public static final int TAG_EXPIRATION_TIME = APPLICATION_RECORD | 38;
|
||||||
|
// /** 2:40 Special Instructions */
|
||||||
|
// public static final int TAG_SPECIAL_INSTRUCTIONS = APPLICATION_RECORD | 40; // 0x0228
|
||||||
|
// /** 2:42 Action Advised (1: Kill, 2: Replace, 3: Append, 4: Reference) */
|
||||||
|
// public static final int TAG_ACTION_ADVICED = APPLICATION_RECORD | 42;
|
||||||
|
// /** 2:45 Reference Service (repeatable in triplets with 2:47 and 2:50) */
|
||||||
|
// public static final int TAG_REFERENCE_SERVICE = APPLICATION_RECORD | 45;
|
||||||
|
// /** 2:47 Reference Date (mandatory if 2:45 present) */
|
||||||
|
// public static final int TAG_REFERENCE_DATE = APPLICATION_RECORD | 47;
|
||||||
|
// /** 2:50 Reference Number (mandatory if 2:45 present) */
|
||||||
|
// public static final int TAG_REFERENCE_NUMBER = APPLICATION_RECORD | 50;
|
||||||
|
// /** 2:55 Date Created */
|
||||||
|
// public static final int TAG_DATE_CREATED = APPLICATION_RECORD | 55; // 0x0237
|
||||||
|
// /** 2:60 Time Created */
|
||||||
|
// public static final int TAG_TIME_CREATED = APPLICATION_RECORD | 60;
|
||||||
|
// /** 2:62 Digital Creation Date */
|
||||||
|
// public static final int TAG_DIGITAL_CREATION_DATE = APPLICATION_RECORD | 62;
|
||||||
|
// /** 2:63 Digital Creation Date */
|
||||||
|
// public static final int TAG_DIGITAL_CREATION_TIME = APPLICATION_RECORD | 63;
|
||||||
|
// /** 2:65 Originating Program */
|
||||||
|
// public static final int TAG_ORIGINATING_PROGRAM = APPLICATION_RECORD | 65;
|
||||||
|
// /** 2:70 Program Version (only valid if 2:65 present) */
|
||||||
|
// public static final int TAG_PROGRAM_VERSION = APPLICATION_RECORD | 70;
|
||||||
|
// /** 2:75 Object Cycle (a: morning, p: evening, b: both) */
|
||||||
|
// public static final int TAG_OBJECT_CYCLE = APPLICATION_RECORD | 75;
|
||||||
|
// /** 2:80 By-line (repeatable) */
|
||||||
|
// public static final int TAG_BY_LINE = APPLICATION_RECORD | 80; // 0x0250
|
||||||
|
// /** 2:85 By-line Title (repeatable) */
|
||||||
|
// public static final int TAG_BY_LINE_TITLE = APPLICATION_RECORD | 85; // 0x0255
|
||||||
|
// /** 2:90 City */
|
||||||
|
// public static final int TAG_CITY = APPLICATION_RECORD | 90; // 0x025a
|
||||||
|
// /** 2:92 Sub-location */
|
||||||
|
// public static final int TAG_SUB_LOCATION = APPLICATION_RECORD | 92;
|
||||||
|
// /** 2:95 Province/State */
|
||||||
|
// public static final int TAG_PROVINCE_OR_STATE = APPLICATION_RECORD | 95; // 0x025f
|
||||||
|
// /** 2:100 Country/Primary Location Code */
|
||||||
|
// public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION_CODE = APPLICATION_RECORD | 100;
|
||||||
|
// /** 2:101 Country/Primary Location Name */
|
||||||
|
// public static final int TAG_COUNTRY_OR_PRIMARY_LOCATION = APPLICATION_RECORD | 101; // 0x0265
|
||||||
|
// /** 2:103 Original Transmission Reference */
|
||||||
|
// public static final int TAG_ORIGINAL_TRANSMISSION_REFERENCE = APPLICATION_RECORD | 103; // 0x0267
|
||||||
|
// /** 2:105 Headline */
|
||||||
|
// public static final int TAG_HEADLINE = APPLICATION_RECORD | 105; // 0x0269
|
||||||
|
// /** 2:110 Credit */
|
||||||
|
// public static final int TAG_CREDIT = APPLICATION_RECORD | 110; // 0x026e
|
||||||
|
// /** 2:115 Source */
|
||||||
|
// public static final int TAG_SOURCE = APPLICATION_RECORD | 115; // 0x0273
|
||||||
|
// /** 2:116 Copyright Notice */
|
||||||
|
// public static final int TAG_COPYRIGHT_NOTICE = APPLICATION_RECORD | 116; // 0x0274
|
||||||
|
// /** 2:118 Contact */
|
||||||
|
// public static final int TAG_CONTACT = APPLICATION_RECORD | 118;
|
||||||
|
// /** 2:120 Catption/Abstract */
|
||||||
|
// public static final int TAG_CAPTION = APPLICATION_RECORD | 120; // 0x0278
|
||||||
|
// /** 2:122 Writer/Editor (repeatable) */
|
||||||
|
// public static final int TAG_WRITER = APPLICATION_RECORD | 122; // 0x027a
|
||||||
|
// /** 2:125 Rasterized Caption (binary data) */
|
||||||
|
// public static final int TAG_RASTERIZED_CATPTION = APPLICATION_RECORD | 125;
|
||||||
|
// /** 2:130 Image Type */
|
||||||
|
// public static final int TAG_IMAGE_TYPE = APPLICATION_RECORD | 130;
|
||||||
|
// /** 2:131 Image Orientation */
|
||||||
|
// public static final int TAG_IMAGE_ORIENTATION = APPLICATION_RECORD | 131;
|
||||||
|
// /** 2:135 Language Identifier */
|
||||||
|
// public static final int TAG_LANGUAGE_IDENTIFIER = APPLICATION_RECORD | 135;
|
||||||
|
//
|
||||||
|
// // TODO: Should we expose this field?
|
||||||
|
// /**
|
||||||
|
// * 2:199 JobMinder Assignment Data (Custom IPTC field).
|
||||||
|
// * A common custom IPTC field used by a now discontinued application called JobMinder.
|
||||||
|
// *
|
||||||
|
// * @see <a href="http://www.jobminder.net/">JobMinder Homepage</a>
|
||||||
|
// */
|
||||||
|
// static final int CUSTOM_TAG_JOBMINDER_ASSIGMENT_DATA = APPLICATION_RECORD | 199;
|
||||||
|
//
|
||||||
|
// // TODO: 2:150-2:154 Audio and 2:200-2:202 Object Preview Data
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,9 @@ import java.lang.reflect.Field;
|
|||||||
* @version $Id: PSDImageResource.java,v 1.0 Apr 29, 2008 5:49:06 PM haraldk Exp$
|
* @version $Id: PSDImageResource.java,v 1.0 Apr 29, 2008 5:49:06 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
class PSDImageResource {
|
class PSDImageResource {
|
||||||
|
// TODO: Refactor image resources to separate package
|
||||||
|
// TODO: Change constructor to store stream offset and length only (+ possibly the name), defer reading
|
||||||
|
|
||||||
final short mId;
|
final short mId;
|
||||||
final String mName;
|
final String mName;
|
||||||
final long mSize;
|
final long mSize;
|
||||||
@ -61,6 +64,8 @@ class PSDImageResource {
|
|||||||
mSize = pInput.readUnsignedInt();
|
mSize = pInput.readUnsignedInt();
|
||||||
readData(pInput);
|
readData(pInput);
|
||||||
|
|
||||||
|
// TODO: Sanity check reading here?
|
||||||
|
|
||||||
// Data is even-padded
|
// Data is even-padded
|
||||||
if (mSize % 2 != 0) {
|
if (mSize % 2 != 0) {
|
||||||
pInput.read();
|
pInput.read();
|
||||||
@ -114,6 +119,8 @@ class PSDImageResource {
|
|||||||
case PSD.RES_ALPHA_CHANNEL_INFO:
|
case PSD.RES_ALPHA_CHANNEL_INFO:
|
||||||
case PSD.RES_DISPLAY_INFO:
|
case PSD.RES_DISPLAY_INFO:
|
||||||
case PSD.RES_PRINT_FLAGS:
|
case PSD.RES_PRINT_FLAGS:
|
||||||
|
case PSD.RES_IPTC_NAA:
|
||||||
|
case PSD.RES_GRID_AND_GUIDES_INFO:
|
||||||
case PSD.RES_THUMBNAIL_PS4:
|
case PSD.RES_THUMBNAIL_PS4:
|
||||||
case PSD.RES_THUMBNAIL:
|
case PSD.RES_THUMBNAIL:
|
||||||
case PSD.RES_ICC_PROFILE:
|
case PSD.RES_ICC_PROFILE:
|
||||||
@ -121,6 +128,8 @@ class PSDImageResource {
|
|||||||
case PSD.RES_EXIF_DATA_1:
|
case PSD.RES_EXIF_DATA_1:
|
||||||
// case PSD.RES_EXIF_DATA_3:
|
// case PSD.RES_EXIF_DATA_3:
|
||||||
case PSD.RES_XMP_DATA:
|
case PSD.RES_XMP_DATA:
|
||||||
|
case PSD.RES_PRINT_SCALE:
|
||||||
|
case PSD.RES_PIXEL_ASPECT_RATIO:
|
||||||
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
||||||
return null;
|
return null;
|
||||||
default:
|
default:
|
||||||
@ -135,7 +144,7 @@ class PSDImageResource {
|
|||||||
catch (IllegalAccessException ignore) {
|
catch (IllegalAccessException ignore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown resource";
|
return "UnknownResource";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,17 +166,27 @@ class PSDImageResource {
|
|||||||
return new PSDDisplayInfo(id, pInput);
|
return new PSDDisplayInfo(id, pInput);
|
||||||
case PSD.RES_PRINT_FLAGS:
|
case PSD.RES_PRINT_FLAGS:
|
||||||
return new PSDPrintFlags(id, pInput);
|
return new PSDPrintFlags(id, pInput);
|
||||||
|
case PSD.RES_IPTC_NAA:
|
||||||
|
return new PSDIPTCData(id, pInput);
|
||||||
|
case PSD.RES_GRID_AND_GUIDES_INFO:
|
||||||
|
return new PSDGridAndGuideInfo(id, pInput);
|
||||||
case PSD.RES_THUMBNAIL_PS4:
|
case PSD.RES_THUMBNAIL_PS4:
|
||||||
case PSD.RES_THUMBNAIL:
|
case PSD.RES_THUMBNAIL:
|
||||||
return new PSDThumbnail(id, pInput);
|
return new PSDThumbnail(id, pInput);
|
||||||
case PSD.RES_ICC_PROFILE:
|
case PSD.RES_ICC_PROFILE:
|
||||||
return new ICCProfile(id, pInput);
|
return new ICCProfile(id, pInput);
|
||||||
|
case PSD.RES_UNICODE_ALPHA_NAMES:
|
||||||
|
return new PSDUnicodeAlphaNames(id, pInput);
|
||||||
case PSD.RES_VERSION_INFO:
|
case PSD.RES_VERSION_INFO:
|
||||||
return new PSDVersionInfo(id, pInput);
|
return new PSDVersionInfo(id, pInput);
|
||||||
case PSD.RES_EXIF_DATA_1:
|
case PSD.RES_EXIF_DATA_1:
|
||||||
return new PSDEXIF1Data(id, pInput);
|
return new PSDEXIF1Data(id, pInput);
|
||||||
case PSD.RES_XMP_DATA:
|
case PSD.RES_XMP_DATA:
|
||||||
return new PSDXMPData(id, pInput);
|
return new PSDXMPData(id, pInput);
|
||||||
|
case PSD.RES_PRINT_SCALE:
|
||||||
|
return new PSDPrintScale(id, pInput);
|
||||||
|
case PSD.RES_PIXEL_ASPECT_RATIO:
|
||||||
|
return new PSDPixelAspectRatio(id, pInput);
|
||||||
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
||||||
return new PSDPrintFlagsInformation(id, pInput);
|
return new PSDPrintFlagsInformation(id, pInput);
|
||||||
default:
|
default:
|
||||||
|
@ -43,11 +43,24 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
|
|
||||||
static final String[] DISPLAY_INFO_CS = {
|
static final String[] DISPLAY_INFO_CS = {
|
||||||
"RGB", "HSB", "CMYK", "PANTONE", "FOCOLTONE", "TRUMATCH", "TOYO", "LAB", "GRAYSCALE", null, "HKS", "DIC",
|
"RGB", "HSB", "CMYK", "PANTONE", "FOCOLTONE", "TRUMATCH", "TOYO", "LAB", "GRAYSCALE", null, "HKS", "DIC",
|
||||||
null, // ... (until index 2999),
|
null, // TODO: ... (until index 2999),
|
||||||
"ANPA"
|
"ANPA"
|
||||||
};
|
};
|
||||||
static final String[] DISPLAY_INFO_KINDS = {"selected", "protected"};
|
static final String[] DISPLAY_INFO_KINDS = {"selected", "protected"};
|
||||||
|
|
||||||
|
static final String[] RESOLUTION_UNITS = {null, "pixels/inch", "pixels/cm"};
|
||||||
|
static final String[] DIMENSION_UNITS = {null, "in", "cm", "pt", "picas", "columns"};
|
||||||
|
|
||||||
|
static final String[] JAVA_CS = {
|
||||||
|
"XYZ", "Lab", "Yuv", "YCbCr", "Yxy", "RGB", "GRAY", "HSV", "HLS", "CMYK", "CMY",
|
||||||
|
"2CLR", "3CLR", "4CLR", "5CLR", "6CLR", "7CLR", "8CLR", "9CLR", "ACLR", "BCLR", "CCLR", "DCLR", "ECLR", "FCLR"
|
||||||
|
};
|
||||||
|
|
||||||
|
static final String[] GUIDE_ORIENTATIONS = {"vertical", "horizontal"};
|
||||||
|
|
||||||
|
static final String[] PRINT_SCALE_STYLES = {"centered", "scaleToFit", "userDefined"};
|
||||||
|
|
||||||
|
|
||||||
protected PSDMetadata() {
|
protected PSDMetadata() {
|
||||||
// TODO: Allow XMP, EXIF and IPTC as extra formats?
|
// TODO: Allow XMP, EXIF and IPTC as extra formats?
|
||||||
super(true, NATIVE_METADATA_FORMAT_NAME, NATIVE_METADATA_FORMAT_CLASS_NAME, null, null);
|
super(true, NATIVE_METADATA_FORMAT_NAME, NATIVE_METADATA_FORMAT_CLASS_NAME, null, null);
|
||||||
@ -155,8 +168,9 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Node createHeaderNode() {
|
private Node createHeaderNode() {
|
||||||
IIOMetadataNode header = new IIOMetadataNode("PSDHeader");
|
IIOMetadataNode header = new IIOMetadataNode("Header");
|
||||||
|
|
||||||
|
header.setAttribute("type", "PSD");
|
||||||
header.setAttribute("version", "1");
|
header.setAttribute("version", "1");
|
||||||
header.setAttribute("channels", Integer.toString(mHeader.mChannels));
|
header.setAttribute("channels", Integer.toString(mHeader.mChannels));
|
||||||
header.setAttribute("height", Integer.toString(mHeader.mHeight));
|
header.setAttribute("height", Integer.toString(mHeader.mHeight));
|
||||||
@ -175,7 +189,15 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
// TODO: Always add name (if set) and id (as resourceId) to all nodes?
|
// TODO: Always add name (if set) and id (as resourceId) to all nodes?
|
||||||
// Resource Id is useful for people with access to the PSD spec..
|
// Resource Id is useful for people with access to the PSD spec..
|
||||||
|
|
||||||
if (imageResource instanceof PSDAlphaChannelInfo) {
|
if (imageResource instanceof ICCProfile) {
|
||||||
|
ICCProfile profile = (ICCProfile) imageResource;
|
||||||
|
|
||||||
|
// TODO: Format spec
|
||||||
|
node = new IIOMetadataNode("ICCProfile");
|
||||||
|
node.setAttribute("colorSpaceType", JAVA_CS[profile.getProfile().getColorSpaceType()]);
|
||||||
|
node.setUserObject(profile.getProfile());
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDAlphaChannelInfo) {
|
||||||
PSDAlphaChannelInfo alphaChannelInfo = (PSDAlphaChannelInfo) imageResource;
|
PSDAlphaChannelInfo alphaChannelInfo = (PSDAlphaChannelInfo) imageResource;
|
||||||
|
|
||||||
node = new IIOMetadataNode("AlphaChannelInfo");
|
node = new IIOMetadataNode("AlphaChannelInfo");
|
||||||
@ -185,8 +207,6 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
nameNode.setAttribute("value", name);
|
nameNode.setAttribute("value", name);
|
||||||
node.appendChild(nameNode);
|
node.appendChild(nameNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
resource.appendChild(node);
|
|
||||||
}
|
}
|
||||||
else if (imageResource instanceof PSDDisplayInfo) {
|
else if (imageResource instanceof PSDDisplayInfo) {
|
||||||
PSDDisplayInfo displayInfo = (PSDDisplayInfo) imageResource;
|
PSDDisplayInfo displayInfo = (PSDDisplayInfo) imageResource;
|
||||||
@ -205,14 +225,121 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
node.setAttribute("colors", builder.toString());
|
node.setAttribute("colors", builder.toString());
|
||||||
node.setAttribute("opacity", Integer.toString(displayInfo.mOpacity));
|
node.setAttribute("opacity", Integer.toString(displayInfo.mOpacity));
|
||||||
node.setAttribute("kind", DISPLAY_INFO_KINDS[displayInfo.mKind]);
|
node.setAttribute("kind", DISPLAY_INFO_KINDS[displayInfo.mKind]);
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDGridAndGuideInfo) {
|
||||||
|
PSDGridAndGuideInfo info = (PSDGridAndGuideInfo) imageResource;
|
||||||
|
|
||||||
resource.appendChild(node);
|
node = new IIOMetadataNode("GridAndGuideInfo");
|
||||||
|
node.setAttribute("version", String.valueOf(info.mVersion));
|
||||||
|
node.setAttribute("verticalGridCycle", String.valueOf(info.mGridCycleVertical));
|
||||||
|
node.setAttribute("horizontalGridCycle", String.valueOf(info.mGridCycleHorizontal));
|
||||||
|
|
||||||
|
for (PSDGridAndGuideInfo.GuideResource guide : info.mGuides) {
|
||||||
|
IIOMetadataNode guideNode = new IIOMetadataNode("Guide");
|
||||||
|
guideNode.setAttribute("location", Integer.toString(guide.mLocation));
|
||||||
|
guideNode.setAttribute("orientation", GUIDE_ORIENTATIONS[guide.mDirection]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDPixelAspectRatio) {
|
||||||
|
PSDPixelAspectRatio aspectRatio = (PSDPixelAspectRatio) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("PixelAspectRatio");
|
||||||
|
node.setAttribute("version", String.valueOf(aspectRatio.mVersion));
|
||||||
|
node.setAttribute("aspectRatio", String.valueOf(aspectRatio.mAspect));
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDPrintFlags) {
|
||||||
|
PSDPrintFlags flags = (PSDPrintFlags) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("PrintFlags");
|
||||||
|
node.setAttribute("labels", String.valueOf(flags.mLabels));
|
||||||
|
node.setAttribute("cropMarks", String.valueOf(flags.mCropMasks));
|
||||||
|
node.setAttribute("colorBars", String.valueOf(flags.mColorBars));
|
||||||
|
node.setAttribute("registrationMarks", String.valueOf(flags.mRegistrationMarks));
|
||||||
|
node.setAttribute("negative", String.valueOf(flags.mNegative));
|
||||||
|
node.setAttribute("flip", String.valueOf(flags.mFlip));
|
||||||
|
node.setAttribute("interpolate", String.valueOf(flags.mInterpolate));
|
||||||
|
node.setAttribute("caption", String.valueOf(flags.mCaption));
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDPrintFlagsInformation) {
|
||||||
|
PSDPrintFlagsInformation information = (PSDPrintFlagsInformation) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("PrintFlagsInformation");
|
||||||
|
node.setAttribute("version", String.valueOf(information.mVersion));
|
||||||
|
node.setAttribute("cropMarks", String.valueOf(information.mCropMasks));
|
||||||
|
node.setAttribute("field", String.valueOf(information.mField));
|
||||||
|
node.setAttribute("bleedWidth", String.valueOf(information.mBleedWidth));
|
||||||
|
node.setAttribute("bleedScale", String.valueOf(information.mBleedScale));
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDPrintScale) {
|
||||||
|
PSDPrintScale printScale = (PSDPrintScale) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("PrintScale");
|
||||||
|
node.setAttribute("style", PRINT_SCALE_STYLES[printScale.mStyle]);
|
||||||
|
node.setAttribute("xLocation", String.valueOf(printScale.mXLocation));
|
||||||
|
node.setAttribute("yLocation", String.valueOf(printScale.mYlocation));
|
||||||
|
node.setAttribute("scale", String.valueOf(printScale.mScale));
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDResolutionInfo) {
|
||||||
|
PSDResolutionInfo information = (PSDResolutionInfo) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("ResolutionInfo");
|
||||||
|
node.setAttribute("horizontalResolution", String.valueOf(information.mHRes));
|
||||||
|
node.setAttribute("horizontalResolutionUnit", RESOLUTION_UNITS[information.mHResUnit]);
|
||||||
|
node.setAttribute("widthUnit", DIMENSION_UNITS[information.mWidthUnit]);
|
||||||
|
node.setAttribute("verticalResolution", String.valueOf(information.mVRes));
|
||||||
|
node.setAttribute("verticalResolutionUnit", RESOLUTION_UNITS[information.mVResUnit]);
|
||||||
|
node.setAttribute("heightUnit", DIMENSION_UNITS[information.mHeightUnit]);
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDUnicodeAlphaNames) {
|
||||||
|
PSDUnicodeAlphaNames alphaNames = (PSDUnicodeAlphaNames) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("UnicodeAlphaNames");
|
||||||
|
|
||||||
|
for (String name : alphaNames.mNames) {
|
||||||
|
IIOMetadataNode nameNode = new IIOMetadataNode("Name");
|
||||||
|
nameNode.setAttribute("value", name);
|
||||||
|
node.appendChild(nameNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDVersionInfo) {
|
||||||
|
PSDVersionInfo information = (PSDVersionInfo) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("VersionInfo");
|
||||||
|
node.setAttribute("version", String.valueOf(information.mVersion));
|
||||||
|
node.setAttribute("hasRealMergedData", String.valueOf(information.mHasRealMergedData));
|
||||||
|
node.setAttribute("writer", information.mWriter);
|
||||||
|
node.setAttribute("reader", information.mReader);
|
||||||
|
node.setAttribute("fileVersion", String.valueOf(information.mFileVersion));
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDThumbnail) {
|
||||||
|
// TODO: Revise/rethink this...
|
||||||
|
PSDThumbnail thumbnail = (PSDThumbnail) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("Thumbnail");
|
||||||
|
// TODO: Thumbnail attributes + access to data, to avoid JPEG re-compression problems
|
||||||
|
node.setUserObject(thumbnail.getThumbnail());
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDIPTCData) {
|
||||||
|
// TODO: Revise/rethink this...
|
||||||
|
// Transcode to XMP? ;-)
|
||||||
|
PSDIPTCData iptc = (PSDIPTCData) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("IPTC");
|
||||||
|
node.setUserObject(iptc.mDirectory);
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDEXIF1Data) {
|
||||||
|
// TODO: Revise/rethink this...
|
||||||
|
// Transcode to XMP? ;-)
|
||||||
|
PSDEXIF1Data exif = (PSDEXIF1Data) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("EXIF");
|
||||||
|
node.setUserObject(exif.mDirectory);
|
||||||
}
|
}
|
||||||
else if (imageResource instanceof PSDXMPData) {
|
else if (imageResource instanceof PSDXMPData) {
|
||||||
// TODO: Revise/rethink this...
|
// TODO: Revise/rethink this... Would it be possible to parse XMP as IIOMetadataNodes? Or is that just stupid...
|
||||||
PSDXMPData xmp = (PSDXMPData) imageResource;
|
PSDXMPData xmp = (PSDXMPData) imageResource;
|
||||||
|
|
||||||
node = new IIOMetadataNode("XMPData");
|
node = new IIOMetadataNode("XMP");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
@ -225,20 +352,16 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
resource.appendChild(node);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Generic resource..
|
// Generic resource..
|
||||||
node = new IIOMetadataNode(PSDImageResource.resourceTypeForId(imageResource.mId));
|
node = new IIOMetadataNode(PSDImageResource.resourceTypeForId(imageResource.mId));
|
||||||
|
|
||||||
resource.appendChild(node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO: More resources
|
// TODO: More resources
|
||||||
|
|
||||||
node.setAttribute("resourceId", Integer.toHexString(imageResource.mId));
|
node.setAttribute("resourceId", String.format("0x%04x", imageResource.mId));
|
||||||
|
resource.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
|
@ -4,6 +4,7 @@ import org.w3c.dom.Document;
|
|||||||
|
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -32,20 +33,19 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
|
|
||||||
// root -> PSDHeader
|
// root -> PSDHeader
|
||||||
// TODO: How do I specify that the header is required?
|
// TODO: How do I specify that the header is required?
|
||||||
addElement("PSDHeader", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_EMPTY);
|
addElement("Header", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_EMPTY);
|
||||||
|
|
||||||
// TODO: Do the first two make sense?
|
addAttribute("Header", "type", DATATYPE_STRING, false, "PSD", Arrays.asList("PSD", "PSB"));
|
||||||
// addAttribute("PSDHeader", "signature", DATATYPE_STRING, false, "8BPS", Arrays.asList("8BPS"));
|
addAttribute("Header", "version", DATATYPE_INTEGER, false, "1", Arrays.asList("1"));
|
||||||
addAttribute("PSDHeader", "version", DATATYPE_INTEGER, false, "1", Arrays.asList("1"));
|
|
||||||
|
|
||||||
addAttribute("PSDHeader", "channels", DATATYPE_INTEGER, true, null, "1", "24", true, true);
|
addAttribute("Header", "channels", DATATYPE_INTEGER, true, null, "1", "24", true, true);
|
||||||
// rows?
|
// rows?
|
||||||
addAttribute("PSDHeader", "height", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
addAttribute("Header", "height", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
||||||
// columns?
|
// columns?
|
||||||
addAttribute("PSDHeader", "width", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
addAttribute("Header", "width", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
||||||
addAttribute("PSDHeader", "bits", DATATYPE_INTEGER, true, null, Arrays.asList("1", "8", "16"));
|
addAttribute("Header", "bits", DATATYPE_INTEGER, true, null, Arrays.asList("1", "8", "16"));
|
||||||
// TODO: Consider using more readable names?!
|
// TODO: Consider using more readable names?!
|
||||||
addAttribute("PSDHeader", "mode", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.COLOR_MODES));
|
addAttribute("Header", "mode", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.COLOR_MODES));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Contains the required data to define the color mode.
|
Contains the required data to define the color mode.
|
||||||
@ -85,22 +85,46 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
// root -> ImageResources -> AlphaChannelInfo
|
// root -> ImageResources -> AlphaChannelInfo
|
||||||
addElement("AlphaChannelInfo", "ImageResources", 0, Integer.MAX_VALUE); // The format probably does not support that many layers..
|
addElement("AlphaChannelInfo", "ImageResources", 0, Integer.MAX_VALUE); // The format probably does not support that many layers..
|
||||||
addElement("Name", "AlphaChannelInfo", CHILD_POLICY_EMPTY);
|
addElement("Name", "AlphaChannelInfo", CHILD_POLICY_EMPTY);
|
||||||
addAttribute("Name", "value", DATATYPE_STRING, true, 0, Integer.MAX_VALUE);
|
addAttribute("Name", "value", DATATYPE_STRING, true, null);
|
||||||
|
|
||||||
// root -> ImageResources -> DisplayInfo
|
// root -> ImageResources -> DisplayInfo
|
||||||
addElement("DisplayInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
addElement("DisplayInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
// TODO: Consider using human readable strings
|
// TODO: Consider using human readable strings
|
||||||
// TODO: Limit values (0-8, 10, 11, 3000)
|
// TODO: Limit values (0-8, 10, 11, 3000)
|
||||||
addAttribute("DisplayInfo", "colorSpace", DATATYPE_INTEGER, true, null);
|
addAttribute("DisplayInfo", "colorSpace", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.DISPLAY_INFO_CS));
|
||||||
addAttribute("DisplayInfo", "colors", DATATYPE_INTEGER, true, 4, 4);
|
addAttribute("DisplayInfo", "colors", DATATYPE_INTEGER, true, 4, 4);
|
||||||
addAttribute("DisplayInfo", "opacity", DATATYPE_INTEGER, true, null, "0", "100", true, true);
|
addAttribute("DisplayInfo", "opacity", DATATYPE_INTEGER, true, null, "0", "100", true, true);
|
||||||
// TODO: Consider using human readable strings
|
// TODO: Consider using human readable strings
|
||||||
addAttribute("DisplayInfo", "kind", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.DISPLAY_INFO_KINDS));
|
addAttribute("DisplayInfo", "kind", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.DISPLAY_INFO_KINDS));
|
||||||
|
|
||||||
// root -> ImageResources -> EXIF1Data
|
// root -> ImageResources -> EXIF
|
||||||
addElement("EXIF1Data", "ImageResources", CHILD_POLICY_ALL);
|
addElement("EXIF", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addObjectValue("EXIF", PSDEXIF1Data.Directory.class, true, null);
|
||||||
// TODO: Incorporate EXIF / TIFF metadata here somehow... (or treat as opaque bytes?)
|
// TODO: Incorporate EXIF / TIFF metadata here somehow... (or treat as opaque bytes?)
|
||||||
|
|
||||||
|
// root -> ImageResources -> GridAndGuideInfo
|
||||||
|
addElement("GridAndGuideInfo", "ImageResources", 0, Integer.MAX_VALUE);
|
||||||
|
addAttribute("GridAndGuideInfo", "version", DATATYPE_INTEGER, false, "1");
|
||||||
|
addAttribute("GridAndGuideInfo", "verticalGridCycle", DATATYPE_INTEGER, false, "576");
|
||||||
|
addAttribute("GridAndGuideInfo", "horizontalGridCycle", DATATYPE_INTEGER, false, "576");
|
||||||
|
addElement("Guide", "GridAndGuideInfo", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("Guide", "location", DATATYPE_INTEGER, true, null, "0", Integer.toString(Integer.MAX_VALUE), true, true);
|
||||||
|
addAttribute("Guide", "orientation", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.GUIDE_ORIENTATIONS));
|
||||||
|
|
||||||
|
// root -> ImageResources -> ICCProfile
|
||||||
|
addElement("ICCProfile", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("ICCProfile", "colorSpaceType", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.JAVA_CS));
|
||||||
|
|
||||||
|
// root -> ImageResources -> IPTC
|
||||||
|
addElement("IPTC", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addObjectValue("IPTC", PSDIPTCData.Directory.class, true, null);
|
||||||
|
// TODO: Incorporate IPTC metadata here somehow... (or treat as opaque bytes?)
|
||||||
|
|
||||||
|
// root -> ImageResources -> PixelAspectRatio
|
||||||
|
addElement("PixelAspectRatio", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("PixelAspectRatio", "version", DATATYPE_STRING, false, "1");
|
||||||
|
addAttribute("PixelAspectRatio", "aspectRatio", DATATYPE_DOUBLE, true, null, "0", Double.toString(Double.POSITIVE_INFINITY), true, false);
|
||||||
|
|
||||||
// root -> ImageResources -> PrintFlags
|
// root -> ImageResources -> PrintFlags
|
||||||
addElement("PrintFlags", "ImageResources", CHILD_POLICY_EMPTY);
|
addElement("PrintFlags", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
addBooleanAttribute("PrintFlags", "labels", false, false);
|
addBooleanAttribute("PrintFlags", "labels", false, false);
|
||||||
@ -114,29 +138,53 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
|
|
||||||
// root -> ImageResources -> PrintFlagsInformation
|
// root -> ImageResources -> PrintFlagsInformation
|
||||||
addElement("PrintFlagsInformation", "ImageResources", CHILD_POLICY_EMPTY);
|
addElement("PrintFlagsInformation", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
addAttribute("PrintFlagsInformation", "version", DATATYPE_INTEGER, true, null);
|
addAttribute("PrintFlagsInformation", "version", DATATYPE_INTEGER, false, "1");
|
||||||
addBooleanAttribute("PrintFlagsInformation", "cropMarks", false, false);
|
addBooleanAttribute("PrintFlagsInformation", "cropMarks", false, false);
|
||||||
addAttribute("PrintFlagsInformation", "field", DATATYPE_INTEGER, true, null);
|
addAttribute("PrintFlagsInformation", "field", DATATYPE_INTEGER, true, "0");
|
||||||
addAttribute("PrintFlagsInformation", "bleedWidth", DATATYPE_INTEGER, true, null, "0", String.valueOf(Long.MAX_VALUE), true, true); // TODO: LONG??!
|
addAttribute("PrintFlagsInformation", "bleedWidth", DATATYPE_INTEGER, true, null, "0", String.valueOf(Long.MAX_VALUE), true, true); // TODO: LONG??!
|
||||||
addAttribute("PrintFlagsInformation", "bleedScale", DATATYPE_INTEGER, true, null, "0", String.valueOf(Integer.MAX_VALUE), true, true);
|
addAttribute("PrintFlagsInformation", "bleedScale", DATATYPE_INTEGER, true, null, "0", String.valueOf(Integer.MAX_VALUE), true, true);
|
||||||
|
|
||||||
|
// root -> ImageResources -> PrintScale
|
||||||
|
addElement("PrintScale", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("PrintScale", "style", DATATYPE_STRING, false, null, Arrays.asList(PSDMetadata.PRINT_SCALE_STYLES));
|
||||||
|
addAttribute("PrintScale", "xLocation", DATATYPE_FLOAT, true, null);
|
||||||
|
addAttribute("PrintScale", "yLocation", DATATYPE_FLOAT, true, null);
|
||||||
|
addAttribute("PrintScale", "scale", DATATYPE_FLOAT, true, null);
|
||||||
|
|
||||||
// root -> ImageResources -> ResolutionInfo
|
// root -> ImageResources -> ResolutionInfo
|
||||||
addElement("ResolutionInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
addElement("ResolutionInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
addAttribute("ResolutionInfo", "hRes", DATATYPE_FLOAT, true, null);
|
addAttribute("ResolutionInfo", "hRes", DATATYPE_FLOAT, true, null);
|
||||||
// TODO: Or use string and more friendly names? "pixels/inch"/"pixels/cm" and "inch"/"cm"/"pt"/"pica"/"column"
|
addAttribute("ResolutionInfo", "hResUnit", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.RESOLUTION_UNITS));
|
||||||
addAttribute("ResolutionInfo", "hResUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2"));
|
addAttribute("ResolutionInfo", "widthUnit", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.DIMENSION_UNITS));
|
||||||
addAttribute("ResolutionInfo", "widthUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2", "3", "4", "5"));
|
|
||||||
addAttribute("ResolutionInfo", "vRes", DATATYPE_FLOAT, true, null);
|
addAttribute("ResolutionInfo", "vRes", DATATYPE_FLOAT, true, null);
|
||||||
// TODO: Or use more friendly names?
|
addAttribute("ResolutionInfo", "vResUnit", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.RESOLUTION_UNITS));
|
||||||
addAttribute("ResolutionInfo", "vResUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2"));
|
addAttribute("ResolutionInfo", "heightUnit", DATATYPE_STRING, true, null, Arrays.asList(PSDMetadata.DIMENSION_UNITS));
|
||||||
addAttribute("ResolutionInfo", "heightUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2", "3", "4", "5"));
|
|
||||||
|
|
||||||
// ??? addElement("Thumbnail", "ImageResources", CHILD_POLICY_CHOICE);
|
// root -> ImageResources -> UnicodeAlphaNames
|
||||||
|
addElement("UnicodeAlphaNames", "ImageResources", 0, Integer.MAX_VALUE);
|
||||||
|
addChildElement("UnicodeAlphaNames", "Name"); // TODO: Does this really work?
|
||||||
|
|
||||||
// root -> ImageResources -> XMPData
|
|
||||||
addElement("XMPData", "ImageResources", CHILD_POLICY_CHOICE);
|
// root -> ImageResources -> VersionInfo
|
||||||
|
addElement("VersionInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("VersionInfo", "version", DATATYPE_INTEGER, false, "1");
|
||||||
|
addBooleanAttribute("VersionInfo", "hasRealMergedData", false, false);
|
||||||
|
addAttribute("VersionInfo", "writer", DATATYPE_STRING, true, null);
|
||||||
|
addAttribute("VersionInfo", "reader", DATATYPE_STRING, true, null);
|
||||||
|
addAttribute("VersionInfo", "fileVersion", DATATYPE_INTEGER, true, "1");
|
||||||
|
|
||||||
|
// root -> ImageResources -> Thumbnail
|
||||||
|
addElement("Thumbnail", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addObjectValue("Thumbnail", BufferedImage.class, true, null);
|
||||||
|
|
||||||
|
// root -> ImageResources -> UnicodeAlphaName
|
||||||
|
addElement("UnicodeAlphaName", "ImageResources", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("UnicodeAlphaName", "value", DATATYPE_STRING, true, null);
|
||||||
|
|
||||||
|
// root -> ImageResources -> XMP
|
||||||
|
addElement("XMP", "ImageResources", CHILD_POLICY_CHOICE);
|
||||||
// TODO: Incorporate XMP metadata here somehow (or treat as opaque bytes?)
|
// TODO: Incorporate XMP metadata here somehow (or treat as opaque bytes?)
|
||||||
addObjectValue("XMPData", Document.class, true, null);
|
addObjectValue("XMP", Document.class, true, null);
|
||||||
|
|
||||||
// TODO: Layers
|
// TODO: Layers
|
||||||
//addElement("ChannelSourceDestinationRange", "LayerSomething", CHILD_POLICY_CHOICE);
|
//addElement("ChannelSourceDestinationRange", "LayerSomething", CHILD_POLICY_CHOICE);
|
||||||
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDPixelAspectRatio
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDPixelAspectRatio.java,v 1.0 Nov 7, 2009 8:23:09 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDPixelAspectRatio extends PSDImageResource {
|
||||||
|
// 4 bytes (version = 1), 8 bytes double, x / y of a pixel
|
||||||
|
int mVersion;
|
||||||
|
double mAspect;
|
||||||
|
|
||||||
|
PSDPixelAspectRatio(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
mVersion = pInput.readInt();
|
||||||
|
mAspect = pInput.readDouble();
|
||||||
|
}
|
||||||
|
}
|
@ -11,14 +11,14 @@ import java.io.IOException;
|
|||||||
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class PSDPrintFlags extends PSDImageResource {
|
final class PSDPrintFlags extends PSDImageResource {
|
||||||
private boolean mLabels;
|
boolean mLabels;
|
||||||
private boolean mCropMasks;
|
boolean mCropMasks;
|
||||||
private boolean mColorBars;
|
boolean mColorBars;
|
||||||
private boolean mRegistrationMarks;
|
boolean mRegistrationMarks;
|
||||||
private boolean mNegative;
|
boolean mNegative;
|
||||||
private boolean mFlip;
|
boolean mFlip;
|
||||||
private boolean mInterpolate;
|
boolean mInterpolate;
|
||||||
private boolean mCaption;
|
boolean mCaption;
|
||||||
|
|
||||||
PSDPrintFlags(final short pId, final ImageInputStream pInput) throws IOException {
|
PSDPrintFlags(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
super(pId, pInput);
|
super(pId, pInput);
|
||||||
|
@ -11,11 +11,11 @@ import java.io.IOException;
|
|||||||
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
final class PSDPrintFlagsInformation extends PSDImageResource {
|
final class PSDPrintFlagsInformation extends PSDImageResource {
|
||||||
private int mVersion;
|
int mVersion;
|
||||||
private boolean mCropMasks;
|
boolean mCropMasks;
|
||||||
private int mField;
|
int mField;
|
||||||
private long mBleedWidth;
|
long mBleedWidth;
|
||||||
private int mBleedScale;
|
int mBleedScale;
|
||||||
|
|
||||||
PSDPrintFlagsInformation(final short pId, final ImageInputStream pInput) throws IOException {
|
PSDPrintFlagsInformation(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
super(pId, pInput);
|
super(pId, pInput);
|
||||||
@ -25,7 +25,7 @@ final class PSDPrintFlagsInformation extends PSDImageResource {
|
|||||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
mVersion = pInput.readUnsignedShort();
|
mVersion = pInput.readUnsignedShort();
|
||||||
mCropMasks = pInput.readBoolean();
|
mCropMasks = pInput.readBoolean();
|
||||||
mField = pInput.readUnsignedByte();
|
mField = pInput.readUnsignedByte(); // TODO: Is this really pad?
|
||||||
mBleedWidth = pInput.readUnsignedInt();
|
mBleedWidth = pInput.readUnsignedInt();
|
||||||
mBleedScale = pInput.readUnsignedShort();
|
mBleedScale = pInput.readUnsignedShort();
|
||||||
|
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDPrintScale
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDPrintScale.java,v 1.0 Nov 7, 2009 9:41:17 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDPrintScale extends PSDImageResource {
|
||||||
|
// 2 bytes style (0 = centered, 1 = size to fit, 2 = user defined).
|
||||||
|
// 4 bytes x location (floating point).
|
||||||
|
// 4 bytes y location (floating point).
|
||||||
|
// 4 bytes scale (floating point)
|
||||||
|
|
||||||
|
short mStyle;
|
||||||
|
float mXLocation;
|
||||||
|
float mYlocation;
|
||||||
|
float mScale;
|
||||||
|
|
||||||
|
PSDPrintScale(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
mStyle = pInput.readShort();
|
||||||
|
mXLocation = pInput.readFloat();
|
||||||
|
mYlocation = pInput.readFloat();
|
||||||
|
mScale = pInput.readFloat();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDUnicodeAlphaNames
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDUnicodeAlphaNames.java,v 1.0 Nov 7, 2009 9:16:56 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDUnicodeAlphaNames extends PSDImageResource {
|
||||||
|
List<String> mNames;
|
||||||
|
|
||||||
|
PSDUnicodeAlphaNames(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
mNames = new ArrayList<String>();
|
||||||
|
|
||||||
|
long left = mSize;
|
||||||
|
while (left > 0) {
|
||||||
|
String name = PSDUtil.readUTF16String(pInput);
|
||||||
|
mNames.add(name);
|
||||||
|
left -= name.length() * 2 + 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,4 +2,5 @@ Implement source subsampling and region of interest
|
|||||||
Separate package for the resources (seems to be a lot)?
|
Separate package for the resources (seems to be a lot)?
|
||||||
Possibility to read only some resources? readResources(int[] resourceKeys)?
|
Possibility to read only some resources? readResources(int[] resourceKeys)?
|
||||||
- Probably faster when we only need the color space
|
- Probably faster when we only need the color space
|
||||||
PSDImageWriter
|
Support for Photoshop specific TIFF tags (extension for TIFFImageReader)?
|
||||||
|
PSDImageWriter?
|
Loading…
x
Reference in New Issue
Block a user