TMI-PSD: Added support for PSB (aka "Large Document Format")

Added support for 32 bit channels.
Added test cases + fixed a few bugs
General code clean-up
This commit is contained in:
Harald Kuhr
2014-09-09 16:36:18 +02:00
parent 7e88a6f7e3
commit 06674d1273
46 changed files with 1067 additions and 459 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -36,7 +36,9 @@ package com.twelvemonkeys.imageio.metadata.psd;
* @version $Id: PSD.java,v 1.0 24.01.12 16:51 haraldk Exp$
*/
public interface PSD {
static final int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
/** PSD image resource marker "8BIM". */
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
static final int RES_IPTC_NAA = 0x0404;
/** IPTC image resource id. */
int RES_IPTC_NAA = 0x0404;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,6 +136,10 @@ public final class PSDReader extends MetadataReader {
pInput.readFully(data);
}
public final int id() {
return id;
}
public final byte[] data() {
return data;
}

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import org.w3c.dom.Node;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,7 +42,7 @@ import java.io.InputStream;
* @author last modified by $Author: haraldk$
* @version $Id: ICCProfile.java,v 1.0 May 20, 2008 6:24:10 PM haraldk Exp$
*/
class ICCProfile extends PSDImageResource {
final class ICCProfile extends PSDImageResource {
private ICC_Profile profile;
ICCProfile(final short pId, final ImageInputStream pInput) throws IOException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,15 +35,20 @@ package com.twelvemonkeys.imageio.plugins.psd;
* @author last modified by $Author: haraldk$
* @version $Id: PSD.java,v 1.0 Apr 29, 2008 4:47:47 PM haraldk Exp$
*
* @see <a href="http://www.adobe.com/devnet-apps/photoshop/fileformatashtml">Adobe Photoshop File Formats Specification</a>
* @see <a href="http://www.fileformat.info/format/psd/egff.htm">http://www.fileformat.info/format/psd/egff.htm</a>
*/
interface PSD {
/** PSD 2+ Native format (.PSD) identifier "8BPS" */
int SIGNATURE_8BPS = ('8' << 24) + ('B' << 16) + ('P' << 8) + 'S';
// TODO: Is this ever used??! Spec says (and sample files uses) 8BPS + version == 2 for PSB...
/** PSD 5+ Large Document Format (.PSB) identifier "8BPB" */
int SIGNATURE_8BPB = ('8' << 24) + ('B' << 16) + ('P' << 8) + 'B';
int VERSION_PSD = 1;
int VERSION_PSB = 2;
/** PSD Resource type identifier "8BIM" */
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
@@ -105,7 +110,7 @@ interface PSD {
// Color Modes
/** Bitmap (monochrome) */
short COLOR_MODE_MONOCHROME = 0;
short COLOR_MODE_BITMAP = 0;
/** Gray-scale */
short COLOR_MODE_GRAYSCALE = 1;
@@ -541,4 +546,13 @@ interface PSD {
*/
int RES_PRINT_FLAGS_INFORMATION = 0x2710;
int RES_PATH_INFO_MAX = 0x0bb6;
int RES_PATH_INFO_MIN = 0x07d0;
/** Plug-In resource(s). Resources added by a plug-in. See the plug-in API found in the SDK documentation */
int RES_PLUGIN_MIN = 0x0fa0;
/** Plug-In resource(s). Resources added by a plug-in. See the plug-in API found in the SDK documentation */
int RES_PLUGIN_MAX = 0x1387;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ import java.util.List;
* @author last modified by $Author: haraldk$
* @version $Id: PSDAlphaChannelInfo.java,v 1.0 May 2, 2008 5:33:40 PM haraldk Exp$
*/
class PSDAlphaChannelInfo extends PSDImageResource {
final class PSDAlphaChannelInfo extends PSDImageResource {
List<String> names;
public PSDAlphaChannelInfo(short pId, final ImageInputStream pInput) throws IOException {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -35,7 +35,7 @@ package com.twelvemonkeys.imageio.plugins.psd;
* @author last modified by $Author: haraldk$
* @version $Id: PSDChannelInfo.java,v 1.0 May 6, 2008 2:46:23 PM haraldk Exp$
*/
class PSDChannelInfo {
final class PSDChannelInfo {
final short channelId;
final long length;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDChannelSourceDestinationRange.java,v 1.0 May 6, 2008 5:14:13 PM haraldk Exp$
*/
class PSDChannelSourceDestinationRange {
final class PSDChannelSourceDestinationRange {
private String channel;
private short sourceBlack;
private short sourceWhite;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -43,7 +43,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDColorData.java,v 1.0 Apr 29, 2008 5:33:01 PM haraldk Exp$
*/
class PSDColorData {
final class PSDColorData {
final byte[] colors;
private IndexColorModel colorModel;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDResolutionInfo.java,v 1.0 May 2, 2008 3:58:19 PM haraldk Exp$
*/
class PSDDisplayInfo extends PSDImageResource {
final class PSDDisplayInfo extends PSDImageResource {
// TODO: Size of this struct should be 14.. Does not compute... Something bogus here
// ColorSpace definitions:

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.metadata.Directory;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,7 +38,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDGlobalLayerMask.java,v 1.0 May 8, 2008 5:33:48 PM haraldk Exp$
*/
class PSDGlobalLayerMask {
final class PSDGlobalLayerMask {
final int colorSpace;
final int color1;
final int color2;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -28,8 +28,9 @@
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;
import javax.imageio.IIOException;
import java.io.DataInput;
import java.io.IOException;
/**
@@ -39,19 +40,21 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDHeader.java,v 1.0 Apr 29, 2008 5:18:22 PM haraldk Exp$
*/
class PSDHeader {
final class PSDHeader {
static final int PSD_MAX_SIZE = 30000;
static final int PSB_MAX_SIZE = 300000;
// The header is 26 bytes in length and is structured as follows:
//
// typedef struct _PSD_HEADER
// {
// BYTE Signature[4]; /* File ID "8BPS" */
// WORD Version; /* Version number, always 1 */
// WORD Version; /* Version number, always 1. 2 for PSB */
// BYTE Reserved[6]; /* Reserved, must be zeroed */
// WORD Channels; /* Number of color channels (1-24) including alpha
// WORD Channels; /* Number of color channels (1-56) including alpha
// channels */
// LONG Rows; /* Height of image in pixels (1-30000) */
// LONG Columns; /* Width of image in pixels (1-30000) */
// WORD Depth; /* Number of bits per channel (1, 8, and 16) */
// LONG Rows; /* Height of image in pixels (1-30000/1-300000 for PSB) */
// LONG Columns; /* Width of image in pixels (1-30000/1-300000 for PSB) */
// WORD Depth; /* Number of bits per channel (1, 8, 16 or 32) */
// WORD Mode; /* Color mode */
// } PSD_HEADER;
@@ -60,8 +63,9 @@ class PSDHeader {
final int height;
final short bits;
final short mode;
final boolean largeFormat;
PSDHeader(final ImageInputStream pInput) throws IOException {
PSDHeader(final DataInput pInput) throws IOException {
int signature = pInput.readInt();
if (signature != PSD.SIGNATURE_8BPS) {
throw new IIOException("Not a PSD document, expected signature \"8BPS\": \"" + PSDUtil.intToStr(signature) + "\" (0x" + Integer.toHexString(signature) + ")");
@@ -70,67 +74,105 @@ class PSDHeader {
int version = pInput.readUnsignedShort();
switch (version) {
case 1:
case PSD.VERSION_PSD:
largeFormat = false;
break;
case PSD.VERSION_PSB:
largeFormat = true;
break;
case 2:
throw new IIOException("Photoshop Large Document Format (PSB) not supported yet.");
default:
throw new IIOException(String.format("Unknown PSD version, expected 1 or 2: 0x%08x", version));
}
byte[] reserved = new byte[6];
pInput.readFully(reserved);
pInput.readFully(reserved); // We don't really care
channels = pInput.readShort();
if (channels <= 0) {
throw new IIOException(String.format("Unsupported number of channels: %d", channels));
}
height = pInput.readInt(); // Rows
width = pInput.readInt(); // Columns
bits = pInput.readShort();
switch (bits) {
case 1:
case 8:
case 16:
case 32:
break;
default:
throw new IIOException(String.format("Unsupported bit depth for PSD: %d bits", bits));
}
mode = pInput.readShort();
switch (mode) {
case PSD.COLOR_MODE_BITMAP:
case PSD.COLOR_MODE_GRAYSCALE:
case PSD.COLOR_MODE_INDEXED:
case PSD.COLOR_MODE_RGB:
case PSD.COLOR_MODE_CMYK:
case PSD.COLOR_MODE_MULTICHANNEL:
case PSD.COLOR_MODE_DUOTONE:
case PSD.COLOR_MODE_LAB:
break;
default:
throw new IIOException(String.format("Unsupported mode depth for PSD: %d", mode));
}
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
builder.append("[Channels: ");
builder.append(channels);
builder.append(", width: ");
builder.append(width);
builder.append(", height: ");
builder.append(height);
builder.append(", depth: ");
builder.append(bits);
builder.append(", mode: ");
builder.append(mode);
switch (mode) {
case PSD.COLOR_MODE_MONOCHROME:
builder.append(" (Monochrome)");
break;
case PSD.COLOR_MODE_GRAYSCALE:
builder.append(" (Grayscale)");
break;
case PSD.COLOR_MODE_INDEXED:
builder.append(" (Indexed)");
break;
case PSD.COLOR_MODE_RGB:
builder.append(" (RGB)");
break;
case PSD.COLOR_MODE_CMYK:
builder.append(" (CMYK)");
break;
case PSD.COLOR_MODE_MULTICHANNEL:
builder.append(" (Multi channel)");
break;
case PSD.COLOR_MODE_DUOTONE:
builder.append(" (Duotone)");
break;
case PSD.COLOR_MODE_LAB:
builder.append(" (Lab color)");
break;
default:
builder.append(" (Unkown mode)");
return new StringBuilder(getClass().getSimpleName())
.append("[version: ")
.append(largeFormat ? "2" : "1")
.append(", channels: ")
.append(channels)
.append(", width: ")
.append(width)
.append(", height: ")
.append(height)
.append(", depth: ")
.append(bits)
.append(", mode: ")
.append(mode)
.append(" (")
.append(modeAsString())
.append(")]")
.toString();
}
builder.append("]");
return builder.toString();
int getMaxSize() {
return largeFormat ? PSB_MAX_SIZE : PSD_MAX_SIZE;
}
boolean hasValidDimensions() {
return width <= getMaxSize() && height <= getMaxSize();
}
private String modeAsString() {
switch (mode) {
case PSD.COLOR_MODE_BITMAP:
return "Monochrome";
case PSD.COLOR_MODE_GRAYSCALE:
return "Grayscale";
case PSD.COLOR_MODE_INDEXED:
return "Indexed";
case PSD.COLOR_MODE_RGB:
return "RGB";
case PSD.COLOR_MODE_CMYK:
return "CMYK";
case PSD.COLOR_MODE_MULTICHANNEL:
return "Multi channel";
case PSD.COLOR_MODE_DUOTONE:
return "Duotone";
case PSD.COLOR_MODE_LAB:
return "Lab color";
default:
return "Unkown mode";
}
}
}

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.metadata.Directory;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -32,15 +32,12 @@ import com.twelvemonkeys.image.ImageUtil;
import com.twelvemonkeys.imageio.ImageReaderBase;
import com.twelvemonkeys.imageio.color.ColorSpaces;
import com.twelvemonkeys.imageio.util.IndexedImageTypeSpecifier;
import com.twelvemonkeys.xml.XMLSerializer;
import org.w3c.dom.Node;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.metadata.IIOMetadataFormatImpl;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
@@ -70,12 +67,12 @@ import java.util.List;
// See http://www.codeproject.com/KB/graphics/PSDParser.aspx
// See http://www.adobeforums.com/webx?14@@.3bc381dc/0
// Done: Allow reading the extra alpha channels (index after composite data)
public class PSDImageReader extends ImageReaderBase {
public final class PSDImageReader extends ImageReaderBase {
private PSDHeader header;
private ICC_ColorSpace colorSpace;
protected PSDMetadata metadata;
private PSDMetadata metadata;
protected PSDImageReader(final ImageReaderSpi originatingProvider) {
PSDImageReader(final ImageReaderSpi originatingProvider) {
super(originatingProvider);
}
@@ -108,10 +105,7 @@ public class PSDImageReader extends ImageReaderBase {
}
private int getLayerWidth(int layerIndex) throws IOException {
if (metadata == null || metadata.layerInfo == null) {
readImageResources(false);
readLayerAndMaskInfo(true);
}
PSDLayerInfo layerInfo = metadata.layerInfo.get(layerIndex);
@@ -119,10 +113,7 @@ public class PSDImageReader extends ImageReaderBase {
}
private int getLayerHeight(int layerIndex) throws IOException {
if (metadata == null || metadata.layerInfo == null) {
readImageResources(false);
readLayerAndMaskInfo(true);
}
PSDLayerInfo layerInfo = metadata.layerInfo.get(layerIndex);
@@ -136,14 +127,10 @@ public class PSDImageReader extends ImageReaderBase {
private ImageTypeSpecifier getRawImageTypeInternal(final int imageIndex) throws IOException {
checkBounds(imageIndex);
readHeader();
// Image index above 0, means a layer
if (imageIndex > 0) {
if (metadata == null || metadata.layerInfo == null) {
readImageResources(false);
readLayerAndMaskInfo(true);
}
return getRawImageTypeForLayer(imageIndex - 1);
}
@@ -154,46 +141,56 @@ public class PSDImageReader extends ImageReaderBase {
private ImageTypeSpecifier getRawImageTypeForCompositeLayer() throws IOException {
ColorSpace cs;
switch (header.mode) {
case PSD.COLOR_MODE_MONOCHROME:
case PSD.COLOR_MODE_BITMAP:
if (header.channels == 1 && header.bits == 1) {
return ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_BINARY);
}
throw new IIOException(
String.format("Unsupported channel count/bit depth for Monochrome PSD: %d channels/%d bits", header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported channel count/bit depth for Monochrome PSD: %d channels/%d bits", header.channels, header.bits));
case PSD.COLOR_MODE_INDEXED:
// TODO: 16 bit indexed?! Does it exist?
if (header.channels == 1 && header.bits == 8) {
return IndexedImageTypeSpecifier.createFromIndexColorModel(metadata.colorData.getIndexColorModel());
}
throw new IIOException(
String.format("Unsupported channel count/bit depth for Indexed Color PSD: %d channels/%d bits", header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported channel count/bit depth for Indexed Color PSD: %d channels/%d bits", header.channels, header.bits));
case PSD.COLOR_MODE_DUOTONE:
// NOTE: Duotone (whatever that is) should be treated as gray scale
// Fall-through
case PSD.COLOR_MODE_GRAYSCALE:
cs = getEmbeddedColorSpace();
if (cs == null) {
cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
}
if (header.channels == 1 && header.bits == 8) {
return ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_BYTE_GRAY);
}
else if (header.channels == 2 && header.bits == 8) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, DataBuffer.TYPE_BYTE, true, false);
}
else if (header.channels == 1 && header.bits == 16) {
return ImageTypeSpecifier.createFromBufferedImageType(BufferedImage.TYPE_USHORT_GRAY);
}
else if (header.channels == 2 && header.bits == 16) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, DataBuffer.TYPE_USHORT, true, false);
}
else if (header.channels == 1 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0}, new int[] {0}, DataBuffer.TYPE_INT, false, false);
}
else if (header.channels == 2 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1}, new int[] {0, 0}, DataBuffer.TYPE_INT, true, false);
}
throw new IIOException(
String.format("Unsupported channel count/bit depth for Gray Scale PSD: %d channels/%d bits", header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported channel count/bit depth for Gray Scale PSD: %d channels/%d bits", header.channels, header.bits));
case PSD.COLOR_MODE_RGB:
cs = getEmbeddedColorSpace();
if (cs == null) {
// TODO: Should probably be Adobe RGB (1998), not sRGB. Or..? Can't find any spec saying either...
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB); // ColorSpaces.getColorSpace(ColorSpaces.CS_ADOBE_RGB_1998); ?
cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
}
if (header.channels == 3 && header.bits == 8) {
@@ -208,10 +205,14 @@ public class PSDImageReader extends ImageReaderBase {
else if (header.channels >= 4 && header.bits == 16) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2, 3}, new int[] {0, 0, 0, 0}, DataBuffer.TYPE_USHORT, true, false);
}
else if (header.channels == 3 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2}, new int[] {0, 0, 0}, DataBuffer.TYPE_INT, false, false);
}
else if (header.channels >= 4 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2, 3}, new int[] {0, 0, 0, 0}, DataBuffer.TYPE_INT, true, false);
}
throw new IIOException(
String.format("Unsupported channel count/bit depth for RGB PSD: %d channels/%d bits", header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported channel count/bit depth for RGB PSD: %d channels/%d bits", header.channels, header.bits));
case PSD.COLOR_MODE_CMYK:
cs = getEmbeddedColorSpace();
@@ -231,10 +232,14 @@ public class PSDImageReader extends ImageReaderBase {
else if (header.channels == 5 && header.bits == 16) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2, 3, 4}, new int[] {0, 0, 0, 0, 0}, DataBuffer.TYPE_USHORT, true, false);
}
else if (header.channels == 4 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2, 3}, new int[] {0, 0, 0, 0}, DataBuffer.TYPE_INT, false, false);
}
else if (header.channels == 5 && header.bits == 32) {
return ImageTypeSpecifier.createBanded(cs, new int[] {0, 1, 2, 3, 4}, new int[] {0, 0, 0, 0, 0}, DataBuffer.TYPE_INT, true, false);
}
throw new IIOException(
String.format("Unsupported channel count/bit depth for CMYK PSD: %d channels/%d bits", header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported channel count/bit depth for CMYK PSD: %d channels/%d bits", header.channels, header.bits));
case PSD.COLOR_MODE_MULTICHANNEL:
// TODO: Implement
@@ -242,9 +247,7 @@ public class PSDImageReader extends ImageReaderBase {
// TODO: Implement
// TODO: If there's a color profile embedded, it should be easy, otherwise we're out of luck...
default:
throw new IIOException(
String.format("Unsupported PSD MODE: %s (%d channels/%d bits)", header.mode, header.channels, header.bits)
);
throw new IIOException(String.format("Unsupported PSD MODE: %s (%d channels/%d bits)", header.mode, header.channels, header.bits));
}
}
@@ -330,8 +333,6 @@ public class PSDImageReader extends ImageReaderBase {
private ColorSpace getEmbeddedColorSpace() throws IOException {
readImageResources(true);
// TODO: Skip this, requires storing some stream offsets
readLayerAndMaskInfo(false);
if (colorSpace == null) {
ICC_Profile profile = null;
@@ -351,27 +352,12 @@ public class PSDImageReader extends ImageReaderBase {
public BufferedImage read(final int imageIndex, final ImageReadParam param) throws IOException {
checkBounds(imageIndex);
readHeader();
readImageResources(false);
// readLayerAndMaskInfo(false);
readLayerAndMaskInfo(imageIndex > 0);
// TODO: What about the extra alpha channels possibly present? Read as gray scale as extra images?
// Layer hacks... For now, any index above 0 is considered to be a layer...
// TODO: Support layer in index 0, if "has real merged data" flag is false?
// TODO: Param support in layer code (more duping/cleanup..)
if (imageIndex > 0) {
// ImageTypeSpecifier compositeType = getRawImageTypeForCompositeLayer();
// ImageTypeSpecifier imageType = getImageTypes(0).next();
// int layerIndex = imageIndex - 1;
// PSDLayerInfo layerInfo = metadata.layerInfo.get(layerIndex);
//
// imageInput.seek(findLayerStartPos(layerIndex));
// return readLayerData(layerIndex, layerInfo, compositeType, imageType, param);
return readLayerData(imageIndex - 1, param);
}
@@ -421,13 +407,11 @@ public class PSDImageReader extends ImageReaderBase {
ySub = param.getSourceYSubsampling();
}
processImageStarted(imageIndex);
int[] byteCounts = null;
imageInput.seek(metadata.imageDataStart);
int compression = imageInput.readShort();
// TODO: Need to make sure compression is set in metadata, even without reading the image data!
metadata.compression = compression;
int[] byteCounts = null;
switch (compression) {
case PSD.COMPRESSION_NONE:
break;
@@ -435,14 +419,12 @@ public class PSDImageReader extends ImageReaderBase {
// NOTE: Byte counts will allow us to easily skip rows before AOI
byteCounts = new int[header.channels * header.height];
for (int i = 0; i < byteCounts.length; i++) {
byteCounts[i] = imageInput.readUnsignedShort();
byteCounts[i] = header.largeFormat ? imageInput.readInt() : imageInput.readUnsignedShort();
}
break;
case PSD.COMPRESSION_ZIP:
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here..
case PSD.COMPRESSION_ZIP_PREDICTION:
// TODO: Look at TIFF prediction reading
// Could be same as PNG prediction? Read up...
// TODO: Could probably use the ZIPDecoder (DeflateDecoder) here.. Look at TIFF prediction reading
throw new IIOException("PSD with ZIP compression not supported");
default:
throw new IIOException(
@@ -453,6 +435,8 @@ public class PSDImageReader extends ImageReaderBase {
);
}
processImageStarted(imageIndex);
// What we read here is the "composite layer" of the PSD file
readImageData(image, rawType.getColorModel(), source, dest, xSub, ySub, byteCounts, compression);
@@ -512,8 +496,12 @@ public class PSDImageReader extends ImageReaderBase {
short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
read16bitChannel(c, header.channels, raster.getDataBuffer(), interleavedBands, bandOffset, pSourceCM, row16, pSource, pDest, pXSub, pYSub, header.width, header.height, pByteCounts, c * header.height, pCompression == PSD.COMPRESSION_RLE);
break;
case 32:
int[] row32 = ((DataBufferInt) rowRaster.getDataBuffer()).getData();
read32bitChannel(c, header.channels, raster.getDataBuffer(), interleavedBands, bandOffset, pSourceCM, row32, pSource, pDest, pXSub, pYSub, header.width, header.height, pByteCounts, c * header.height, pCompression == PSD.COMPRESSION_RLE);
break;
default:
throw new IIOException(String.format("Unknown PSD bit depth: %s", header.bits));
throw new IIOException(String.format("Unsupported PSD bit depth: %s", header.bits));
}
if (abortRequested()) {
@@ -531,6 +519,67 @@ public class PSDImageReader extends ImageReaderBase {
processImageProgress(100f * channel / channelCount + 100f * y / (height * channelCount));
}
private void read32bitChannel(final int pChannel, final int pChannelCount,
final DataBuffer pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel,
final int[] pRow,
final Rectangle pSource, final Rectangle pDest,
final int pXSub, final int pYSub,
final int pChannelWidth, final int pChannelHeight,
final int[] pRowByteCounts, final int pRowOffset,
final boolean pRLECompressed) throws IOException {
final boolean isCMYK = pSourceColorModel.getColorSpace().getType() == ColorSpace.TYPE_CMYK;
final int colorComponents = pSourceColorModel.getColorSpace().getNumComponents();
final boolean banded = pData.getNumBanks() > 1;
for (int y = 0; y < pChannelHeight; y++) {
// NOTE: Length is in *16 bit values* (shorts)
int length = 2 * (pRLECompressed ? pRowByteCounts[pRowOffset + y] : pChannelWidth);
// TODO: Sometimes need to read the line y == source.y + source.height...
// Read entire line, if within source region and sampling
if (y >= pSource.y && y < pSource.y + pSource.height && y % pYSub == 0) {
if (pRLECompressed) {
DataInputStream input = PSDUtil.createPackBitsStream(imageInput, length);
try {
for (int x = 0; x < pChannelWidth; x++) {
pRow[x] = input.readInt();
}
}
finally {
input.close();
}
}
else {
imageInput.readFully(pRow, 0, pChannelWidth);
}
// TODO: Destination offset...??
// Copy line sub sampled into real data
int offset = (y - pSource.y) / pYSub * pDest.width * pBands + pBandOffset;
for (int x = 0; x < pDest.width; x++) {
int value = pRow[pSource.x + x * pXSub];
// CMYK values are stored inverted, but alpha is not
if (isCMYK && pChannel < colorComponents) {
value = 0xffffffff - value;
}
pData.setElem(banded ? pChannel : 0, offset + x * pBands, value);
}
}
else {
imageInput.skipBytes(length);
}
if (abortRequested()) {
break;
}
processImageProgressForChannel(pChannel, pChannelCount, y, pChannelHeight);
}
}
private void read16bitChannel(final int pChannel, final int pChannelCount,
final DataBuffer pData, final int pBands, final int pBandOffset,
final ColorModel pSourceColorModel,
@@ -731,7 +780,7 @@ public class PSDImageReader extends ImageReaderBase {
private void decomposeAlpha(final ColorModel pModel, final DataBuffer pBuffer,
final int pWidth, final int pHeight, final int pChannels) {
// TODO: Is the document background always white!?
// NOTE: It seems that the document background always white..?!
// TODO: What about CMYK + alpha?
if (pModel.hasAlpha() && pModel.getColorSpace().getType() == ColorSpace.TYPE_RGB) {
@@ -791,9 +840,16 @@ public class PSDImageReader extends ImageReaderBase {
private void readHeader() throws IOException {
assertInput();
if (header == null) {
header = new PSDHeader(imageInput);
if (!header.hasValidDimensions()) {
processWarningOccurred(String.format("Dimensions exceed maximum allowed for %s: %dx%d (max %dx%d)",
header.largeFormat ? "PSB" : "PSD",
header.width, header.height, header.getMaxSize(), header.getMaxSize()));
}
metadata = new PSDMetadata();
metadata.header = header;
@@ -818,6 +874,8 @@ public class PSDImageReader extends ImageReaderBase {
imageInput.skipBytes(length);
}
metadata.imageResourcesStart = imageInput.getStreamPosition();
// Don't need the header again
imageInput.flushBefore(imageInput.getStreamPosition());
}
@@ -826,19 +884,19 @@ public class PSDImageReader extends ImageReaderBase {
// TODO: Flags or list of interesting resources to parse
// TODO: Obey ignoreMetadata
private void readImageResources(final boolean pParseData) throws IOException {
// TODO: Avoid unnecessary stream repositioning
long pos = imageInput.getFlushedPosition();
imageInput.seek(pos);
readHeader();
long length = imageInput.readUnsignedInt();
if (pParseData || metadata.layerAndMaskInfoStart == 0) {
imageInput.seek(metadata.imageResourcesStart);
if (pParseData && length > 0) {
long imageResourcesLength = imageInput.readUnsignedInt();
if (pParseData && imageResourcesLength > 0) {
if (metadata.imageResources == null) {
metadata.imageResources = new ArrayList<PSDImageResource>();
long expectedEnd = imageInput.getStreamPosition() + length;
long expectedEnd = imageInput.getStreamPosition() + imageResourcesLength;
while (imageInput.getStreamPosition() < expectedEnd) {
// TODO: Have PSDImageResources defer actual parsing? (Just store stream offsets)
PSDImageResource resource = PSDImageResource.read(imageInput);
metadata.imageResources.add(resource);
}
@@ -847,64 +905,83 @@ public class PSDImageReader extends ImageReaderBase {
throw new IIOException("Corrupt PSD document"); // ..or maybe just a bug in the reader.. ;-)
}
}
// TODO: We should now be able to flush input
// imageInput.flushBefore(metadata.imageResourcesStart + imageResourcesLength + 4);
}
imageInput.seek(pos + length + 4);
metadata.layerAndMaskInfoStart = metadata.imageResourcesStart + imageResourcesLength + 4; // + 4 for the length field itself
}
}
// TODO: Flags or list of interesting resources to parse
// TODO: Obey ignoreMetadata
private void readLayerAndMaskInfo(final boolean pParseData) throws IOException {
// TODO: Make sure we are positioned correctly
// TODO: Avoid unnecessary stream repositioning
long length = imageInput.readUnsignedInt();
if (pParseData && length > 0) {
readImageResources(false);
if (pParseData || metadata.imageDataStart == 0) {
imageInput.seek(metadata.layerAndMaskInfoStart);
long layerAndMaskInfoLength = header.largeFormat ? imageInput.readLong() : imageInput.readUnsignedInt();
// NOTE: The spec says that if this section is empty, the length should be 0.
// Yet I have a PSB file that has size 12, and both contained lengths set to 0 (which
// is alo not as per spec, as layer count should be included if there's a layer info
// block, so minimum size should be either 0 or 14 (or 16 if multiple of 4 for PSB))...
if (pParseData && layerAndMaskInfoLength > 0) {
long pos = imageInput.getStreamPosition();
long read;
if (metadata.layerInfo == null) {
long layerInfoLength = imageInput.readUnsignedInt();
long layerInfoLength = header.largeFormat ? imageInput.readLong() : imageInput.readUnsignedInt();
if (layerInfoLength > 0) {
/*
"Layer count. If it is a negative number, its absolute value is the number of
layers and the first alpha channel contains the transparency data for the
merged result."
*/
// TODO: Figure out what the last part of that sentence means in practice...
int layers = imageInput.readShort();
int layerCount = imageInput.readShort();
PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layers)];
PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layerCount)];
for (int i = 0; i < layerInfos.length; i++) {
layerInfos[i] = new PSDLayerInfo(imageInput);
layerInfos[i] = new PSDLayerInfo(header.largeFormat, imageInput);
}
metadata.layerInfo = Arrays.asList(layerInfos);
metadata.layersStart = imageInput.getStreamPosition();
read = imageInput.getStreamPosition() - pos;
long read = imageInput.getStreamPosition() - pos;
long diff = layerInfoLength - (read - (header.largeFormat ? 8 : 4)); // - 4 for the layerInfoLength field itself
long diff = layerInfoLength - (read - 4); // - 4 for the layerInfoLength field itself
// System.out.println("diff: " + diff);
imageInput.skipBytes(diff);
} else {
metadata.layerInfo = Collections.emptyList();
}
// TODO: Global LayerMaskInfo (18 bytes or more..?)
// Global LayerMaskInfo (18 bytes or more..?)
// 4 (length), 2 (colorSpace), 8 (4 * 2 byte color components), 2 (opacity %), 1 (kind), variable (pad)
long layerMaskInfoLength = imageInput.readUnsignedInt();
// System.out.println("GlobalLayerMaskInfo length: " + layerMaskInfoLength);
long layerMaskInfoLength = imageInput.readUnsignedInt(); // NOTE: Not long for PSB!
if (layerMaskInfoLength > 0) {
metadata.globalLayerMask = new PSDGlobalLayerMask(imageInput);
// System.err.println("globalLayerMask: " + metadata.globalLayerMask);
}
}
read = imageInput.getStreamPosition() - pos;
// TODO: Parse "Additional layer information"
long toSkip = length - read;
// TODO: We should now be able to flush input
// imageInput.seek(metadata.layerAndMaskInfoStart + layerAndMaskInfoLength + (header.largeFormat ? 8 : 4));
// imageInput.flushBefore(metadata.layerAndMaskInfoStart + layerAndMaskInfoLength + (header.largeFormat ? 8 : 4));
}
// read = imageInput.getStreamPosition() - pos;
//
// long toSkip = layerAndMaskInfoLength - read;
// System.out.println("toSkip: " + toSkip);
imageInput.skipBytes(toSkip);
// imageInput.skipBytes(toSkip);
}
else {
// Skip entire layer and mask section
imageInput.skipBytes(length);
metadata.imageDataStart = metadata.layerAndMaskInfoStart + layerAndMaskInfoLength + (header.largeFormat ? 8 : 4);
}
}
@@ -949,19 +1026,22 @@ public class PSDImageReader extends ImageReaderBase {
final boolean banded = raster.getDataBuffer().getNumBanks() > 1;
final int interleavedBands = banded ? 1 : raster.getNumBands();
// TODO: progress for layers!
// TODO: Consider creating a method in PSDLayerInfo that can tell how many channels we really want to decode
for (PSDChannelInfo channelInfo : layerInfo.channelInfo) {
int compression = imageInput.readUnsignedShort();
// Skip layer if we can't read it
// channelId == -2 means "user supplied layer mask", whatever that is...
if (width <= 0 || height <= 0 || channelInfo.channelId == -2 ||
(compression != PSD.COMPRESSION_NONE && compression != PSD.COMPRESSION_RLE)) {
// channelId
// -1 = transparency mask; -2 = user supplied layer mask, -3 = real user supplied layer mask (when both a user mask and a vector mask are present)
if (width <= 0 || height <= 0 || channelInfo.channelId < -1 ||
(compression != PSD.COMPRESSION_NONE && compression != PSD.COMPRESSION_RLE)) { // TODO: ZIP Compressions!
imageInput.skipBytes(channelInfo.length - 2);
}
else {
// 0 = red, 1 = green, etc
// -1 = transparency mask; -2 = user supplied layer mask
int c = channelInfo.channelId == -1 ? layerInfo.channelInfo.length - 1 : channelInfo.channelId;
// -1 = transparency mask; -2 = user supplied layer mask, -3 = real user supplied layer mask (when both a user mask and a vector mask are present)
int c = channelInfo.channelId == -1 ? rowRaster.getNumBands() - 1 : channelInfo.channelId;
// NOTE: For layers, byte counts are written per channel, while for the composite data
// byte counts are written for all channels before the image data.
@@ -975,10 +1055,10 @@ public class PSDImageReader extends ImageReaderBase {
case PSD.COMPRESSION_RLE:
// If RLE, the the image data starts with the byte counts
// for all the scan lines in the channel (LayerBottom-LayerTop), with
// each count stored as a two*byte value.
// each count stored as a two*byte (four for PSB) value.
byteCounts = new int[layerInfo.bottom - layerInfo.top];
for (int i = 0; i < byteCounts.length; i++) {
byteCounts[i] = imageInput.readUnsignedShort();
byteCounts[i] = header.largeFormat ? imageInput.readInt() : imageInput.readUnsignedShort();
}
break;
@@ -998,11 +1078,18 @@ public class PSDImageReader extends ImageReaderBase {
break;
case 8:
byte[] row8 = ((DataBufferByte) rowRaster.getDataBuffer()).getData();
read8bitChannel(c, imageType.getNumBands(), raster.getDataBuffer(), interleavedBands, bandOffset, sourceCM, row8, area, area, xsub, ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
read8bitChannel(c, imageType.getNumBands(), raster.getDataBuffer(), interleavedBands, bandOffset, sourceCM, row8, area, area, xsub,
ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
break;
case 16:
short[] row16 = ((DataBufferUShort) rowRaster.getDataBuffer()).getData();
read16bitChannel(c, imageType.getNumBands(), raster.getDataBuffer(), interleavedBands, bandOffset, sourceCM, row16, area, area, xsub, ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
read16bitChannel(c, imageType.getNumBands(), raster.getDataBuffer(), interleavedBands, bandOffset, sourceCM, row16, area, area, xsub,
ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
break;
case 32:
int[] row32 = ((DataBufferInt) rowRaster.getDataBuffer()).getData();
read32bitChannel(c, imageType.getNumBands(), raster.getDataBuffer(), interleavedBands, bandOffset, sourceCM, row32, area, area, xsub,
ysub, width, height, byteCounts, 0, compression == PSD.COMPRESSION_RLE);
break;
default:
throw new IIOException(String.format("Unknown PSD bit depth: %s", header.bits));
@@ -1024,16 +1111,16 @@ public class PSDImageReader extends ImageReaderBase {
// If layer has more channels than composite data, it's normally extra alpha...
if (layerInfo.channelInfo.length > compositeType.getNumBands()) {
// ...but, it could also be just the user mask...
boolean userMask = false;
// ...but, it could also be just one of the user masks...
int newBandNum = 0;
for (PSDChannelInfo channelInfo : layerInfo.channelInfo) {
if (channelInfo.channelId == -2) {
userMask = true;
break;
// -2 = user supplied layer mask, -3 real user supplied layer mask (when both a user mask and a vector mask are present)
if (channelInfo.channelId >= -1) {
newBandNum++;
}
}
int newBandNum = layerInfo.channelInfo.length - (userMask ? 1 : 0);
// If there really is more channels, then create new imageTypeSpec
if (newBandNum > compositeType.getNumBands()) {
@@ -1056,30 +1143,28 @@ public class PSDImageReader extends ImageReaderBase {
/// Layer support
@Override protected void checkBounds(final int index) throws IOException {
// Avoid parsing layer stuff, if we just want to read the composite data
if (index == 0) {
assertInput();
readLayerAndMaskInfo(false);
}
else {
super.checkBounds(index);
}
}
@Override
public int getNumImages(boolean allowSearch) throws IOException {
// NOTE: Spec says this method should throw IllegalStateException if allowSearch && isSeekForwardOnly()
// But that makes no sense for a format (like PSD) that does not need to search, right?
readHeader();
readImageResources(false);
readLayerAndMaskInfo(true); // TODO: Consider quicker reading of just the number of layers.
readLayerAndMaskInfo(true);
return metadata.layerInfo != null ? metadata.layerInfo.size() + 1 : 1; // TODO: Only plus one, if "has real merged data"?
}
// TODO: For now, leave as Metadata
/*
// ?
Point getOffset(int pImageIndex) throws IOException;
// Return 0, 0 for index 0, otherwise use layer offset
*/
/// Metadata support
// TODO
@Override
public IIOMetadata getStreamMetadata() throws IOException {
@@ -1090,20 +1175,15 @@ public class PSDImageReader extends ImageReaderBase {
@Override
public IIOMetadata getImageMetadata(final int imageIndex) throws IOException {
// TODO: Implement
checkBounds(imageIndex);
readHeader();
readImageResources(true);
readLayerAndMaskInfo(true);
// TODO: Need to make sure compression is set in metadata, even without reading the image data!
// NOTE: Need to make sure compression is set in metadata, even without reading the image data!
imageInput.seek(metadata.imageDataStart);
metadata.compression = imageInput.readShort();
// metadata.header = header;
// metadata.colorData = colorData;
// metadata.imageResources = imageResources;
return metadata; // TODO: clone if we change to mutable metadata
}
@@ -1129,8 +1209,6 @@ public class PSDImageReader extends ImageReaderBase {
if (metadata.imageResources == null) {
// TODO: Need flag here, to specify what resources to read...
readImageResources(true);
// TODO: Skip this, requires storing some stream offsets
readLayerAndMaskInfo(false);
}
for (PSDImageResource resource : metadata.imageResources) {
@@ -1236,12 +1314,15 @@ public class PSDImageReader extends ImageReaderBase {
PSDImageReader imageReader = new PSDImageReader(null);
for (; idx < pArgs.length; idx++) {
File file = new File(pArgs[idx]);
System.out.println();
System.out.println("file: " + file.getAbsolutePath());
ImageInputStream stream = ImageIO.createImageInputStream(file);
imageReader.setInput(stream);
imageReader.readHeader();
// System.out.println("imageReader.header: " + imageReader.header);
System.out.println("imageReader.header: " + imageReader.header);
imageReader.readImageResources(true);
System.out.println("imageReader.imageResources: " + imageReader.metadata.imageResources);
@@ -1249,6 +1330,7 @@ public class PSDImageReader extends ImageReaderBase {
imageReader.readLayerAndMaskInfo(true);
System.out.println("imageReader.layerInfo: " + imageReader.metadata.layerInfo);
/*
// System.out.println("imageReader.globalLayerMask: " + imageReader.globalLayerMask);
System.out.println();
@@ -1264,7 +1346,7 @@ public class PSDImageReader extends ImageReaderBase {
node = metadata.getAsTree(PSDMetadata.NATIVE_METADATA_FORMAT_NAME);
// serializer = new XMLSerializer(System.out, System.getProperty("file.encoding"));
serializer.serialize(node, true);
*/
if (readThumbnails && imageReader.hasThumbnails(0)) {
int thumbnails = imageReader.getNumThumbnails(0);
for (int i = 0; i < thumbnails; i++) {
@@ -1318,3 +1400,4 @@ public class PSDImageReader extends ImageReaderBase {
}
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -44,7 +44,7 @@ import java.util.Locale;
* @author last modified by $Author: haraldk$
* @version $Id: PSDImageReaderSpi.java,v 1.0 Apr 29, 2008 4:49:03 PM haraldk Exp$
*/
public class PSDImageReaderSpi extends ImageReaderSpi {
final public class PSDImageReaderSpi extends ImageReaderSpi {
/**
* Creates a {@code PSDImageReaderSpi}.
@@ -87,9 +87,23 @@ public class PSDImageReaderSpi extends ImageReaderSpi {
ImageInputStream stream = (ImageInputStream) pSource;
stream.mark();
try {
return stream.readInt() == PSD.SIGNATURE_8BPS;
// TODO: Test more of the header, see PSDImageReader#readHeader
if (stream.readInt() == PSD.SIGNATURE_8BPS) {
int version = stream.readUnsignedShort();
switch (version) {
case PSD.VERSION_PSD:
case PSD.VERSION_PSB:
break;
default:
return false;
}
return true;
}
return false;
}
finally {
stream.reset();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -110,7 +110,7 @@ public class PSDImageResource {
builder.append("[ID: 0x");
builder.append(Integer.toHexString(id));
if (name != null && name.trim().length() != 0) {
if (name != null && !name.trim().isEmpty()) {
builder.append(", name: \"");
builder.append(name);
builder.append("\"");
@@ -139,6 +139,13 @@ public class PSDImageResource {
case PSD.RES_PRINT_FLAGS_INFORMATION:
return null;
default:
if (pId >= PSD.RES_PATH_INFO_MIN && pId <= PSD.RES_PATH_INFO_MAX) {
return "PathInformationResource";
}
if (pId >= PSD.RES_PLUGIN_MIN && pId <= PSD.RES_PLUGIN_MAX) {
return "PluginResource";
}
try {
for (Field field : PSD.class.getDeclaredFields()) {
if (field.getName().startsWith("RES_") && field.getInt(null) == pId) {
@@ -160,9 +167,9 @@ public class PSDImageResource {
throw new IIOException(String.format("Wrong image resource type, expected '8BIM': '%s'", PSDUtil.intToStr(type)));
}
// TODO: Process more of the resource stuff, most important are IPTC, EXIF and XMP data,
// version info, and thumbnail for thumbnail-support.
// TODO: Have PSDImageResources defer actual parsing? (Just store stream offsets)
short id = pInput.readShort();
switch (id) {
case PSD.RES_RESOLUTION_INFO:
return new PSDResolutionInfo(id, pInput);
@@ -196,9 +203,8 @@ public class PSDImageResource {
case PSD.RES_PRINT_FLAGS_INFORMATION:
return new PSDPrintFlagsInformation(id, pInput);
default:
if (id >= 0x07d0 && id <= 0x0bb6) {
// TODO: Parse saved path information
return new PSDImageResource(id, pInput);
if (id >= PSD.RES_PATH_INFO_MIN && id <= PSD.RES_PATH_INFO_MAX) {
return new PSDPathResource(id, pInput);
}
else {
return new PSDImageResource(id, pInput);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDLayerBlendMode.java,v 1.0 May 8, 2008 4:34:35 PM haraldk Exp$
*/
class PSDLayerBlendMode {
final class PSDLayerBlendMode {
final int blendMode;
final int opacity; // 0-255
final int clipping; // 0: base, 1: non-base

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -40,7 +40,7 @@ import java.util.Arrays;
* @author last modified by $Author: haraldk$
* @version $Id: PSDLayerInfo.java,v 1.0 Apr 29, 2008 6:01:12 PM haraldk Exp$
*/
class PSDLayerInfo {
final class PSDLayerInfo {
final int top;
final int left;
final int bottom;
@@ -52,7 +52,7 @@ class PSDLayerInfo {
final PSDChannelSourceDestinationRange[] ranges;
final String layerName;
PSDLayerInfo(ImageInputStream pInput) throws IOException {
PSDLayerInfo(final boolean largeFormat, final ImageInputStream pInput) throws IOException {
top = pInput.readInt();
left = pInput.readInt();
bottom = pInput.readInt();
@@ -63,7 +63,7 @@ class PSDLayerInfo {
channelInfo = new PSDChannelInfo[channels];
for (int i = 0; i < channels; i++) {
short channelId = pInput.readShort();
long length = pInput.readUnsignedInt();
long length = largeFormat ? pInput.readLong() : pInput.readUnsignedInt();
channelInfo[i] = new PSDChannelInfo(channelId, length);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDLayerMaskData.java,v 1.0 May 6, 2008 5:15:05 PM haraldk Exp$
*/
class PSDLayerMaskData {
final class PSDLayerMaskData {
private int top;
private int left;
private int bottom;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.metadata.Directory;
@@ -35,7 +63,11 @@ public final class PSDMetadata extends AbstractMetadata {
List<PSDImageResource> imageResources;
PSDGlobalLayerMask globalLayerMask;
List<PSDLayerInfo> layerInfo;
long imageResourcesStart;
long layerAndMaskInfoStart;
long layersStart;
long imageDataStart;
static final String[] COLOR_MODES = {
"MONOCHROME", "GRAYSCALE", "INDEXED", "RGB", "CMYK", null, null, "MULTICHANNEL", "DUOTONE", "LAB"
@@ -85,17 +117,17 @@ public final class PSDMetadata extends AbstractMetadata {
}
private Node createHeaderNode() {
IIOMetadataNode header = new IIOMetadataNode("Header");
IIOMetadataNode headerNode = new IIOMetadataNode("Header");
header.setAttribute("type", "PSD");
header.setAttribute("version", "1");
header.setAttribute("channels", Integer.toString(this.header.channels));
header.setAttribute("height", Integer.toString(this.header.height));
header.setAttribute("width", Integer.toString(this.header.width));
header.setAttribute("bits", Integer.toString(this.header.bits));
header.setAttribute("mode", COLOR_MODES[this.header.mode]);
headerNode.setAttribute("type", "PSD");
headerNode.setAttribute("version", header.largeFormat ? "2" : "1");
headerNode.setAttribute("channels", Integer.toString(header.channels));
headerNode.setAttribute("height", Integer.toString(header.height));
headerNode.setAttribute("width", Integer.toString(header.width));
headerNode.setAttribute("bits", Integer.toString(header.bits));
headerNode.setAttribute("mode", COLOR_MODES[header.mode]);
return header;
return headerNode;
}
private Node createImageResourcesNode() {
@@ -112,18 +144,6 @@ public final class PSDMetadata extends AbstractMetadata {
// TODO: Format spec
node = new IIOMetadataNode("ICCProfile");
node.setAttribute("colorSpaceType", JAVA_CS[profile.getProfile().getColorSpaceType()]);
//
// FastByteArrayOutputStream data = new FastByteArrayOutputStream(0);
// EncoderStream base64 = new EncoderStream(data, new Base64Encoder(), true);
//
// try {
// base64.write(profile.getProfile().getData());
// }
// catch (IOException ignore) {
// }
//
// byte[] bytes = data.toByteArray();
// node.setAttribute("data", StringUtil.decode(bytes, 0, bytes.length, "ASCII"));
node.setUserObject(profile.getProfile());
}
else if (imageResource instanceof PSDAlphaChannelInfo) {
@@ -347,13 +367,12 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardChromaNode() {
IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma");
IIOMetadataNode node; // scratch node
IIOMetadataNode chroma = new IIOMetadataNode("Chroma");
node = new IIOMetadataNode("ColorSpaceType");
IIOMetadataNode colorSpaceType = new IIOMetadataNode("ColorSpaceType");
String cs;
switch (header.mode) {
case PSD.COLOR_MODE_MONOCHROME:
case PSD.COLOR_MODE_BITMAP:
case PSD.COLOR_MODE_GRAYSCALE:
case PSD.COLOR_MODE_DUOTONE: // Rationale: Spec says treat as gray...
cs = "GRAY";
@@ -374,25 +393,24 @@ public final class PSDMetadata extends AbstractMetadata {
default:
throw new AssertionError("Unreachable");
}
node.setAttribute("name", cs);
chroma_node.appendChild(node);
colorSpaceType.setAttribute("name", cs);
chroma.appendChild(colorSpaceType);
// TODO: Channels might be 5 for RGB + A + Mask... Probably not correct
node = new IIOMetadataNode("NumChannels");
node.setAttribute("value", Integer.toString(header.channels));
chroma_node.appendChild(node);
IIOMetadataNode numChannels = new IIOMetadataNode("NumChannels");
numChannels.setAttribute("value", Integer.toString(header.channels));
chroma.appendChild(numChannels);
// TODO: Check if this is correct with bitmap (monchrome)
node = new IIOMetadataNode("BlackIsZero");
node.setAttribute("value", "true");
chroma_node.appendChild(node);
IIOMetadataNode blackIsZero = new IIOMetadataNode("BlackIsZero");
blackIsZero.setAttribute("value", "true");
chroma.appendChild(blackIsZero);
if (header.mode == PSD.COLOR_MODE_INDEXED) {
node = createPaletteNode();
chroma_node.appendChild(node);
IIOMetadataNode paletteNode = createPaletteNode();
chroma.appendChild(paletteNode);
}
// TODO: Hardcode background color to white?
// TODO: Use
// if (bKGD_present) {
// if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
// node = new IIOMetadataNode("BackgroundIndex");
@@ -415,24 +433,25 @@ public final class PSDMetadata extends AbstractMetadata {
// chroma_node.appendChild(node);
// }
return chroma_node;
return chroma;
}
private IIOMetadataNode createPaletteNode() {
IIOMetadataNode node = new IIOMetadataNode("Palette");
IIOMetadataNode palette = new IIOMetadataNode("Palette");
IndexColorModel cm = colorData.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);
palette.appendChild(entry);
}
return node;
return palette;
}
private String getMultiChannelCS(short channels) {
@@ -446,33 +465,33 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardCompressionNode() {
IIOMetadataNode compressionNode = new IIOMetadataNode("Compression");
IIOMetadataNode node; // scratch node
node = new IIOMetadataNode("CompressionTypeName");
String compression;
IIOMetadataNode compressionTypeName = new IIOMetadataNode("CompressionTypeName");
String compressionName;
switch (this.compression) {
switch (compression) {
case PSD.COMPRESSION_NONE:
compression = "none";
compressionName = "none";
break;
case PSD.COMPRESSION_RLE:
compression = "PackBits";
compressionName = "PackBits";
break;
case PSD.COMPRESSION_ZIP:
case PSD.COMPRESSION_ZIP_PREDICTION:
compression = "Deflate"; // TODO: ZLib? (TIFF native metadata format specifies both.. :-P)
compressionName = "Zip";
break;
default:
throw new AssertionError("Unreachable");
}
node.setAttribute("value", compression);
compressionNode.appendChild(node);
compressionTypeName.setAttribute("value", compressionName);
compressionNode.appendChild(compressionTypeName);
// TODO: Does it make sense to specify lossless for compression "none"?
node = new IIOMetadataNode("Lossless");
node.setAttribute("value", "true");
compressionNode.appendChild(node);
if (compression != PSD.COMPRESSION_NONE) {
IIOMetadataNode lossless = new IIOMetadataNode("Lossless");
lossless.setAttribute("value", "true");
compressionNode.appendChild(lossless);
}
return compressionNode;
}
@@ -480,15 +499,14 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardDataNode() {
IIOMetadataNode dataNode = new IIOMetadataNode("Data");
IIOMetadataNode node; // scratch node
node = new IIOMetadataNode("PlanarConfiguration");
node.setAttribute("value", "PlaneInterleaved"); // TODO: Check with spec
dataNode.appendChild(node);
IIOMetadataNode planarConfiguration = new IIOMetadataNode("PlanarConfiguration");
planarConfiguration.setAttribute("value", "PlaneInterleaved");
dataNode.appendChild(planarConfiguration);
node = new IIOMetadataNode("SampleFormat");
node.setAttribute("value", header.mode == PSD.COLOR_MODE_INDEXED ? "Index" : "UnsignedIntegral");
dataNode.appendChild(node);
IIOMetadataNode sampleFormat = new IIOMetadataNode("SampleFormat");
sampleFormat.setAttribute("value", header.mode == PSD.COLOR_MODE_INDEXED ? "Index" : "UnsignedIntegral");
dataNode.appendChild(sampleFormat);
String bitDepth = Integer.toString(header.bits); // bits per plane
@@ -496,11 +514,9 @@ public final class PSDMetadata extends AbstractMetadata {
String[] bps = new String[header.channels];
Arrays.fill(bps, bitDepth);
node = new IIOMetadataNode("BitsPerSample");
node.setAttribute("value", StringUtil.toCSVString(bps, " "));
dataNode.appendChild(node);
// TODO: SampleMSB? Or is network (aka Motorola/big endian) byte order assumed?
IIOMetadataNode bitsPerSample = new IIOMetadataNode("BitsPerSample");
bitsPerSample.setAttribute("value", StringUtil.toCSVString(bps, " "));
dataNode.appendChild(bitsPerSample);
return dataNode;
}
@@ -542,33 +558,6 @@ public final class PSDMetadata extends AbstractMetadata {
dimensionNode.appendChild(node);
}
// TODO:
/*
<!ELEMENT "HorizontalPixelOffset" EMPTY>
<!-- The horizonal position, in pixels, where the image should be
rendered onto a raster display -->
<!ATTLIST "HorizontalPixelOffset" "value" #CDATA #REQUIRED>
<!-- Data type: Integer -->
<!ELEMENT "VerticalPixelOffset" EMPTY>
<!-- The vertical position, in pixels, where the image should be
rendered onto a raster display -->
<!ATTLIST "VerticalPixelOffset" "value" #CDATA #REQUIRED>
<!-- Data type: Integer -->
<!ELEMENT "HorizontalScreenSize" EMPTY>
<!-- The width, in pixels, of the raster display into which the
image should be rendered -->
<!ATTLIST "HorizontalScreenSize" "value" #CDATA #REQUIRED>
<!-- Data type: Integer -->
<!ELEMENT "VerticalScreenSize" EMPTY>
<!-- The height, in pixels, of the raster display into which the
image should be rendered -->
<!ATTLIST "VerticalScreenSize" "value" #CDATA #REQUIRED>
<!-- Data type: Integer -->
*/
return dimensionNode;
}
@@ -580,11 +569,10 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardDocumentNode() {
IIOMetadataNode document_node = new IIOMetadataNode("Document");
IIOMetadataNode node; // scratch node
node = new IIOMetadataNode("FormatVersion");
node.setAttribute("value", "1"); // PSD format version is always 1
document_node.appendChild(node);
IIOMetadataNode formatVersion = new IIOMetadataNode("FormatVersion");
formatVersion.setAttribute("value", header.largeFormat ? "2" : "1"); // PSD format version is always 1, PSB is 2
document_node.appendChild(formatVersion);
// Get EXIF data if present
Iterator<PSDEXIF1Data> exif = getResources(PSDEXIF1Data.class);
@@ -594,18 +582,18 @@ public final class PSDMetadata extends AbstractMetadata {
// Get the EXIF DateTime (aka ModifyDate) tag if present
Entry dateTime = data.directory.getEntryById(TIFF.TAG_DATE_TIME);
if (dateTime != null) {
node = new IIOMetadataNode("ImageCreationTime"); // As TIFF, but could just as well be ImageModificationTime
IIOMetadataNode imageCreationTime = new IIOMetadataNode("ImageCreationTime"); // As TIFF, but could just as well be ImageModificationTime
// Format: "YYYY:MM:DD hh:mm:ss"
String value = dateTime.getValueAsString();
node.setAttribute("year", value.substring(0, 4));
node.setAttribute("month", value.substring(5, 7));
node.setAttribute("day", value.substring(8, 10));
node.setAttribute("hour", value.substring(11, 13));
node.setAttribute("minute", value.substring(14, 16));
node.setAttribute("second", value.substring(17, 19));
imageCreationTime.setAttribute("year", value.substring(0, 4));
imageCreationTime.setAttribute("month", value.substring(5, 7));
imageCreationTime.setAttribute("day", value.substring(8, 10));
imageCreationTime.setAttribute("hour", value.substring(11, 13));
imageCreationTime.setAttribute("minute", value.substring(14, 16));
imageCreationTime.setAttribute("second", value.substring(17, 19));
document_node.appendChild(node);
document_node.appendChild(imageCreationTime);
}
}
@@ -614,7 +602,7 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardTextNode() {
// TODO: TIFF uses
// NOTE: TIFF uses
// DocumentName, ImageDescription, Make, Model, PageName, Software, Artist, HostComputer, InkNames, Copyright:
// /Text/TextEntry@keyword = field name, /Text/TextEntry@value = field value.
// Example: TIFF Software field => /Text/TextEntry@keyword = "Software",
@@ -679,9 +667,10 @@ public final class PSDMetadata extends AbstractMetadata {
}
private void appendTextEntriesFlat(final IIOMetadataNode node, final Directory directory, final FilterIterator.Filter<Entry> filter) {
FilterIterator<Entry> pEntries = new FilterIterator<Entry>(directory.iterator(), filter);
while (pEntries.hasNext()) {
Entry entry = pEntries.next();
FilterIterator<Entry> entries = new FilterIterator<Entry>(directory.iterator(), filter);
while (entries.hasNext()) {
Entry entry = entries.next();
if (entry.getValue() instanceof Directory) {
appendTextEntriesFlat(node, (Directory) entry.getValue(), filter);
@@ -694,7 +683,7 @@ public final class PSDMetadata extends AbstractMetadata {
tag.setAttribute("keyword", fieldName);
}
else {
// TODO: This should never happen, as we filter out only specific nodes
// NOTE: This should never happen, as we filter out only specific nodes
tag.setAttribute("keyword", String.format("%s", entry.getIdentifier()));
}
@@ -711,14 +700,13 @@ public final class PSDMetadata extends AbstractMetadata {
@Override
protected IIOMetadataNode getStandardTransparencyNode() {
IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency");
IIOMetadataNode node; // scratch node
IIOMetadataNode transparencyNode = new IIOMetadataNode("Transparency");
node = new IIOMetadataNode("Alpha");
node.setAttribute("value", hasAlpha() ? "nonpremultiplied" : "none"); // TODO: Check spec
transparency_node.appendChild(node);
IIOMetadataNode node = new IIOMetadataNode("Alpha");
node.setAttribute("value", hasAlpha() ? "premultiplied" : "none");
transparencyNode.appendChild(node);
return transparency_node;
return transparencyNode;
}
private boolean hasAlpha() {

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.metadata.Directory;
@@ -17,7 +45,7 @@ import java.util.Arrays;
*/
public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
private final static PSDMetadataFormat sInstance = new PSDMetadataFormat();
private static final PSDMetadataFormat instance = new PSDMetadataFormat();
/**
* Private constructor.
@@ -207,6 +235,6 @@ public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
* @see javax.imageio.metadata.IIOMetadata#getMetadataFormat
*/
public static PSDMetadataFormat getInstance() {
return sInstance;
return instance;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;
import java.io.IOException;
/**
* PSDPathResource
*
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
* @author last modified by $Author: haraldk$
* @version $Id: PSDPathResource.java,v 1.0 Sept 4, 2014 8:23:09 PM haraldk Exp$
*/
final class PSDPathResource extends PSDImageResource {
PSDPathResource(final short resourceId, final ImageInputStream input) throws IOException {
super(resourceId, input);
}
}

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;
@@ -33,10 +61,14 @@ final class PSDPrintFlags extends PSDImageResource {
negative = pInput.readBoolean();
flip = pInput.readBoolean();
interpolate = pInput.readBoolean();
// Photoshop 2.5 and before has shorter struct
if (size > 7) {
caption = pInput.readBoolean();
pInput.skipBytes(size - 8);
}
}
@Override
public String toString() {

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -39,7 +39,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDResolutionInfo.java,v 1.0 May 2, 2008 3:58:19 PM haraldk Exp$
*/
class PSDResolutionInfo extends PSDImageResource {
final class PSDResolutionInfo extends PSDImageResource {
// typedef struct _ResolutionInfo
// {
// LONG hRes; /* Fixed-point number: pixels per inch */

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.IIOException;
@@ -16,7 +44,7 @@ import java.io.IOException;
* @author last modified by $Author: haraldk$
* @version $Id: PSDThumbnail.java,v 1.0 Jul 29, 2009 4:41:06 PM haraldk Exp$
*/
class PSDThumbnail extends PSDImageResource {
final class PSDThumbnail extends PSDImageResource {
private int format;
private int width;
private int height;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, Harald Kuhr
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import javax.imageio.stream.ImageInputStream;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.metadata.Directory;

View File

@@ -1,3 +1,31 @@
/*
* Copyright (c) 2014, Harald Kuhr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name "TwelveMonkeys" nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.twelvemonkeys.imageio.plugins.psd;
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
@@ -27,7 +55,7 @@ import static org.junit.Assert.*;
*/
public class PSDImageReaderTestCase extends ImageReaderAbstractTestCase<PSDImageReader> {
static ImageReaderSpi provider = new PSDImageReaderSpi();
private static final ImageReaderSpi provider = new PSDImageReaderSpi();
protected List<TestData> getTestData() {
return Arrays.asList(
@@ -48,7 +76,21 @@ public class PSDImageReaderTestCase extends ImageReaderAbstractTestCase<PSDImage
// 1 channel, gray, 16 bit samples
new TestData(getClassLoaderResource("/psd/test_gray16.psd"), new Dimension(710, 512)),
// 4 channel, CMYK, 16 bit samples
new TestData(getClassLoaderResource("/psd/cmyk_16bits.psd"), new Dimension(1000, 275))
new TestData(getClassLoaderResource("/psd/cmyk_16bits.psd"), new Dimension(1000, 275)),
// 3 channel, RGB, 32 bit samples
new TestData(getClassLoaderResource("/psd/32bit5x5.psd"), new Dimension(5, 5)),
// 3 channel, RGB, 8 bit samples ("Large Document Format" aka PSB)
new TestData(getClassLoaderResource("/psd/test_original.psb"), new Dimension(710, 512)),
// From http://telegraphics.com.au/svn/psdparse/trunk/psd/
new TestData(getClassLoaderResource("/psd/adobehq.psd"), new Dimension(341, 512)),
new TestData(getClassLoaderResource("/psd/adobehq_ind.psd"), new Dimension(341, 512)),
// Contains a shorter than normal PrintFlags chunk
new TestData(getClassLoaderResource("/psd/adobehq-2.5.psd"), new Dimension(341, 512)),
new TestData(getClassLoaderResource("/psd/adobehq-3.0.psd"), new Dimension(341, 512)),
new TestData(getClassLoaderResource("/psd/adobehq-5.5.psd"), new Dimension(341, 512)),
new TestData(getClassLoaderResource("/psd/adobehq-7.0.psd"), new Dimension(341, 512)),
// From https://github.com/kmike/psd-tools/tree/master/tests/psd_files
new TestData(getClassLoaderResource("/psd/masks2.psd"), new Dimension(640, 1136)) // TODO: Test read layers!
// TODO: Need uncompressed PSD
// TODO: Need more recent ZIP compressed PSD files from CS2/CS3+
);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.