mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-03 11:35:29 -04:00
Work in progress for PSD metadata support:
- Implemented more of standard support - Changes to native format spec - Implemented more of native format - Minor changes in various resources due to meta data implementation
This commit is contained in:
parent
b5f6c96583
commit
0d41db32cf
@ -101,7 +101,7 @@ interface PSD {
|
|||||||
int COMPRESSION_ZIP = 2;
|
int COMPRESSION_ZIP = 2;
|
||||||
|
|
||||||
/** ZIP compression with prediction */
|
/** ZIP compression with prediction */
|
||||||
int COMPRESSION_ZIP_PREDICTON = 3;
|
int COMPRESSION_ZIP_PREDICTION = 3;
|
||||||
|
|
||||||
// Color Modes
|
// Color Modes
|
||||||
/** Bitmap (monochrome) */
|
/** Bitmap (monochrome) */
|
||||||
|
@ -48,11 +48,11 @@ class PSDAlphaChannelInfo extends PSDImageResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readData(ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
mNames = new ArrayList<String>();
|
mNames = new ArrayList<String>();
|
||||||
long left = mSize;
|
long left = mSize;
|
||||||
while (left > 0) {
|
while (left > 0) {
|
||||||
String name = PSDUtil.readPascalStringByte(pInput);
|
String name = PSDUtil.readPascalString(pInput);
|
||||||
mNames.add(name);
|
mNames.add(name);
|
||||||
left -= name.length() + 1;
|
left -= name.length() + 1;
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,22 @@ import java.io.IOException;
|
|||||||
* @version $Id: PSDResolutionInfo.java,v 1.0 May 2, 2008 3:58:19 PM haraldk Exp$
|
* @version $Id: PSDResolutionInfo.java,v 1.0 May 2, 2008 3:58:19 PM haraldk Exp$
|
||||||
*/
|
*/
|
||||||
class PSDDisplayInfo extends PSDImageResource {
|
class PSDDisplayInfo extends PSDImageResource {
|
||||||
// TODO: Size of this struct should be 14.. Does not compute... Something bogus here
|
// TODO: Size of this struct should be 14.. Does not compute... Something bogus here
|
||||||
|
|
||||||
|
// ColorSpace definitions:
|
||||||
|
// PSD_CS_RGB = 0, /* RGB */
|
||||||
|
// PSD_CS_HSB = 1, /* Hue, Saturation, Brightness */
|
||||||
|
// PSD_CS_CMYK = 2, /* CMYK */
|
||||||
|
// PSD_CS_PANTONE = 3, /* Pantone matching system (Lab)*/
|
||||||
|
// PSD_CS_FOCOLTONE = 4, /* Focoltone colour system (CMYK)*/
|
||||||
|
// PSD_CS_TRUMATCH = 5, /* Trumatch color (CMYK)*/
|
||||||
|
// PSD_CS_TOYO = 6, /* Toyo 88 colorfinder 1050 (Lab)*/
|
||||||
|
// PSD_CS_LAB = 7, /* L*a*b*/
|
||||||
|
// PSD_CS_GRAYSCALE = 8, /* Grey scale */
|
||||||
|
// PSD_CS_HKS = 10, /* HKS colors (CMYK)*/
|
||||||
|
// PSD_CS_DIC = 11, /* DIC color guide (Lab)*/
|
||||||
|
// PSD_CS_ANPA = 3000, /* Anpa color (Lab)*/
|
||||||
|
|
||||||
//typedef _DisplayInfo
|
//typedef _DisplayInfo
|
||||||
//{
|
//{
|
||||||
// WORD ColorSpace;
|
// WORD ColorSpace;
|
||||||
@ -50,10 +65,10 @@ class PSDDisplayInfo extends PSDImageResource {
|
|||||||
// BYTE Padding; /* Always zero */
|
// BYTE Padding; /* Always zero */
|
||||||
//} DISPLAYINFO;
|
//} DISPLAYINFO;
|
||||||
|
|
||||||
private int mColorSpace;
|
int mColorSpace;
|
||||||
private short[] mColors;
|
short[] mColors;
|
||||||
private short mOpacity;
|
short mOpacity;
|
||||||
private byte mKind;
|
byte mKind;
|
||||||
|
|
||||||
PSDDisplayInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
PSDDisplayInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
super(pId, pInput);
|
super(pId, pInput);
|
||||||
|
@ -10,6 +10,7 @@ import java.io.IOException;
|
|||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,8 +68,8 @@ final class PSDEXIF1Data extends PSDImageResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TIFF Image file directory (IFD)
|
// TIFF Image file directory (IFD)
|
||||||
private static class Directory {
|
static class Directory implements Iterable<Entry> {
|
||||||
List<Entry> mEntries = new ArrayList<Entry>();
|
private List<Entry> mEntries = new ArrayList<Entry>();
|
||||||
|
|
||||||
private Directory() {}
|
private Directory() {}
|
||||||
|
|
||||||
@ -90,6 +91,20 @@ final class PSDEXIF1Data extends PSDImageResource {
|
|||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Entry get(int pTag) {
|
||||||
|
for (Entry entry : mEntries) {
|
||||||
|
if (entry.mTag == pTag) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<Entry> iterator() {
|
||||||
|
return mEntries.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return String.format("Directory%s", mEntries);
|
return String.format("Directory%s", mEntries);
|
||||||
@ -97,7 +112,7 @@ final class PSDEXIF1Data extends PSDImageResource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TIFF IFD Entry
|
// TIFF IFD Entry
|
||||||
private static class Entry {
|
static class Entry {
|
||||||
private static final int EXIF_IFD = 0x8769;
|
private static final int EXIF_IFD = 0x8769;
|
||||||
|
|
||||||
private final static String[] TYPE_NAMES = {
|
private final static String[] TYPE_NAMES = {
|
||||||
|
@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import org.w3c.dom.Node;
|
||||||
|
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -61,7 +64,7 @@ class PSDHeader {
|
|||||||
final short mBits;
|
final short mBits;
|
||||||
final short mMode;
|
final short mMode;
|
||||||
|
|
||||||
PSDHeader(ImageInputStream pInput) throws IOException {
|
PSDHeader(final ImageInputStream pInput) throws IOException {
|
||||||
int signature = pInput.readInt();
|
int signature = pInput.readInt();
|
||||||
if (signature != PSD.SIGNATURE_8BPS) {
|
if (signature != PSD.SIGNATURE_8BPS) {
|
||||||
throw new IIOException("Not a PSD document, expected signature \"8BPS\": \"" + PSDUtil.intToStr(signature) + "\" (0x" + Integer.toHexString(signature) + ")");
|
throw new IIOException("Not a PSD document, expected signature \"8BPS\": \"" + PSDUtil.intToStr(signature) + "\" (0x" + Integer.toHexString(signature) + ")");
|
||||||
|
@ -69,11 +69,12 @@ import java.util.List;
|
|||||||
// See http://www.adobeforums.com/webx?14@@.3bc381dc/0
|
// See http://www.adobeforums.com/webx?14@@.3bc381dc/0
|
||||||
public class PSDImageReader extends ImageReaderBase {
|
public class PSDImageReader extends ImageReaderBase {
|
||||||
private PSDHeader mHeader;
|
private PSDHeader mHeader;
|
||||||
private PSDColorData mColorData;
|
// private PSDColorData mColorData;
|
||||||
private List<PSDImageResource> mImageResources;
|
// private List<PSDImageResource> mImageResources;
|
||||||
private PSDGlobalLayerMask mGlobalLayerMask;
|
// private PSDGlobalLayerMask mGlobalLayerMask;
|
||||||
private List<PSDLayerInfo> mLayerInfo;
|
// private List<PSDLayerInfo> mLayerInfo;
|
||||||
private ICC_ColorSpace mColorSpace;
|
private ICC_ColorSpace mColorSpace;
|
||||||
|
protected PSDMetadata mMetadata;
|
||||||
|
|
||||||
protected PSDImageReader(final ImageReaderSpi pOriginatingProvider) {
|
protected PSDImageReader(final ImageReaderSpi pOriginatingProvider) {
|
||||||
super(pOriginatingProvider);
|
super(pOriginatingProvider);
|
||||||
@ -81,8 +82,9 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
protected void resetMembers() {
|
protected void resetMembers() {
|
||||||
mHeader = null;
|
mHeader = null;
|
||||||
mColorData = null;
|
// mColorData = null;
|
||||||
mImageResources = null;
|
// mImageResources = null;
|
||||||
|
mMetadata = null;
|
||||||
mColorSpace = null;
|
mColorSpace = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
case PSD.COLOR_MODE_INDEXED:
|
case PSD.COLOR_MODE_INDEXED:
|
||||||
// TODO: 16 bit indexed?! Does it exist?
|
// TODO: 16 bit indexed?! Does it exist?
|
||||||
if (mHeader.mChannels == 1 && mHeader.mBits == 8) {
|
if (mHeader.mChannels == 1 && mHeader.mBits == 8) {
|
||||||
return IndexedImageTypeSpecifier.createFromIndexColorModel(mColorData.getIndexColorModel());
|
return IndexedImageTypeSpecifier.createFromIndexColorModel(mMetadata.mColorData.getIndexColorModel());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new IIOException(
|
throw new IIOException(
|
||||||
@ -264,7 +266,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
if (mColorSpace == null) {
|
if (mColorSpace == null) {
|
||||||
ICC_Profile profile = null;
|
ICC_Profile profile = null;
|
||||||
for (PSDImageResource resource : mImageResources) {
|
for (PSDImageResource resource : mMetadata.mImageResources) {
|
||||||
if (resource instanceof ICCProfile) {
|
if (resource instanceof ICCProfile) {
|
||||||
profile = ((ICCProfile) resource).getProfile();
|
profile = ((ICCProfile) resource).getProfile();
|
||||||
break;
|
break;
|
||||||
@ -333,6 +335,8 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
int[] byteCounts = null;
|
int[] byteCounts = null;
|
||||||
int compression = mImageInput.readShort();
|
int compression = mImageInput.readShort();
|
||||||
|
// TODO: Need to make sure compression is set in metadata, even without reading the image data!
|
||||||
|
mMetadata.mCompression = compression;
|
||||||
|
|
||||||
switch (compression) {
|
switch (compression) {
|
||||||
case PSD.COMPRESSION_NONE:
|
case PSD.COMPRESSION_NONE:
|
||||||
@ -346,7 +350,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
break;
|
break;
|
||||||
case PSD.COMPRESSION_ZIP:
|
case PSD.COMPRESSION_ZIP:
|
||||||
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here..
|
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here..
|
||||||
case PSD.COMPRESSION_ZIP_PREDICTON:
|
case PSD.COMPRESSION_ZIP_PREDICTION:
|
||||||
// TODO: Need to find out if the normal java.util.zip can handle this...
|
// TODO: Need to find out if the normal java.util.zip can handle this...
|
||||||
// Could be same as PNG prediction? Read up...
|
// Could be same as PNG prediction? Read up...
|
||||||
throw new IIOException("ZIP compression not supported yet");
|
throw new IIOException("ZIP compression not supported yet");
|
||||||
@ -693,6 +697,9 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
if (mHeader == null) {
|
if (mHeader == null) {
|
||||||
mHeader = new PSDHeader(mImageInput);
|
mHeader = new PSDHeader(mImageInput);
|
||||||
|
|
||||||
|
mMetadata = new PSDMetadata();
|
||||||
|
mMetadata.mHeader = mHeader;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Contains the required data to define the color mode.
|
Contains the required data to define the color mode.
|
||||||
|
|
||||||
@ -705,7 +712,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
around as a black box for use when saving the file.
|
around as a black box for use when saving the file.
|
||||||
*/
|
*/
|
||||||
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
||||||
mColorData = new PSDColorData(mImageInput);
|
mMetadata.mColorData = new PSDColorData(mImageInput);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// TODO: We need to store the duotone spec if we decide to create a writer...
|
// TODO: We need to store the duotone spec if we decide to create a writer...
|
||||||
@ -729,14 +736,14 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
long length = mImageInput.readUnsignedInt();
|
long length = mImageInput.readUnsignedInt();
|
||||||
|
|
||||||
if (pParseData && length > 0) {
|
if (pParseData && length > 0) {
|
||||||
if (mImageResources == null) {
|
if (mMetadata.mImageResources == null) {
|
||||||
mImageResources = new ArrayList<PSDImageResource>();
|
mMetadata.mImageResources = new ArrayList<PSDImageResource>();
|
||||||
long expectedEnd = mImageInput.getStreamPosition() + length;
|
long expectedEnd = mImageInput.getStreamPosition() + length;
|
||||||
|
|
||||||
while (mImageInput.getStreamPosition() < expectedEnd) {
|
while (mImageInput.getStreamPosition() < expectedEnd) {
|
||||||
// TODO: Have PSDImageResources defer actual parsing? (Just store stream offsets)
|
// TODO: Have PSDImageResources defer actual parsing? (Just store stream offsets)
|
||||||
PSDImageResource resource = PSDImageResource.read(mImageInput);
|
PSDImageResource resource = PSDImageResource.read(mImageInput);
|
||||||
mImageResources.add(resource);
|
mMetadata.mImageResources.add(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mImageInput.getStreamPosition() != expectedEnd) {
|
if (mImageInput.getStreamPosition() != expectedEnd) {
|
||||||
@ -770,7 +777,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
for (int i = 0; i < layerInfos.length; i++) {
|
for (int i = 0; i < layerInfos.length; i++) {
|
||||||
layerInfos[i] = new PSDLayerInfo(mImageInput);
|
layerInfos[i] = new PSDLayerInfo(mImageInput);
|
||||||
}
|
}
|
||||||
mLayerInfo = Arrays.asList(layerInfos);
|
mMetadata.mLayerInfo = Arrays.asList(layerInfos);
|
||||||
|
|
||||||
// TODO: Clean-up
|
// TODO: Clean-up
|
||||||
mImageInput.mark();
|
mImageInput.mark();
|
||||||
@ -783,9 +790,9 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
BufferedImage layer = readLayerData(layerInfo, raw, imageType);
|
BufferedImage layer = readLayerData(layerInfo, raw, imageType);
|
||||||
|
|
||||||
// TODO: Don't show! Store in meta data somehow...
|
// TODO: Don't show! Store in meta data somehow...
|
||||||
if (layer != null) {
|
// if (layer != null) {
|
||||||
showIt(layer, layerInfo.mLayerName + " " + layerInfo.mBlendMode.toString());
|
// showIt(layer, layerInfo.mLayerName + " " + layerInfo.mBlendMode.toString());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
long read = mImageInput.getStreamPosition() - pos;
|
long read = mImageInput.getStreamPosition() - pos;
|
||||||
@ -799,7 +806,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
long layerMaskInfoLength = mImageInput.readUnsignedInt();
|
long layerMaskInfoLength = mImageInput.readUnsignedInt();
|
||||||
// System.out.println("GlobalLayerMaskInfo length: " + layerMaskInfoLength);
|
// System.out.println("GlobalLayerMaskInfo length: " + layerMaskInfoLength);
|
||||||
if (layerMaskInfoLength > 0) {
|
if (layerMaskInfoLength > 0) {
|
||||||
mGlobalLayerMask = new PSDGlobalLayerMask(mImageInput);
|
mMetadata.mGlobalLayerMask = new PSDGlobalLayerMask(mImageInput);
|
||||||
// System.out.println("mGlobalLayerMask: " + mGlobalLayerMask);
|
// System.out.println("mGlobalLayerMask: " + mGlobalLayerMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,7 +884,7 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case PSD.COMPRESSION_ZIP:
|
case PSD.COMPRESSION_ZIP:
|
||||||
case PSD.COMPRESSION_ZIP_PREDICTON:
|
case PSD.COMPRESSION_ZIP_PREDICTION:
|
||||||
default:
|
default:
|
||||||
// Explicitly skipped above
|
// Explicitly skipped above
|
||||||
throw new AssertionError(String.format("Unsupported layer data. Compression: %d", compression));
|
throw new AssertionError(String.format("Unsupported layer data. Compression: %d", compression));
|
||||||
@ -985,16 +992,19 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
readImageResources(true);
|
readImageResources(true);
|
||||||
readLayerAndMaskInfo(true);
|
readLayerAndMaskInfo(true);
|
||||||
|
|
||||||
PSDMetadata metadata = new PSDMetadata();
|
// TODO: Need to make sure compression is set in metadata, even without reading the image data!
|
||||||
metadata.mHeader = mHeader;
|
mMetadata.mCompression = mImageInput.readShort();
|
||||||
metadata.mColorData = mColorData;
|
|
||||||
metadata.mImageResources = mImageResources;
|
// mMetadata.mHeader = mHeader;
|
||||||
return metadata;
|
// mMetadata.mColorData = mColorData;
|
||||||
|
// mMetadata.mImageResources = mImageResources;
|
||||||
|
|
||||||
|
return mMetadata; // TODO: clone if we change to mutable metadata
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IIOMetadata getImageMetadata(final int imageIndex, final String formatName, final Set<String> nodeNames) throws IOException {
|
public IIOMetadata getImageMetadata(final int imageIndex, final String formatName, final Set<String> nodeNames) throws IOException {
|
||||||
// TODO: This might make sense, as there's loads of meta data in the file
|
// TODO: It might make sense to overload this, as there's loads of meta data in the file
|
||||||
return super.getImageMetadata(imageIndex, formatName, nodeNames);
|
return super.getImageMetadata(imageIndex, formatName, nodeNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,14 +1021,14 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
|
|
||||||
List<PSDThumbnail> thumbnails = null;
|
List<PSDThumbnail> thumbnails = null;
|
||||||
|
|
||||||
if (mImageResources == null) {
|
if (mMetadata.mImageResources == null) {
|
||||||
// TODO: Need flag here, to specify what resources to read...
|
// TODO: Need flag here, to specify what resources to read...
|
||||||
readImageResources(true);
|
readImageResources(true);
|
||||||
// TODO: Skip this, requires storing some stream offsets
|
// TODO: Skip this, requires storing some stream offsets
|
||||||
readLayerAndMaskInfo(false);
|
readLayerAndMaskInfo(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (PSDImageResource resource : mImageResources) {
|
for (PSDImageResource resource : mMetadata.mImageResources) {
|
||||||
if (resource instanceof PSDThumbnail) {
|
if (resource instanceof PSDThumbnail) {
|
||||||
if (thumbnails == null) {
|
if (thumbnails == null) {
|
||||||
thumbnails = new ArrayList<PSDThumbnail>();
|
thumbnails = new ArrayList<PSDThumbnail>();
|
||||||
@ -1120,15 +1130,25 @@ public class PSDImageReader extends ImageReaderBase {
|
|||||||
// System.out.println("imageReader.mHeader: " + imageReader.mHeader);
|
// System.out.println("imageReader.mHeader: " + imageReader.mHeader);
|
||||||
|
|
||||||
imageReader.readImageResources(true);
|
imageReader.readImageResources(true);
|
||||||
System.out.println("imageReader.mImageResources: " + imageReader.mImageResources);
|
System.out.println("imageReader.mImageResources: " + imageReader.mMetadata.mImageResources);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
imageReader.readLayerAndMaskInfo(true);
|
imageReader.readLayerAndMaskInfo(true);
|
||||||
System.out.println("imageReader.mLayerInfo: " + imageReader.mLayerInfo);
|
System.out.println("imageReader.mLayerInfo: " + imageReader.mMetadata.mLayerInfo);
|
||||||
// System.out.println("imageReader.mGlobalLayerMask: " + imageReader.mGlobalLayerMask);
|
// System.out.println("imageReader.mGlobalLayerMask: " + imageReader.mGlobalLayerMask);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
IIOMetadata metadata = imageReader.getImageMetadata(0);
|
IIOMetadata metadata = imageReader.getImageMetadata(0);
|
||||||
Node node = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
Node node;
|
||||||
XMLSerializer serializer = new XMLSerializer(System.out, System.getProperty("file.encoding"));
|
XMLSerializer serializer;
|
||||||
|
|
||||||
|
node = metadata.getAsTree(IIOMetadataFormatImpl.standardMetadataFormatName);
|
||||||
|
serializer = new XMLSerializer(System.out, System.getProperty("file.encoding"));
|
||||||
|
serializer.serialize(node, true);
|
||||||
|
System.out.println();
|
||||||
|
|
||||||
|
node = metadata.getAsTree(PSDMetadata.NATIVE_METADATA_FORMAT_NAME);
|
||||||
|
serializer = new XMLSerializer(System.out, System.getProperty("file.encoding"));
|
||||||
serializer.serialize(node, true);
|
serializer.serialize(node, true);
|
||||||
|
|
||||||
if (imageReader.hasThumbnails(0)) {
|
if (imageReader.hasThumbnails(0)) {
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
|
|
||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import javax.imageio.IIOException;
|
import javax.imageio.IIOException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -50,6 +52,12 @@ class PSDImageResource {
|
|||||||
|
|
||||||
mName = PSDUtil.readPascalString(pInput);
|
mName = PSDUtil.readPascalString(pInput);
|
||||||
|
|
||||||
|
// Skip pad
|
||||||
|
int nameSize = mName.length() + 1;
|
||||||
|
if (nameSize % 2 != 0) {
|
||||||
|
pInput.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
mSize = pInput.readUnsignedInt();
|
mSize = pInput.readUnsignedInt();
|
||||||
readData(pInput);
|
readData(pInput);
|
||||||
|
|
||||||
@ -84,7 +92,10 @@ class PSDImageResource {
|
|||||||
protected StringBuilder toStringBuilder() {
|
protected StringBuilder toStringBuilder() {
|
||||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||||
|
|
||||||
builder.append(resourceTypeForId(mId));
|
String fakeType = resourceTypeForId(mId);
|
||||||
|
if (fakeType != null) {
|
||||||
|
builder.append("(").append(fakeType).append(")");
|
||||||
|
}
|
||||||
|
|
||||||
builder.append("[ID: 0x");
|
builder.append("[ID: 0x");
|
||||||
builder.append(Integer.toHexString(mId));
|
builder.append(Integer.toHexString(mId));
|
||||||
@ -106,23 +117,25 @@ class PSDImageResource {
|
|||||||
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:
|
||||||
|
case PSD.RES_VERSION_INFO:
|
||||||
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_FLAGS_INFORMATION:
|
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
||||||
return "";
|
return null;
|
||||||
default:
|
default:
|
||||||
try {
|
try {
|
||||||
for (Field field : PSD.class.getDeclaredFields()) {
|
for (Field field : PSD.class.getDeclaredFields()) {
|
||||||
if (field.getName().startsWith("RES_") && field.getInt(null) == pId) {
|
if (field.getName().startsWith("RES_") && field.getInt(null) == pId) {
|
||||||
return "(" + field.getName().substring(4) + ")";
|
String name = field.getName().substring(4);
|
||||||
|
return StringUtil.lispToCamel(name.replace("_", "-").toLowerCase(), true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IllegalAccessException ignore) {
|
catch (IllegalAccessException ignore) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return "(unknown resource)";
|
return "unknown resource";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,6 +162,8 @@ class PSDImageResource {
|
|||||||
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_VERSION_INFO:
|
||||||
|
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:
|
||||||
|
@ -98,14 +98,12 @@ class PSDLayerInfo {
|
|||||||
mLayerName = PSDUtil.readPascalString(pInput);
|
mLayerName = PSDUtil.readPascalString(pInput);
|
||||||
|
|
||||||
int layerNameSize = mLayerName.length() + 1;
|
int layerNameSize = mLayerName.length() + 1;
|
||||||
// readPascalString has already read pad byte for word alignment
|
|
||||||
if (layerNameSize % 2 != 0) {
|
// Skip pad bytes for long word alignment
|
||||||
layerNameSize++;
|
|
||||||
}
|
|
||||||
// Skip two more pad bytes if needed
|
|
||||||
if (layerNameSize % 4 != 0) {
|
if (layerNameSize % 4 != 0) {
|
||||||
pInput.skipBytes(2);
|
int skip = layerNameSize % 4;
|
||||||
layerNameSize += 2;
|
pInput.skipBytes(skip);
|
||||||
|
layerNameSize += skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: There's some data skipped here...
|
// TODO: There's some data skipped here...
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
import com.twelvemonkeys.lang.StringUtil;
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
import com.twelvemonkeys.util.FilterIterator;
|
||||||
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
|
import org.xml.sax.InputSource;
|
||||||
|
|
||||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||||
import javax.imageio.metadata.IIOMetadata;
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||||
import javax.imageio.metadata.IIOMetadataNode;
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
|
import javax.xml.parsers.DocumentBuilder;
|
||||||
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import java.awt.image.IndexColorModel;
|
import java.awt.image.IndexColorModel;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,16 +26,28 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
||||||
|
|
||||||
static final String NATIVE_METADATA_FORMAT_NAME = "com_twelvemonkeys_imageio_psd_1.0";
|
// TODO: Decide on image/stream metadata...
|
||||||
|
static final String NATIVE_METADATA_FORMAT_NAME = "com_twelvemonkeys_imageio_psd_image_1.0";
|
||||||
static final String NATIVE_METADATA_FORMAT_CLASS_NAME = "com.twelvemonkeys.imageio.plugins.psd.PSDMetadataFormat";
|
static final String NATIVE_METADATA_FORMAT_CLASS_NAME = "com.twelvemonkeys.imageio.plugins.psd.PSDMetadataFormat";
|
||||||
|
|
||||||
// TODO: Move fields from PSDImageReader (header, color map, resources, etc) here
|
|
||||||
PSDHeader mHeader;
|
PSDHeader mHeader;
|
||||||
PSDColorData mColorData;
|
PSDColorData mColorData;
|
||||||
|
int mCompression = -1;
|
||||||
List<PSDImageResource> mImageResources;
|
List<PSDImageResource> mImageResources;
|
||||||
PSDGlobalLayerMask mGlobalLayerMask;
|
PSDGlobalLayerMask mGlobalLayerMask;
|
||||||
List<PSDLayerInfo> mLayerInfo;
|
List<PSDLayerInfo> mLayerInfo;
|
||||||
|
|
||||||
|
static final String[] COLOR_MODES = {
|
||||||
|
"MONOCHROME", "GRAYSCALE", "INDEXED", "RGB", "CMYK", null, null, "MULTICHANNEL", "DUOTONE", "LAB"
|
||||||
|
};
|
||||||
|
|
||||||
|
static final String[] DISPLAY_INFO_CS = {
|
||||||
|
"RGB", "HSB", "CMYK", "PANTONE", "FOCOLTONE", "TRUMATCH", "TOYO", "LAB", "GRAYSCALE", null, "HKS", "DIC",
|
||||||
|
null, // ... (until index 2999),
|
||||||
|
"ANPA"
|
||||||
|
};
|
||||||
|
static final String[] DISPLAY_INFO_KINDS = {"selected", "protected"};
|
||||||
|
|
||||||
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);
|
||||||
@ -119,8 +136,112 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Native format support
|
||||||
|
|
||||||
private Node getNativeTree() {
|
private Node getNativeTree() {
|
||||||
throw new UnsupportedOperationException("getNativeTree");
|
IIOMetadataNode root = new IIOMetadataNode(NATIVE_METADATA_FORMAT_NAME);
|
||||||
|
|
||||||
|
root.appendChild(createHeaderNode());
|
||||||
|
|
||||||
|
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
||||||
|
root.appendChild(createPaletteNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mImageResources != null && !mImageResources.isEmpty()) {
|
||||||
|
root.appendChild(createImageResourcesNode());
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createHeaderNode() {
|
||||||
|
IIOMetadataNode header = new IIOMetadataNode("PSDHeader");
|
||||||
|
|
||||||
|
header.setAttribute("version", "1");
|
||||||
|
header.setAttribute("channels", Integer.toString(mHeader.mChannels));
|
||||||
|
header.setAttribute("height", Integer.toString(mHeader.mHeight));
|
||||||
|
header.setAttribute("width", Integer.toString(mHeader.mWidth));
|
||||||
|
header.setAttribute("bits", Integer.toString(mHeader.mBits));
|
||||||
|
header.setAttribute("mode", COLOR_MODES[mHeader.mMode]);
|
||||||
|
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Node createImageResourcesNode() {
|
||||||
|
IIOMetadataNode resource = new IIOMetadataNode("ImageResources");
|
||||||
|
IIOMetadataNode node;
|
||||||
|
|
||||||
|
for (PSDImageResource imageResource : mImageResources) {
|
||||||
|
// 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..
|
||||||
|
|
||||||
|
if (imageResource instanceof PSDAlphaChannelInfo) {
|
||||||
|
PSDAlphaChannelInfo alphaChannelInfo = (PSDAlphaChannelInfo) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("AlphaChannelInfo");
|
||||||
|
|
||||||
|
for (String name : alphaChannelInfo.mNames) {
|
||||||
|
IIOMetadataNode nameNode = new IIOMetadataNode("Name");
|
||||||
|
nameNode.setAttribute("value", name);
|
||||||
|
node.appendChild(nameNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.appendChild(node);
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDDisplayInfo) {
|
||||||
|
PSDDisplayInfo displayInfo = (PSDDisplayInfo) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("DisplayInfo");
|
||||||
|
node.setAttribute("colorSpace", DISPLAY_INFO_CS[displayInfo.mColorSpace]);
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
for (short color : displayInfo.mColors) {
|
||||||
|
if (builder.length() > 0) {
|
||||||
|
builder.append(" ");
|
||||||
|
}
|
||||||
|
builder.append(Integer.toString(color));
|
||||||
|
}
|
||||||
|
|
||||||
|
node.setAttribute("colors", builder.toString());
|
||||||
|
node.setAttribute("opacity", Integer.toString(displayInfo.mOpacity));
|
||||||
|
node.setAttribute("kind", DISPLAY_INFO_KINDS[displayInfo.mKind]);
|
||||||
|
|
||||||
|
resource.appendChild(node);
|
||||||
|
}
|
||||||
|
else if (imageResource instanceof PSDXMPData) {
|
||||||
|
// TODO: Revise/rethink this...
|
||||||
|
PSDXMPData xmp = (PSDXMPData) imageResource;
|
||||||
|
|
||||||
|
node = new IIOMetadataNode("XMPData");
|
||||||
|
|
||||||
|
try {
|
||||||
|
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||||||
|
DocumentBuilder builder = factory.newDocumentBuilder();
|
||||||
|
Document document = builder.parse(new InputSource(xmp.getData()));
|
||||||
|
|
||||||
|
// Set the entire XMP document as user data
|
||||||
|
node.setUserObject(document);
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
resource.appendChild(node);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Generic resource..
|
||||||
|
node = new IIOMetadataNode(PSDImageResource.resourceTypeForId(imageResource.mId));
|
||||||
|
|
||||||
|
resource.appendChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: More resources
|
||||||
|
|
||||||
|
node.setAttribute("resourceId", Integer.toHexString(imageResource.mId));
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Standard format support
|
/// Standard format support
|
||||||
@ -135,7 +256,7 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
switch (mHeader.mMode) {
|
switch (mHeader.mMode) {
|
||||||
case PSD.COLOR_MODE_MONOCHROME:
|
case PSD.COLOR_MODE_MONOCHROME:
|
||||||
case PSD.COLOR_MODE_GRAYSCALE:
|
case PSD.COLOR_MODE_GRAYSCALE:
|
||||||
case PSD.COLOR_MODE_DUOTONE: // Rationale is spec says treat as gray...
|
case PSD.COLOR_MODE_DUOTONE: // Rationale: Spec says treat as gray...
|
||||||
cs = "GRAY";
|
cs = "GRAY";
|
||||||
break;
|
break;
|
||||||
case PSD.COLOR_MODE_RGB:
|
case PSD.COLOR_MODE_RGB:
|
||||||
@ -146,8 +267,7 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
cs = "CMYK";
|
cs = "CMYK";
|
||||||
break;
|
break;
|
||||||
case PSD.COLOR_MODE_MULTICHANNEL:
|
case PSD.COLOR_MODE_MULTICHANNEL:
|
||||||
// TODO: FixMe
|
cs = getMultiChannelCS(mHeader.mChannels);
|
||||||
cs = "???";
|
|
||||||
break;
|
break;
|
||||||
case PSD.COLOR_MODE_LAB:
|
case PSD.COLOR_MODE_LAB:
|
||||||
cs = "Lab";
|
cs = "Lab";
|
||||||
@ -158,42 +278,22 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
node.setAttribute("name", cs);
|
node.setAttribute("name", cs);
|
||||||
chroma_node.appendChild(node);
|
chroma_node.appendChild(node);
|
||||||
|
|
||||||
// TODO: Channels might be 5 for RGB + A + Mask...
|
// TODO: Channels might be 5 for RGB + A + Mask... Probably not correct
|
||||||
node = new IIOMetadataNode("NumChannels");
|
node = new IIOMetadataNode("NumChannels");
|
||||||
node.setAttribute("value", Integer.toString(mHeader.mChannels));
|
node.setAttribute("value", Integer.toString(mHeader.mChannels));
|
||||||
chroma_node.appendChild(node);
|
chroma_node.appendChild(node);
|
||||||
|
|
||||||
// if (gAMA_present) {
|
|
||||||
// node = new IIOMetadataNode("Gamma");
|
|
||||||
// node.setAttribute("value", Float.toString(gAMA_gamma*1.0e-5F));
|
|
||||||
// chroma_node.appendChild(node);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// TODO: Check if this is correct with bitmap (monchrome)
|
// TODO: Check if this is correct with bitmap (monchrome)
|
||||||
node = new IIOMetadataNode("BlackIsZero");
|
node = new IIOMetadataNode("BlackIsZero");
|
||||||
node.setAttribute("value", "true");
|
node.setAttribute("value", "true");
|
||||||
chroma_node.appendChild(node);
|
chroma_node.appendChild(node);
|
||||||
|
|
||||||
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
||||||
node = new IIOMetadataNode("Palette");
|
node = createPaletteNode();
|
||||||
|
|
||||||
IndexColorModel cm = mColorData.getIndexColorModel();
|
|
||||||
for (int i = 0; i < cm.getMapSize(); i++) {
|
|
||||||
IIOMetadataNode entry =
|
|
||||||
new IIOMetadataNode("PaletteEntry");
|
|
||||||
entry.setAttribute("index", Integer.toString(i));
|
|
||||||
entry.setAttribute("red",
|
|
||||||
Integer.toString(cm.getRed(i)));
|
|
||||||
entry.setAttribute("green",
|
|
||||||
Integer.toString(cm.getGreen(i)));
|
|
||||||
entry.setAttribute("blue",
|
|
||||||
Integer.toString(cm.getBlue(i)));
|
|
||||||
|
|
||||||
node.appendChild(entry);
|
|
||||||
}
|
|
||||||
chroma_node.appendChild(node);
|
chroma_node.appendChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Hardcode background color to white?
|
||||||
// if (bKGD_present) {
|
// if (bKGD_present) {
|
||||||
// if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
|
// if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
|
||||||
// node = new IIOMetadataNode("BackgroundIndex");
|
// node = new IIOMetadataNode("BackgroundIndex");
|
||||||
@ -219,22 +319,59 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
return chroma_node;
|
return chroma_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IIOMetadataNode createPaletteNode() {
|
||||||
|
IIOMetadataNode node = new IIOMetadataNode("Palette");
|
||||||
|
IndexColorModel cm = mColorData.getIndexColorModel();
|
||||||
|
|
||||||
|
for (int i = 0; i < cm.getMapSize(); i++) {
|
||||||
|
IIOMetadataNode entry = new IIOMetadataNode("PaletteEntry");
|
||||||
|
entry.setAttribute("index", Integer.toString(i));
|
||||||
|
entry.setAttribute("red", Integer.toString(cm.getRed(i)));
|
||||||
|
entry.setAttribute("green", Integer.toString(cm.getGreen(i)));
|
||||||
|
entry.setAttribute("blue", Integer.toString(cm.getBlue(i)));
|
||||||
|
|
||||||
|
node.appendChild(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getMultiChannelCS(short pChannels) {
|
||||||
|
if (pChannels < 16) {
|
||||||
|
return Integer.toHexString(pChannels) + "CLR";
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new UnsupportedOperationException("Standard meta data format does not support more than 15 channels");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardCompressionNode() {
|
protected IIOMetadataNode getStandardCompressionNode() {
|
||||||
IIOMetadataNode compression_node = new IIOMetadataNode("Compression");
|
IIOMetadataNode compression_node = new IIOMetadataNode("Compression");
|
||||||
IIOMetadataNode node; // scratch node
|
IIOMetadataNode node; // scratch node
|
||||||
|
|
||||||
node = new IIOMetadataNode("CompressionTypeName");
|
node = new IIOMetadataNode("CompressionTypeName");
|
||||||
// TODO: Only if set...
|
String compression;
|
||||||
node.setAttribute("value", "PackBits");
|
switch (mCompression) {
|
||||||
|
case PSD.COMPRESSION_NONE:
|
||||||
|
compression = "none";
|
||||||
|
break;
|
||||||
|
case PSD.COMPRESSION_RLE:
|
||||||
|
compression = "packbits";
|
||||||
|
break;
|
||||||
|
case PSD.COMPRESSION_ZIP:
|
||||||
|
case PSD.COMPRESSION_ZIP_PREDICTION:
|
||||||
|
compression = "zip";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new AssertionError("Unreachable");
|
||||||
|
}
|
||||||
|
node.setAttribute("value", compression);
|
||||||
compression_node.appendChild(node);
|
compression_node.appendChild(node);
|
||||||
|
|
||||||
node = new IIOMetadataNode("Lossless");
|
node = new IIOMetadataNode("Lossless");
|
||||||
node.setAttribute("value", "true");
|
node.setAttribute("value", "true");
|
||||||
compression_node.appendChild(node);
|
compression_node.appendChild(node);
|
||||||
|
|
||||||
// compression_node.appendChild(node);
|
|
||||||
|
|
||||||
return compression_node;
|
return compression_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,9 +417,9 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
node.setAttribute("value", "Normal");
|
node.setAttribute("value", "Normal");
|
||||||
dimension_node.appendChild(node);
|
dimension_node.appendChild(node);
|
||||||
|
|
||||||
List<PSDResolutionInfo> resolutionInfos = getResources(PSDResolutionInfo.class);
|
Iterator<PSDResolutionInfo> resolutionInfos = getResources(PSDResolutionInfo.class);
|
||||||
if (!resolutionInfos.isEmpty()) {
|
if (!resolutionInfos.hasNext()) {
|
||||||
PSDResolutionInfo resolutionInfo = resolutionInfos.get(0);
|
PSDResolutionInfo resolutionInfo = resolutionInfos.next();
|
||||||
|
|
||||||
node = new IIOMetadataNode("HorizontalPixelSize");
|
node = new IIOMetadataNode("HorizontalPixelSize");
|
||||||
node.setAttribute("value", Float.toString(asMM(resolutionInfo.mHResUnit, resolutionInfo.mHRes)));
|
node.setAttribute("value", Float.toString(asMM(resolutionInfo.mHResUnit, resolutionInfo.mHRes)));
|
||||||
@ -330,31 +467,49 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardDocumentNode() {
|
protected IIOMetadataNode getStandardDocumentNode() {
|
||||||
// TODO: PSDVersionInfo
|
IIOMetadataNode document_node = new IIOMetadataNode("Document");
|
||||||
|
IIOMetadataNode node; // scratch node
|
||||||
|
|
||||||
// if (!tIME_present) {
|
node = new IIOMetadataNode("FormatVersion");
|
||||||
// return null;
|
node.setAttribute("value", "1"); // PSD format version is always 1
|
||||||
// }
|
document_node.appendChild(node);
|
||||||
//
|
|
||||||
// IIOMetadataNode document_node = new IIOMetadataNode("Document");
|
// Get EXIF data if present
|
||||||
// IIOMetadataNode node = null; // scratch node
|
Iterator<PSDEXIF1Data> exif = getResources(PSDEXIF1Data.class);
|
||||||
//
|
if (exif.hasNext()) {
|
||||||
// node = new IIOMetadataNode("ImageModificationTime");
|
PSDEXIF1Data data = exif.next();
|
||||||
// node.setAttribute("year", Integer.toString(tIME_year));
|
|
||||||
// node.setAttribute("month", Integer.toString(tIME_month));
|
// Get the EXIF DateTime (aka ModifyDate) tag if present
|
||||||
// node.setAttribute("day", Integer.toString(tIME_day));
|
PSDEXIF1Data.Entry dateTime = data.mDirectory.get(0x0132); // TODO: Constant
|
||||||
// node.setAttribute("hour", Integer.toString(tIME_hour));
|
if (dateTime != null) {
|
||||||
// node.setAttribute("minute", Integer.toString(tIME_minute));
|
node = new IIOMetadataNode("ImageModificationTime");
|
||||||
// node.setAttribute("second", Integer.toString(tIME_second));
|
// Format: "YYYY:MM:DD hh:mm:ss" (with quotes! :-P)
|
||||||
// document_node.appendChild(node);
|
String value = dateTime.getValueAsString();
|
||||||
//
|
|
||||||
// return document_node;
|
node.setAttribute("year", value.substring(1, 5));
|
||||||
return null;
|
node.setAttribute("month", value.substring(6, 8));
|
||||||
|
node.setAttribute("day", value.substring(9, 11));
|
||||||
|
node.setAttribute("hour", value.substring(12, 14));
|
||||||
|
node.setAttribute("minute", value.substring(15, 17));
|
||||||
|
node.setAttribute("second", value.substring(18, 20));
|
||||||
|
|
||||||
|
document_node.appendChild(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return document_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardTextNode() {
|
protected IIOMetadataNode getStandardTextNode() {
|
||||||
// TODO: CaptionDigest?, EXIF, XMP
|
// TODO: CaptionDigest?, EXIF, XMP
|
||||||
|
|
||||||
|
Iterator<PSDImageResource> textResources = getResources(PSDEXIF1Data.class, PSDXMPData.class);
|
||||||
|
|
||||||
|
while (textResources.hasNext()) {
|
||||||
|
PSDImageResource textResource = textResources.next();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// int numEntries = tEXt_keyword.size() +
|
// int numEntries = tEXt_keyword.size() +
|
||||||
// iTXt_keyword.size() + zTXt_keyword.size();
|
// iTXt_keyword.size() + zTXt_keyword.size();
|
||||||
@ -411,8 +566,7 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected IIOMetadataNode getStandardTransparencyNode() {
|
protected IIOMetadataNode getStandardTransparencyNode() {
|
||||||
IIOMetadataNode transparency_node =
|
IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency");
|
||||||
new IIOMetadataNode("Transparency");
|
|
||||||
IIOMetadataNode node; // scratch node
|
IIOMetadataNode node; // scratch node
|
||||||
|
|
||||||
node = new IIOMetadataNode("Alpha");
|
node = new IIOMetadataNode("Alpha");
|
||||||
@ -427,20 +581,31 @@ public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
|||||||
mHeader.mMode == PSD.COLOR_MODE_CMYK & mHeader.mChannels >= 5;
|
mHeader.mMode == PSD.COLOR_MODE_CMYK & mHeader.mChannels >= 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace with filter iterator?
|
<T extends PSDImageResource> Iterator<T> getResources(final Class<T> pResourceType) {
|
||||||
<T extends PSDImageResource> List<T> getResources(final Class<T> pResourceType) {
|
// NOTE: The cast here is wrong, strictly speaking, but it does not matter...
|
||||||
List<T> filtered = null;
|
@SuppressWarnings({"unchecked"})
|
||||||
|
Iterator<T> iterator = (Iterator<T>) mImageResources.iterator();
|
||||||
|
|
||||||
for (PSDImageResource resource : mImageResources) {
|
return new FilterIterator<T>(iterator, new FilterIterator.Filter<T>() {
|
||||||
if (pResourceType.isInstance(resource)) {
|
public boolean accept(final T pElement) {
|
||||||
if (filtered == null) {
|
return pResourceType.isInstance(pElement);
|
||||||
filtered = new ArrayList<T>();
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator<PSDImageResource> getResources(final Class<? extends PSDImageResource>... pResourceTypes) {
|
||||||
|
Iterator<PSDImageResource> iterator = mImageResources.iterator();
|
||||||
|
|
||||||
|
return new FilterIterator<PSDImageResource>(iterator, new FilterIterator.Filter<PSDImageResource>() {
|
||||||
|
public boolean accept(final PSDImageResource pElement) {
|
||||||
|
for (Class<?> type : pResourceTypes) {
|
||||||
|
if (type.isInstance(pElement)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
filtered.add(pResourceType.cast(resource));
|
return false;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
return filtered;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.twelvemonkeys.imageio.plugins.psd;
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
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.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -33,7 +35,7 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
addElement("PSDHeader", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_EMPTY);
|
addElement("PSDHeader", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_EMPTY);
|
||||||
|
|
||||||
// TODO: Do the first two make sense?
|
// TODO: Do the first two make sense?
|
||||||
addAttribute("PSDHeader", "signature", DATATYPE_STRING, false, "8BPS", Arrays.asList("8BPS"));
|
// addAttribute("PSDHeader", "signature", DATATYPE_STRING, false, "8BPS", Arrays.asList("8BPS"));
|
||||||
addAttribute("PSDHeader", "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("PSDHeader", "channels", DATATYPE_INTEGER, true, null, "1", "24", true, true);
|
||||||
@ -42,16 +44,8 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
// columns?
|
// columns?
|
||||||
addAttribute("PSDHeader", "width", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
addAttribute("PSDHeader", "width", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
||||||
addAttribute("PSDHeader", "bits", DATATYPE_INTEGER, true, null, Arrays.asList("1", "8", "16"));
|
addAttribute("PSDHeader", "bits", DATATYPE_INTEGER, true, null, Arrays.asList("1", "8", "16"));
|
||||||
addAttribute("PSDHeader", "mode", DATATYPE_INTEGER, true, null, Arrays.asList(
|
// TODO: Consider using more readable names?!
|
||||||
String.valueOf(PSD.COLOR_MODE_MONOCHROME),
|
addAttribute("PSDHeader", "mode", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.COLOR_MODES));
|
||||||
String.valueOf(PSD.COLOR_MODE_GRAYSCALE),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_INDEXED),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_RGB),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_CMYK),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_MULTICHANNEL),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_DUOTONE),
|
|
||||||
String.valueOf(PSD.COLOR_MODE_LAB)
|
|
||||||
));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Contains the required data to define the color mode.
|
Contains the required data to define the color mode.
|
||||||
@ -69,7 +63,7 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
// NOTE: Palette, PaletteEntry naming taken from the standard format, native PSD naming is ColorModeData
|
// NOTE: Palette, PaletteEntry naming taken from the standard format, native PSD naming is ColorModeData
|
||||||
// NOTE: PSD stores these as 256 Red, 256 Green, 256 Blue.. Should we do the same in the meta data?
|
// NOTE: PSD stores these as 256 Red, 256 Green, 256 Blue.. Should we do the same in the meta data?
|
||||||
addElement("Palette", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, 256, 256); // 768 = 256 * 3
|
addElement("Palette", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, 256, 256); // 768 = 256 * 3
|
||||||
addElement("PaletteEntry", "PSDColorData", CHILD_POLICY_EMPTY);
|
addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY);
|
||||||
addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
addAttribute("PaletteEntry", "index", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
||||||
addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
addAttribute("PaletteEntry", "red", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
||||||
addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
addAttribute("PaletteEntry", "green", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
||||||
@ -89,15 +83,19 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
// TODO: Allow arbitrary values to be added as a generic resource...
|
// TODO: Allow arbitrary values to be added as a generic resource...
|
||||||
|
|
||||||
// root -> ImageResources -> AlphaChannelInfo
|
// root -> ImageResources -> AlphaChannelInfo
|
||||||
addElement("AlphaChannelInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
addElement("AlphaChannelInfo", "ImageResources", 0, Integer.MAX_VALUE); // The format probably does not support that many layers..
|
||||||
addAttribute("AlphaChannelInfo", "names", DATATYPE_STRING, true, 0, Integer.MAX_VALUE);
|
addElement("Name", "AlphaChannelInfo", CHILD_POLICY_EMPTY);
|
||||||
|
addAttribute("Name", "value", DATATYPE_STRING, true, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
// 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: Limit values (0-8, 10, 11, 3000)
|
||||||
addAttribute("DisplayInfo", "colorSpace", DATATYPE_INTEGER, true, null);
|
addAttribute("DisplayInfo", "colorSpace", DATATYPE_INTEGER, true, null);
|
||||||
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);
|
||||||
addAttribute("DisplayInfo", "kind", DATATYPE_INTEGER, true, null, Arrays.asList("0", "1"));
|
// TODO: Consider using human readable strings
|
||||||
|
addAttribute("DisplayInfo", "kind", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.DISPLAY_INFO_KINDS));
|
||||||
|
|
||||||
// root -> ImageResources -> EXIF1Data
|
// root -> ImageResources -> EXIF1Data
|
||||||
addElement("EXIF1Data", "ImageResources", CHILD_POLICY_ALL);
|
addElement("EXIF1Data", "ImageResources", CHILD_POLICY_ALL);
|
||||||
@ -138,6 +136,7 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
|||||||
// root -> ImageResources -> XMPData
|
// root -> ImageResources -> XMPData
|
||||||
addElement("XMPData", "ImageResources", CHILD_POLICY_CHOICE);
|
addElement("XMPData", "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);
|
||||||
|
|
||||||
// TODO: Layers
|
// TODO: Layers
|
||||||
//addElement("ChannelSourceDestinationRange", "LayerSomething", CHILD_POLICY_CHOICE);
|
//addElement("ChannelSourceDestinationRange", "LayerSomething", CHILD_POLICY_CHOICE);
|
||||||
|
@ -26,14 +26,14 @@ final class PSDPrintFlags extends PSDImageResource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
mLabels = pInput.readUnsignedByte() != 0;
|
mLabels = pInput.readBoolean();
|
||||||
mCropMasks = pInput.readUnsignedByte() != 0;
|
mCropMasks = pInput.readBoolean();
|
||||||
mColorBars = pInput.readUnsignedByte() != 0;
|
mColorBars = pInput.readBoolean();
|
||||||
mRegistrationMarks = pInput.readUnsignedByte() != 0;
|
mRegistrationMarks = pInput.readBoolean();
|
||||||
mNegative = pInput.readUnsignedByte() != 0;
|
mNegative = pInput.readBoolean();
|
||||||
mFlip = pInput.readUnsignedByte() != 0;
|
mFlip = pInput.readBoolean();
|
||||||
mInterpolate = pInput.readUnsignedByte() != 0;
|
mInterpolate = pInput.readBoolean();
|
||||||
mCaption = pInput.readUnsignedByte() != 0;
|
mCaption = pInput.readBoolean();
|
||||||
|
|
||||||
pInput.skipBytes(mSize - 8);
|
pInput.skipBytes(mSize - 8);
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ final class PSDPrintFlagsInformation extends PSDImageResource {
|
|||||||
@Override
|
@Override
|
||||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
mVersion = pInput.readUnsignedShort();
|
mVersion = pInput.readUnsignedShort();
|
||||||
mCropMasks = pInput.readUnsignedByte() != 0;
|
mCropMasks = pInput.readBoolean();
|
||||||
mField = pInput.readUnsignedByte();
|
mField = pInput.readUnsignedByte();
|
||||||
mBleedWidth = pInput.readUnsignedInt();
|
mBleedWidth = pInput.readUnsignedInt();
|
||||||
mBleedScale = pInput.readUnsignedShort();
|
mBleedScale = pInput.readUnsignedShort();
|
||||||
|
@ -37,7 +37,7 @@ class PSDThumbnail extends PSDImageResource {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
// TODO: Support for RAW RGB (format == 0)
|
// TODO: Support for RAW RGB (format == 0): Extract RAW reader from PICT RAW QuickTime decompressor
|
||||||
int format = pInput.readInt();
|
int format = pInput.readInt();
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 0:
|
case 0:
|
||||||
|
@ -31,8 +31,10 @@ package com.twelvemonkeys.imageio.plugins.psd;
|
|||||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||||
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||||
|
import com.twelvemonkeys.lang.StringUtil;
|
||||||
|
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.DataInput;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipInputStream;
|
||||||
@ -57,23 +59,22 @@ final class PSDUtil {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Proably also useful for PICT reader, move to some common util?
|
// TODO: Proably also useful for PICT reader, move to some common util?
|
||||||
static String readPascalString(ImageInputStream pInput) throws IOException {
|
// TODO: Is this REALLY different from the previous method? Maybe the pad should not be read..
|
||||||
|
static String readPascalString(final DataInput pInput) throws IOException {
|
||||||
int length = pInput.readUnsignedByte();
|
int length = pInput.readUnsignedByte();
|
||||||
// int length = pInput.readUnsignedShort();
|
|
||||||
byte[] bytes = new byte[length];
|
byte[] bytes = new byte[length];
|
||||||
pInput.readFully(bytes);
|
pInput.readFully(bytes);
|
||||||
if (length % 2 == 0) {
|
|
||||||
pInput.readByte(); // Pad
|
return StringUtil.decode(bytes, 0, bytes.length, "ASCII");
|
||||||
}
|
|
||||||
return new String(bytes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static String readPascalStringByte(ImageInputStream pInput) throws IOException {
|
static String readUTF16String(final DataInput pInput) throws IOException {
|
||||||
int length = pInput.readUnsignedByte();
|
int length = pInput.readInt();
|
||||||
byte[] bytes = new byte[length];
|
byte[] bytes = new byte[length * 2];
|
||||||
pInput.readFully(bytes);
|
pInput.readFully(bytes);
|
||||||
return new String(bytes);
|
|
||||||
|
return StringUtil.decode(bytes, 0, bytes.length, "UTF-16");
|
||||||
}
|
}
|
||||||
|
|
||||||
static DataInputStream createPackBitsStream(final ImageInputStream pInput, long pLength) {
|
static DataInputStream createPackBitsStream(final ImageInputStream pInput, long pLength) {
|
||||||
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.twelvemonkeys.imageio.plugins.psd;
|
||||||
|
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PSDVersionInfo
|
||||||
|
*
|
||||||
|
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||||
|
* @author last modified by $Author: haraldk$
|
||||||
|
* @version $Id: PSDVersionInfo.java,v 1.0 Nov 6, 2009 1:02:19 PM haraldk Exp$
|
||||||
|
*/
|
||||||
|
final class PSDVersionInfo extends PSDImageResource {
|
||||||
|
|
||||||
|
int mVersion;
|
||||||
|
boolean mHasRealMergedData;
|
||||||
|
String mWriter;
|
||||||
|
String mReader;
|
||||||
|
int mFileVersion;
|
||||||
|
|
||||||
|
PSDVersionInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
||||||
|
super(pId, pInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||||
|
/*
|
||||||
|
4 bytes version
|
||||||
|
1 byte hasRealMergedData
|
||||||
|
Unicode string: writer name
|
||||||
|
Unicode string: reader name
|
||||||
|
4 bytes file version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mVersion = pInput.readInt();
|
||||||
|
mHasRealMergedData = pInput.readBoolean();
|
||||||
|
|
||||||
|
mWriter = PSDUtil.readUTF16String(pInput);
|
||||||
|
mReader = PSDUtil.readUTF16String(pInput);
|
||||||
|
|
||||||
|
mFileVersion = pInput.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder builder = toStringBuilder();
|
||||||
|
|
||||||
|
builder.append(", version: ").append(mVersion);
|
||||||
|
builder.append(", hasRealMergedData: ").append(mHasRealMergedData);
|
||||||
|
builder.append(", writer: ").append(mWriter);
|
||||||
|
builder.append(", reader: ").append(mReader);
|
||||||
|
builder.append(", file version: ").append(mFileVersion);
|
||||||
|
builder.append("]");
|
||||||
|
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user