mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-10-04 11:26:44 -04:00
It all works
This commit is contained in:
25
imageio/imageio-psd/license.txt
Executable file
25
imageio/imageio-psd/license.txt
Executable file
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2009, 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.
|
31
imageio/imageio-psd/pom.xml
Normal file
31
imageio/imageio-psd/pom.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-psd</artifactId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
<name>TwelveMonkeys ImageIO PSD plugin</name>
|
||||
<description>
|
||||
ImageIO plugin for Adobe Photoshop Document (PSD).
|
||||
</description>
|
||||
|
||||
<parent>
|
||||
<artifactId>twelvemonkeys-imageio</artifactId>
|
||||
<groupId>com.twelvemonkeys</groupId>
|
||||
<version>2.3-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.twelvemonkeys.imageio</groupId>
|
||||
<artifactId>twelvemonkeys-imageio-core</artifactId>
|
||||
<classifier>tests</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 java.awt.color.ColorSpace;
|
||||
|
||||
/**
|
||||
* CMYKColorSpace
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: CMYKColorSpace.java,v 1.0 Apr 30, 2008 1:38:13 PM haraldk Exp$
|
||||
*/
|
||||
// TODO: Move to com.twelvemonkeys.image?
|
||||
// TODO: Read a ICC CMYK profile from classpath resource (from ECI)? ISO coated?
|
||||
final class CMYKColorSpace extends ColorSpace {
|
||||
|
||||
static final ColorSpace INSTANCE = new CMYKColorSpace();
|
||||
final ColorSpace sRGB = getInstance(CS_sRGB);
|
||||
|
||||
CMYKColorSpace() {
|
||||
super(ColorSpace.TYPE_CMYK, 4);
|
||||
}
|
||||
|
||||
public static ColorSpace getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public float[] toRGB(float[] colorvalue) {
|
||||
return new float[] {
|
||||
(1 - colorvalue[0]) * (1 - colorvalue[3]),
|
||||
(1 - colorvalue[1]) * (1 - colorvalue[3]),
|
||||
(1 - colorvalue[2]) * (1 - colorvalue[3])
|
||||
};
|
||||
// TODO: Convert via CIEXYZ space using sRGB space, as suggested in docs
|
||||
// return sRGB.fromCIEXYZ(toCIEXYZ(colorvalue));
|
||||
}
|
||||
|
||||
public float[] fromRGB(float[] rgbvalue) {
|
||||
// Compute CMY
|
||||
float c = 1 - rgbvalue[0];
|
||||
float m = 1 - rgbvalue[1];
|
||||
float y = 1 - rgbvalue[2];
|
||||
|
||||
// Find K
|
||||
float k = Math.min(c, Math.min(m, y));
|
||||
|
||||
// Convert to CMYK values
|
||||
return new float[] {(c - k), (m - k), (y - k), k};
|
||||
/*
|
||||
http://www.velocityreviews.com/forums/t127265-rgb-to-cmyk.html
|
||||
|
||||
(Step 0: Normalize R,G, and B values to fit into range [0.0 ... 1.0], or
|
||||
adapt the following matrix.)
|
||||
|
||||
Step 1: RGB to CMY
|
||||
|
||||
| C | | 1 | | R |
|
||||
| M | = | 1 | - | G |
|
||||
| Y | | 1 | | B |
|
||||
|
||||
Step 2: CMY to CMYK
|
||||
|
||||
| C' | | C | | min(C,M,Y) |
|
||||
| M' | | M | | min(C,M,Y) |
|
||||
| Y' | = | Y | - | min(C,M,Y) |
|
||||
| K' | | min(C,M,Y) | | 0 |
|
||||
|
||||
Easier to calculate if K' is calculated first, because K' = min(C,M,Y):
|
||||
|
||||
| C' | | C | | K' |
|
||||
| M' | | M | | K' |
|
||||
| Y' | = | Y | - | K' |
|
||||
| K' | | K'| | 0 |
|
||||
*/
|
||||
// return fromCIEXYZ(sRGB.toCIEXYZ(rgbvalue));
|
||||
}
|
||||
|
||||
public float[] toCIEXYZ(float[] colorvalue) {
|
||||
throw new UnsupportedOperationException("Method toCIEXYZ not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
public float[] fromCIEXYZ(float[] colorvalue) {
|
||||
throw new UnsupportedOperationException("Method fromCIEXYZ not implemented"); // TODO: Implement
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.IIOUtil;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.color.ICC_Profile;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* ICCProfile
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 {
|
||||
private ICC_Profile mProfile;
|
||||
|
||||
ICCProfile(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(ImageInputStream pInput) throws IOException {
|
||||
InputStream stream = IIOUtil.createStreamAdapter(pInput, mSize);
|
||||
try {
|
||||
mProfile = ICC_Profile.getInstance(stream);
|
||||
}
|
||||
finally {
|
||||
// Make sure stream has correct position after read
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
|
||||
public ICC_Profile getProfile() {
|
||||
return mProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", profile: ").append(mProfile);
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
544
imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSD.java
Executable file
544
imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSD.java
Executable file
@@ -0,0 +1,544 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
/**
|
||||
* PSD format constants.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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.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';
|
||||
|
||||
/** PSD 5+ Large Document Format (.PSB) identifier "8BPB" */
|
||||
int SIGNATURE_8BPB = ('8' << 24) + ('B' << 16) + ('P' << 8) + 'B';
|
||||
|
||||
/** PSD Resource type identifier "8BIM" */
|
||||
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
|
||||
|
||||
// Blending modes
|
||||
/** Normal blending mode "norm"*/
|
||||
int BLEND_NORM = ('n' << 24) + ('o' << 16) + ('r' << 8) + 'm';
|
||||
|
||||
/** Darken blending mode "dark" */
|
||||
int BLEND_DARK = ('d' << 24) + ('a' << 16) + ('r' << 8) + 'k';
|
||||
|
||||
/** Lighten blending mode "lite" */
|
||||
int BLEND_LITE = ('l' << 24) + ('i' << 16) + ('t' << 8) + 'e';
|
||||
|
||||
/** Hue blending mode "hue " */
|
||||
int BLEND_HUE = ('h' << 24) + ('u' << 16) + ('e' << 8) + ' ';
|
||||
|
||||
/** Saturation blending mode "sat " */
|
||||
int BLEND_SAT = ('s' << 24) + ('a' << 16) + ('t' << 8) + ' ';
|
||||
|
||||
/** Color blending mode "colr" */
|
||||
int BLEND_COLR = ('c' << 24) + ('o' << 16) + ('l' << 8) + 'r';
|
||||
|
||||
/** Luminosity blending mode "lum " */
|
||||
int BLEND_LUM = ('l' << 24) + ('u' << 16) + ('m' << 8) + ' ';
|
||||
|
||||
/** Multiply blending mode "mul " */
|
||||
int BELND_MUL = ('m' << 24) + ('u' << 16) + ('l' << 8) + ' ';
|
||||
|
||||
/** Screen blending mode "scrn" */
|
||||
int BLEND_SCRN = ('s' << 24) + ('c' << 16) + ('r' << 8) + 'n';
|
||||
|
||||
/** Dissolve blending mode "diss" */
|
||||
int BLEND_DISS = ('d' << 24) + ('i' << 16) + ('s' << 8) + 's';
|
||||
|
||||
/** Overlay blending mode "over" */
|
||||
int BLEND_OVER = ('o' << 24) + ('v' << 16) + ('e' << 8) + 'r';
|
||||
|
||||
/** Hard light blending mode "hLit" */
|
||||
int BLEND_HLIT = ('h' << 24) + ('L' << 16) + ('i' << 8) + 't';
|
||||
|
||||
/** Soft light blending mode "sLit" */
|
||||
int BLEND_SLIT = ('s' << 24) + ('L' << 16) + ('i' << 8) + 't';
|
||||
|
||||
/** Difference blending mode "diff" */
|
||||
int BLEND_DIFF = ('d' << 24) + ('i' << 16) + ('f' << 8) + 'f';
|
||||
|
||||
// Compression modes
|
||||
/** No compression */
|
||||
int COMPRESSION_NONE = 0;
|
||||
|
||||
/** PacBits RLE compression */
|
||||
int COMPRESSION_RLE = 1;
|
||||
|
||||
/** ZIP compression */
|
||||
int COMPRESSION_ZIP = 2;
|
||||
|
||||
/** ZIP compression with prediction */
|
||||
int COMPRESSION_ZIP_PREDICTION = 3;
|
||||
|
||||
// Color Modes
|
||||
/** Bitmap (monochrome) */
|
||||
short COLOR_MODE_MONOCHROME = 0;
|
||||
|
||||
/** Gray-scale */
|
||||
short COLOR_MODE_GRAYSCALE = 1;
|
||||
|
||||
/** Indexed color (palette color) */
|
||||
short COLOR_MODE_INDEXED = 2;
|
||||
|
||||
/** RGB color */
|
||||
short COLOR_MODE_RGB = 3;
|
||||
|
||||
/** CMYK color */
|
||||
short COLOR_MODE_CMYK = 4;
|
||||
|
||||
/** Multichannel color */
|
||||
short COLOR_MODE_MULTICHANNEL = 7;
|
||||
|
||||
/** Duotone (halftone) */
|
||||
short COLOR_MODE_DUOTONE = 8;
|
||||
|
||||
/** Lab color */
|
||||
short COLOR_MODE_LAB = 9;
|
||||
|
||||
// TODO: Consider moving these constants to PSDImageResource
|
||||
// ID values 03e8, 03eb, 03ff, and 0403 are considered obsolete. Values 03e8 and 03eb are associated with
|
||||
// Photoshop v2.0. The data format for values 03f2, 03f4-03fa, 03fc, 03fd, 0405-0bb7 is intentionally not
|
||||
// documented by Adobe, or the data is missing.
|
||||
// Please refer to the Adobe Photoshop SDK for information on obtaining the IPTC-NAA record 2 structure definition.
|
||||
// WORD[5]
|
||||
/** Channels, rows, columns, depth, and mode (Obsolete?Photoshop 2.0 only). */
|
||||
int RES_CHANNELS_ROWS_COLUMNS_DEPTH_MODE = 0x03e8;
|
||||
|
||||
/** Optional Macintosh print manager information. */
|
||||
int RES_MAC_PRINT_MANAGER_INFO = 0x03e9;
|
||||
|
||||
/** Indexed color table (Obsolete?Photoshop 2.0 only). */
|
||||
int RES_INDEXED_COLOR_TABLE = 0x03eb;
|
||||
|
||||
/** Resolution information
|
||||
// ID value 03ed indicates that the data is in the form of a ResolutionInfo structure:
|
||||
//
|
||||
// typedef struct _ResolutionInfo
|
||||
// {
|
||||
// LONG hRes; // Fixed-point number: pixels per inch
|
||||
// WORD hResUnit; // 1=pixels per inch, 2=pixels per centimeter
|
||||
// WORD WidthUnit; // 1=in, 2=cm, 3=pt, 4=picas, 5=columns
|
||||
// LONG vRes; // Fixed-point number: pixels per inch/
|
||||
// WORD vResUnit; // 1=pixels per inch, 2=pixels per centimeter
|
||||
// WORD HeightUnit; // 1=in, 2=cm, 3=pt, 4=picas, 5=columns
|
||||
// } RESOLUTIONINFO;
|
||||
*/
|
||||
int RES_RESOLUTION_INFO = 0x3ed;
|
||||
|
||||
/** Alpha channel names (Pascal-format strings) */
|
||||
int RES_ALPHA_CHANNEL_INFO = 0x3ee;
|
||||
|
||||
/** Display information for each channel
|
||||
// ID value 03ef indicates that the data is stored as a DisplayInfo structure, which contains display information
|
||||
// associated with each channel:
|
||||
//
|
||||
// typedef _DisplayInfo
|
||||
// {
|
||||
// WORD ColorSpace;
|
||||
// WORD Color[4];
|
||||
// WORD Opacity; // 0-100
|
||||
// BYTE Kind; // 0=selected, 1=protected
|
||||
// BYTE Padding; // Always zero
|
||||
// } DISPLAYINFO;
|
||||
//
|
||||
*/
|
||||
int RES_DISPLAY_INFO = 0x3ef;
|
||||
|
||||
// 03f0
|
||||
// BYTE[]
|
||||
/** Optional Pascal-format caption string */
|
||||
int RES_CAPTION = 0x03f0;
|
||||
|
||||
// 03f1
|
||||
// LONG, WORD
|
||||
/** Fixed-point border width, border units */
|
||||
int RES_BORDER_WIDTH = 0x03f1;
|
||||
|
||||
// 03f2
|
||||
/** Background color */
|
||||
// 2 byte Color space: 0 = RGB (unsigned 16 bit), 1 = HSB (unsigned 16 bit), 2 = CMYK (unsigned 16 bit),
|
||||
// 3 = Pantone matching system (undocumented), 4 = Focoltone colour system (undocumented),
|
||||
// 5 = Truematch color (undocumented), 6 = Toyo 88 colorfinder 1050 (undocumented),
|
||||
// 7 = Lab (lighntess 0...10000, chrominance -12800..127000, 8 = Grayscale 0...10000,
|
||||
// 10 = HKS colors
|
||||
// 8 byte Color data: 6 first bytes used for RGB, HSB and Lab, all 8 for CMYK and only first two for grayscale
|
||||
int RES_BACKGROUND_COLOR = 0x03f2;
|
||||
|
||||
// 03f3
|
||||
// BYTE[8]
|
||||
/**
|
||||
* Print flags.
|
||||
* ID value 03f3 indicates that the data is a series of eight flags, indicating the enabled state of labels,
|
||||
* crop marks, color bars, registration marks, negative, flip, interpolate, and caption items in the
|
||||
* Photoshop Page Setup dialog box.
|
||||
*/
|
||||
int RES_PRINT_FLAGS = 0x03f3;
|
||||
|
||||
// 03f4
|
||||
/** Gray-scale and halftoning information */
|
||||
int RES_GRAYSCALE_HALFTONE_INFO = 0x03f4;
|
||||
|
||||
// 03f5
|
||||
/** Color halftoning information */
|
||||
int RES_COLOR_HALFTONE_INFO = 0x03f5;
|
||||
|
||||
// 03f6
|
||||
/** Duotone halftoning information */
|
||||
int RES_DUOTONE_HALFTONE_INFO = 0x03f6;
|
||||
|
||||
// 03f7
|
||||
/** Gray-scale and multichannel transfer function */
|
||||
int RES_GRAYSCALE_MULTICHANNEL_TRANSFER_FUNCTION = 0x03f7;
|
||||
|
||||
// 03f8
|
||||
/** Color transfer functions */
|
||||
int RES_COLOR_TRANSFER_FUNCITON = 0x03f8;
|
||||
|
||||
// 03f9
|
||||
/** Duotone transfer functions */
|
||||
int RES_DUOTONE_TRANSFER_FUNCITON = 0x03f9;
|
||||
|
||||
// 03fa
|
||||
/** Duotone image information */
|
||||
int RES_DUOTONE_IMAGE_INFO = 0x03fa;
|
||||
|
||||
// 03fb
|
||||
// BYTE[2]
|
||||
/** Effective black and white value for dot range */
|
||||
int RES_EFFECTIVE_BLACK_WHITE = 0x03fb;
|
||||
|
||||
// 03fc
|
||||
/** Obsolete undocumented resource. */
|
||||
int RES_03FC = 0x03fc;
|
||||
|
||||
// 03fd
|
||||
/** EPS options */
|
||||
int RES_EPS_OPTIONS = 0x03fd;
|
||||
|
||||
// 03fe
|
||||
// WORD, BYTE
|
||||
/** Quick Mask channel ID, flag for mask initially empty */
|
||||
int RES_QUICK_MASK_CHANNEL_ID = 0x03fe;
|
||||
|
||||
// 03ff
|
||||
/** Obsolete undocumented resource. */
|
||||
int RES_03ff = 0x03ff;
|
||||
|
||||
// 0400
|
||||
// WORD
|
||||
/** Index of target layer (0=bottom)*/
|
||||
int RES_INDEX_OF_TARGET_LAYER = 0x0400;
|
||||
|
||||
// 0401
|
||||
/** Working path */
|
||||
int RES_WORKING_PATH = 0x0401;
|
||||
|
||||
// 0402
|
||||
// WORD[]
|
||||
/** Layers group info, group ID for dragging groups */
|
||||
int RES_LAYERS_GROUP_INFO = 0x0402;
|
||||
|
||||
//
|
||||
// 0403
|
||||
/** Obsolete undocumented resource. */
|
||||
int RES_0403 = 0x0403;
|
||||
|
||||
// 0404
|
||||
/** IPTC-NAA record */
|
||||
int RES_IPTC_NAA = 0x0404;
|
||||
|
||||
// 0405
|
||||
/** Image mode for raw-format files */
|
||||
int RES_RAW_IMAGE_MODE = 0x0405;
|
||||
|
||||
// 0406
|
||||
/** JPEG quality (Adobe internal) */
|
||||
int RES_JPEG_QUALITY = 0x0406;
|
||||
|
||||
// 1032
|
||||
/** (Photoshop 4.0) Grid and guides information */
|
||||
int RES_GRID_AND_GUIDES_INFO = 0x0408;
|
||||
|
||||
// 1033
|
||||
/**
|
||||
* (Photoshop 4.0) Thumbnail resource for Photoshop 4.0 only. BGR layout. Obsolete.
|
||||
* @see #RES_THUMBNAIL
|
||||
*/
|
||||
int RES_THUMBNAIL_PS4 = 0x0409;
|
||||
|
||||
// 1034
|
||||
/**
|
||||
* (Photoshop 4.0) Copyright flag
|
||||
* Boolean indicating whether image is copyrighted. Can be set via
|
||||
* Property suite or by user in File Info...
|
||||
*/
|
||||
int RES_COPYRIGHT_FLAG = 0x040A;
|
||||
|
||||
// 1035
|
||||
/**
|
||||
* (Photoshop 4.0) URL
|
||||
* Handle of a text string with uniform resource locator. Can be set via
|
||||
* Property suite or by user in File Info...
|
||||
*/
|
||||
int RES_URL = 0x040B;
|
||||
|
||||
// 1036
|
||||
/** (Photoshop 5.0) Thumbnail resource (supersedes resource 1033) */
|
||||
int RES_THUMBNAIL = 0x040C;
|
||||
|
||||
// 1037
|
||||
/**
|
||||
* (Photoshop 5.0) Global Angle
|
||||
* 4 bytes that contain an integer between 0 and 359, which is the global
|
||||
* lighting angle for effects layer. If not present, assumed to be 30.
|
||||
*/
|
||||
int RES_GLOBAL_ANGLE = 0x040D;
|
||||
|
||||
// 1038
|
||||
/**
|
||||
* (Photoshop 5.0) Color samplers resource
|
||||
* See "Color samplers resource format" on page20.
|
||||
*/
|
||||
int RES_COLOR_SAMPLERS = 0x040E;
|
||||
|
||||
/**
|
||||
* (Photoshop 5.0) ICC Profile
|
||||
* The raw bytes of an ICC (International Color Consortium) format profile.
|
||||
*/
|
||||
int RES_ICC_PROFILE = 0x040f;
|
||||
|
||||
// 1040
|
||||
/**
|
||||
* (Photoshop 5.0) Watermark
|
||||
* One byte.
|
||||
*/
|
||||
int RES_WATERMARK = 0x0410;
|
||||
|
||||
// 1041
|
||||
/**
|
||||
* (Photoshop 5.0) ICC Untagged Profile
|
||||
* 1 byte that disables any assumed profile handling when opening the file.
|
||||
* 1 = intentionally untagged.
|
||||
*/
|
||||
int RES_ICC_UNTAGGED_PROFILE = 0x0411;
|
||||
|
||||
// 1042
|
||||
/**
|
||||
* (Photoshop 5.0) Effects visible
|
||||
* 1-byte global flag to show/hide all the effects layer. Only present when
|
||||
* they are hidden.
|
||||
*/
|
||||
int RES_EFFECTS_VISIBLE = 0x0412;
|
||||
|
||||
// 1043
|
||||
/**
|
||||
* (Photoshop 5.0) Spot Halftone
|
||||
* 4 bytes for version, 4 bytes for length, and the variable length data.
|
||||
*/
|
||||
int RES_SPOT_HALFTONE = 0x0413;
|
||||
|
||||
// 1044
|
||||
/**
|
||||
* (Photoshop 5.0) Document-specific IDs seed number
|
||||
* 4 bytes: Base value, starting at which layer IDs will be generated (or a
|
||||
* greater value if existing IDs already exceed it). Its purpose is to avoid the
|
||||
* case where we add layers, flatten, save, open, and then add more layers
|
||||
* that end up with the same IDs as the first set.
|
||||
*/
|
||||
int RES_DOC_ID_SEED = 0x0414;
|
||||
|
||||
// 1045
|
||||
/**
|
||||
* (Photoshop 5.0) Unicode Alpha Names
|
||||
* Unicode string (4 bytes length followed by string).
|
||||
*/
|
||||
int RES_UNICODE_ALPHA_NAME = 0x0415;
|
||||
|
||||
// 1046
|
||||
/**
|
||||
* (Photoshop 6.0) Indexed Color Table Count
|
||||
* 2 bytes for the number of colors in table that are actually defined
|
||||
*/
|
||||
int RES_INDEXED_COLOR_TABLE_COUNT = 0x0416;
|
||||
|
||||
//1047
|
||||
/**
|
||||
* (Photoshop 6.0) Transparency Index.
|
||||
* 2 bytes for the index of transparent color, if any.
|
||||
*/
|
||||
int RES_TRANSPARENCY_INDEX = 0x0417;
|
||||
|
||||
//1049
|
||||
/**
|
||||
* (Photoshop 6.0) Global Altitude
|
||||
* 4 byte entry for altitude
|
||||
*/
|
||||
int RES_GLOBAL_ALTITUDE = 0x0419;
|
||||
|
||||
//1050
|
||||
/**
|
||||
* (Photoshop 6.0) Slices
|
||||
*/
|
||||
int RES_SLICES = 0x041A;
|
||||
|
||||
//1051
|
||||
/**
|
||||
* (Photoshop 6.0) Workflow URL
|
||||
* Unicode string
|
||||
*/
|
||||
int RES_WORKFLOW_URL = 0x041B;
|
||||
|
||||
// 1052
|
||||
/**
|
||||
* (Photoshop 6.0) Jump To XPEP
|
||||
* 2 bytes major version, 2 bytes minor version, 4 bytes count. Following is
|
||||
* repeated for count: 4 bytes block size, 4 bytes key, if key = 'jtDd', then
|
||||
* next is a Boolean for the dirty flag; otherwise its a 4 byte entry for the
|
||||
* mod date.
|
||||
*/
|
||||
int RES_JUMP_TO_XPEP = 0x041C;
|
||||
|
||||
// 1053
|
||||
/**
|
||||
* (Photoshop 6.0) Alpha Identifiers
|
||||
* 4 bytes of length, followed by 4 bytes each for every alpha identifier.
|
||||
*/
|
||||
int RES_ALPHA_IDENTIFIERS = 0x041D;
|
||||
|
||||
// 1054
|
||||
/**
|
||||
* (Photoshop 6.0) URL List
|
||||
* 4 byte count of URLs, followed by 4 byte long, 4 byte ID, and Unicode
|
||||
* string for each count.
|
||||
*/
|
||||
int RES_URL_LIST = 0x041E;
|
||||
|
||||
// 1057
|
||||
/**
|
||||
* (Photoshop 6.0) Version Info
|
||||
* 4 bytes version, 1 byte hasRealMergedData, Unicode string: writer
|
||||
* name, Unicode string: reader name, 4 bytes file version.
|
||||
*/
|
||||
int RES_VERSION_INFO = 0x0421;
|
||||
|
||||
// 1058
|
||||
/**
|
||||
* (Photoshop 7.0) EXIF data 1
|
||||
*
|
||||
* @see <a href="http://www.pima.net/standards/it10/PIMA15740/exif.htm">EXIF standard</a>
|
||||
*/
|
||||
int RES_EXIF_DATA_1 = 0x0422;
|
||||
|
||||
//1059
|
||||
/**
|
||||
* (Photoshop 7.0) EXIF data 3
|
||||
*
|
||||
* @see <a href="http://www.pima.net/standards/it10/PIMA15740/exif.htm">EXIF standard</a>
|
||||
*/
|
||||
int RES_EXIF_DATA_3 = 0x0423;
|
||||
|
||||
//1060
|
||||
/**
|
||||
* (Photoshop 7.0) XMP metadata
|
||||
* File info as XML description.
|
||||
*
|
||||
* @see <a href="http://Partners.adobe.com/asn/developer/xmp/main.html">XMP standard</a>
|
||||
*/
|
||||
int RES_XMP_DATA = 0x0424;
|
||||
|
||||
// 1061
|
||||
/**
|
||||
* (Photoshop 7.0) Caption digest
|
||||
* 16 bytes: RSA Data Security, MD5 message-digest algorithm
|
||||
*/
|
||||
int RES_CAPTION_DIGEST = 0x0425;
|
||||
|
||||
// 1062
|
||||
/**
|
||||
* (Photoshop 7.0) Print scale
|
||||
* 2 bytes style (0 = centered, 1 = size to fit, 2 = user defined). 4 bytes x
|
||||
* location (floating point). 4 bytes y location (floating point). 4 bytes scale
|
||||
* (floating point)
|
||||
*/
|
||||
int RES_PRINT_SCALE = 0x0426;
|
||||
|
||||
// 1064
|
||||
/**
|
||||
* (Photoshop CS) Pixel Aspect Ratio
|
||||
* 4 bytes (version = 1), 8 bytes double, x / y of a pixel
|
||||
* 0x0429 1065 (Photoshop CS) Layer Comps
|
||||
* 4 bytes (descriptor version = 16), Descriptor (see ?Descriptor structure?
|
||||
* on page57)
|
||||
*/
|
||||
int RES_PIXEL_ASPECT_RATIO = 0x0428;
|
||||
|
||||
// 1066
|
||||
/**
|
||||
* (Photoshop CS) Alternate Duotone Colors
|
||||
* 2 bytes (version = 1), 2 bytes count, following is repeated for each count:
|
||||
* [ Color: 2 bytes for space followed by 4 * 2 byte color component ],
|
||||
* following this is another 2 byte count, usually 256, followed by Lab colors
|
||||
* one byte each for L, a, b
|
||||
* This resource is not read or used by Photoshop.
|
||||
*/
|
||||
int RES_ALTERNATE_DUOTONE_COLORS = 0x042A;
|
||||
|
||||
// 1067
|
||||
/**
|
||||
* (Photoshop CS) Alternate Spot Colors
|
||||
* 2 bytes (version = 1), 2 bytes channel count, following is repeated for
|
||||
* each count: 4 bytes channel ID, Color: 2 bytes for space followed by 4 * 2
|
||||
* byte color component
|
||||
* This resource is not read or used by Photoshop.
|
||||
*/
|
||||
int RES_ALTERNATE_SPOT_COLORS = 0x042B;
|
||||
|
||||
// 07d0-0bb6
|
||||
/* Saved path information */
|
||||
|
||||
// 0bb7
|
||||
/** Clipping path name */
|
||||
int RES_CLIPPING_PATH_NAME = 0x0bb7;
|
||||
|
||||
// 2710
|
||||
/** Print flags information
|
||||
* ID value 2710 signals that the Data section contains a WORD-length version number (should be 1),
|
||||
* a BYTE-length flag indicating crop marks, a BYTE-length field (should be 0), a LONG-length bleed width value, and a
|
||||
* WORD indicating the bleed width scale.
|
||||
*/
|
||||
int RES_PRINT_FLAGS_INFORMATION = 0x2710;
|
||||
|
||||
}
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PSDAlhpaChannelInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDAlhpaChannelInfo.java,v 1.0 May 2, 2008 5:33:40 PM haraldk Exp$
|
||||
*/
|
||||
class PSDAlphaChannelInfo extends PSDImageResource {
|
||||
List<String> mNames;
|
||||
|
||||
public PSDAlphaChannelInfo(short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
mNames = new ArrayList<String>();
|
||||
long left = mSize;
|
||||
while (left > 0) {
|
||||
String name = PSDUtil.readPascalString(pInput);
|
||||
mNames.add(name);
|
||||
left -= name.length() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
builder.append(", alpha channels: ").append(mNames).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
/**
|
||||
* PSDChannelInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 short mChannelId;
|
||||
final long mLength;
|
||||
|
||||
// typedef struct _CLI
|
||||
// {
|
||||
// WORD ChannelID; /* Channel Length Info field one */
|
||||
// LONG LengthOfChannelData; /* Channel Length Info field two */
|
||||
// } CLI;
|
||||
public PSDChannelInfo(short pChannelId, long pLength) {
|
||||
mChannelId = pChannelId;
|
||||
mLength = pLength;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
builder.append("[");
|
||||
builder.append("channelId: ").append(mChannelId);
|
||||
builder.append(", length: ").append(mLength);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
/**
|
||||
* PSDChannelSourceDestinationRange
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDChannelSourceDestinationRange.java,v 1.0 May 6, 2008 5:14:13 PM haraldk Exp$
|
||||
*/
|
||||
class PSDChannelSourceDestinationRange {
|
||||
private String mChannel;
|
||||
private short mSourceBlack;
|
||||
private short mSourceWhite;
|
||||
private short mDestBlack;
|
||||
private short mDestWhite;
|
||||
|
||||
public PSDChannelSourceDestinationRange(ImageInputStream pInput, String pChannel) throws IOException {
|
||||
mChannel = pChannel;
|
||||
mSourceBlack = pInput.readShort();
|
||||
mSourceWhite = pInput.readShort();
|
||||
mDestBlack = pInput.readShort();
|
||||
mDestWhite = pInput.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
|
||||
builder.append("[(").append(mChannel);
|
||||
builder.append("): sourceBlack: ").append(Integer.toHexString(mSourceBlack & 0xffff));
|
||||
builder.append(", sourceWhite: ").append(Integer.toHexString(mSourceWhite & 0xffff));
|
||||
builder.append(", destBlack: ").append(Integer.toHexString(mDestBlack & 0xffff));
|
||||
builder.append(", destWhite: ").append(Integer.toHexString(mDestWhite & 0xffff));
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.image.InverseColorMapIndexColorModel;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.image.DataBuffer;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDColorData
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 byte[] mColors;
|
||||
private IndexColorModel mColorModel;
|
||||
|
||||
PSDColorData(final ImageInputStream pInput) throws IOException {
|
||||
int length = pInput.readInt();
|
||||
if (length == 0) {
|
||||
throw new IIOException("No palette information in PSD");
|
||||
}
|
||||
else if (length % 3 != 0) {
|
||||
throw new IIOException("Wrong palette information in PSD");
|
||||
}
|
||||
|
||||
// NOTE: Spec says length may only be 768 bytes (256 RGB triplets)
|
||||
mColors = new byte[length];
|
||||
pInput.readFully(mColors);
|
||||
|
||||
// NOTE: Could be a padding byte here, if not even..
|
||||
}
|
||||
|
||||
IndexColorModel getIndexColorModel() {
|
||||
if (mColorModel == null) {
|
||||
int[] rgb = toInterleavedRGB(mColors);
|
||||
mColorModel = new InverseColorMapIndexColorModel(8, rgb.length, rgb, 0, false, -1, DataBuffer.TYPE_BYTE);
|
||||
}
|
||||
|
||||
return mColorModel;
|
||||
}
|
||||
|
||||
private static int[] toInterleavedRGB(final byte[] pColors) {
|
||||
int[] rgb = new int[pColors.length / 3];
|
||||
|
||||
for (int i = 0; i < rgb.length; i++) {
|
||||
// Pack the non-interleaved samples into interleaved form
|
||||
int r = pColors[ i] & 0xff;
|
||||
int g = pColors[ rgb.length + i] & 0xff;
|
||||
int b = pColors[2 * rgb.length + i] & 0xff;
|
||||
|
||||
rgb[i] = (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
}
|
||||
}
|
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDResolutionInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 {
|
||||
// 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
|
||||
//{
|
||||
// WORD ColorSpace;
|
||||
// WORD Color[4];
|
||||
// WORD Opacity; /* 0-100 */
|
||||
// BYTE Kind; /* 0=selected, 1=protected */
|
||||
// BYTE Padding; /* Always zero */
|
||||
//} DISPLAYINFO;
|
||||
|
||||
int mColorSpace;
|
||||
short[] mColors;
|
||||
short mOpacity;
|
||||
byte mKind;
|
||||
|
||||
PSDDisplayInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(ImageInputStream pInput) throws IOException {
|
||||
if (mSize % 14 != 0) {
|
||||
throw new IIOException("Display info length expected to be mod 14: " + mSize);
|
||||
}
|
||||
|
||||
// long left = mSize;
|
||||
// while (left > 0) {
|
||||
mColorSpace = pInput.readShort();
|
||||
|
||||
// Color[4]...?
|
||||
mColors = new short[4];
|
||||
mColors[0] = pInput.readShort();
|
||||
mColors[1] = pInput.readShort();
|
||||
mColors[2] = pInput.readShort();
|
||||
mColors[3] = pInput.readShort();
|
||||
|
||||
mOpacity = pInput.readShort();
|
||||
|
||||
mKind = pInput.readByte();
|
||||
|
||||
pInput.readByte(); // Pad
|
||||
// left -= 14;
|
||||
// }
|
||||
pInput.skipBytes(mSize - 14);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", ColorSpace: ").append(mColorSpace);
|
||||
builder.append(", Colors: {");
|
||||
builder.append(mColors[0]);
|
||||
builder.append(", ");
|
||||
builder.append(mColors[1]);
|
||||
builder.append(", ");
|
||||
builder.append(mColors[2]);
|
||||
builder.append(", ");
|
||||
builder.append(mColors[3]);
|
||||
builder.append("}, Opacity: ").append(mOpacity);
|
||||
builder.append(", Kind: ").append(kind(mKind));
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String kind(final byte pKind) {
|
||||
switch (pKind) {
|
||||
case 0:
|
||||
return "selected";
|
||||
case 1:
|
||||
return "protected";
|
||||
default:
|
||||
return "unknown kind: " + Integer.toHexString(pKind & 0xff);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,342 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.stream.MemoryCacheImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* EXIF metadata.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: XMPData.java,v 1.0 Jul 28, 2009 5:50:34 PM haraldk Exp$
|
||||
*
|
||||
* @see <a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format">Wikipedia</a>
|
||||
* @see <a href="http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif.html">Aware systems TIFF tag reference</a>
|
||||
* @see <a href="http://partners.adobe.com/public/developer/tiff/index.html">Adobe TIFF developer resources</a>
|
||||
*/
|
||||
final class PSDEXIF1Data extends PSDImageResource {
|
||||
// protected byte[] mData;
|
||||
protected Directory mDirectory;
|
||||
|
||||
PSDEXIF1Data(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
// This is in essence an embedded TIFF file.
|
||||
// TODO: Extract TIFF parsing to more general purpose package
|
||||
// TODO: Instead, read the byte data, store for later parsing (or store offset, and read on request)
|
||||
MemoryCacheImageInputStream stream = new MemoryCacheImageInputStream(IIOUtil.createStreamAdapter(pInput, mSize));
|
||||
|
||||
byte[] bom = new byte[2];
|
||||
stream.readFully(bom);
|
||||
if (bom[0] == 'I' && bom[1] == 'I') {
|
||||
stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
else if (!(bom[0] == 'M' && bom[1] == 'M')) {
|
||||
throw new IIOException(String.format("Invalid byte order marker '%s'", StringUtil.decode(bom, 0, bom.length, "ASCII")));
|
||||
}
|
||||
|
||||
if (stream.readUnsignedShort() != 42) {
|
||||
throw new IIOException("Wrong TIFF magic in EXIF data.");
|
||||
}
|
||||
|
||||
long directoryOffset = stream.readUnsignedInt();
|
||||
mDirectory = Directory.read(stream, directoryOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", ").append(mDirectory);
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
// TIFF Image file directory (IFD)
|
||||
static class Directory implements Iterable<Entry> {
|
||||
private List<Entry> mEntries = new ArrayList<Entry>();
|
||||
|
||||
private Directory() {}
|
||||
|
||||
public static Directory read(final ImageInputStream pInput, final long pOffset) throws IOException {
|
||||
Directory directory = new Directory();
|
||||
|
||||
pInput.seek(pOffset);
|
||||
int entryCount = pInput.readUnsignedShort();
|
||||
for (int i = 0; i < entryCount; i++) {
|
||||
directory.mEntries.add(Entry.read(pInput));
|
||||
}
|
||||
|
||||
long nextOffset = pInput.readUnsignedInt();
|
||||
if (nextOffset != 0) {
|
||||
Directory next = Directory.read(pInput, nextOffset);
|
||||
directory.mEntries.addAll(next.mEntries);
|
||||
}
|
||||
|
||||
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
|
||||
public String toString() {
|
||||
return String.format("Directory%s", mEntries);
|
||||
}
|
||||
}
|
||||
|
||||
// TIFF IFD Entry
|
||||
static class Entry {
|
||||
private static final int EXIF_IFD = 0x8769;
|
||||
|
||||
private final static String[] TYPE_NAMES = {
|
||||
"BYTE", "ASCII", "SHORT", "LONG", "RATIONAL",
|
||||
|
||||
"SBYTE", "UNDEFINED", "SSHORT", "SLONG", "SRATIONAL", "FLOAT", "DOUBLE",
|
||||
};
|
||||
|
||||
private final static int[] TYPE_LENGTHS = {
|
||||
1, 1, 2, 4, 8,
|
||||
|
||||
1, 1, 2, 4, 8, 4, 8,
|
||||
};
|
||||
|
||||
private int mTag;
|
||||
/*
|
||||
1 = BYTE 8-bit unsigned integer.
|
||||
2 = ASCII 8-bit byte that contains a 7-bit ASCII code; the last byte
|
||||
must be NUL (binary zero).
|
||||
3 = SHORT 16-bit (2-byte) unsigned integer.
|
||||
4 = LONG 32-bit (4-byte) unsigned integer.
|
||||
5 = RATIONAL Two LONGs: the first represents the numerator of a
|
||||
fraction; the second, the denominator.
|
||||
|
||||
TIFF 6.0 and above:
|
||||
6 = SBYTE An 8-bit signed (twos-complement) integer.
|
||||
7 = UNDEFINED An 8-bit byte that may contain anything, depending on
|
||||
the definition of the field.
|
||||
8 = SSHORT A 16-bit (2-byte) signed (twos-complement) integer.
|
||||
9 = SLONG A 32-bit (4-byte) signed (twos-complement) integer.
|
||||
10 = SRATIONAL Two SLONGs: the first represents the numerator of a
|
||||
fraction, the second the denominator.
|
||||
11 = FLOAT Single precision (4-byte) IEEE format.
|
||||
12 = DOUBLE Double precision (8-byte) IEEE format.
|
||||
*/
|
||||
private short mType;
|
||||
private int mCount;
|
||||
private long mValueOffset;
|
||||
private Object mValue;
|
||||
|
||||
private Entry() {}
|
||||
|
||||
public static Entry read(final ImageInputStream pInput) throws IOException {
|
||||
Entry entry = new Entry();
|
||||
|
||||
entry.mTag = pInput.readUnsignedShort();
|
||||
entry.mType = pInput.readShort();
|
||||
entry.mCount = pInput.readInt(); // Number of values
|
||||
|
||||
// TODO: Handle other sub-IFDs
|
||||
if (entry.mTag == EXIF_IFD) {
|
||||
long offset = pInput.readUnsignedInt();
|
||||
pInput.mark();
|
||||
try {
|
||||
entry.mValue = Directory.read(pInput, offset);
|
||||
}
|
||||
finally {
|
||||
pInput.reset();
|
||||
}
|
||||
}
|
||||
else {
|
||||
int valueLength = entry.getValueLength();
|
||||
if (valueLength > 0 && valueLength <= 4) {
|
||||
entry.readValueInLine(pInput);
|
||||
pInput.skipBytes(4 - valueLength);
|
||||
}
|
||||
else {
|
||||
entry.mValueOffset = pInput.readUnsignedInt(); // This is the *value* iff the value size is <= 4 bytes
|
||||
entry.readValue(pInput);
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
private void readValue(final ImageInputStream pInput) throws IOException {
|
||||
long pos = pInput.getStreamPosition();
|
||||
try {
|
||||
pInput.seek(mValueOffset);
|
||||
readValueInLine(pInput);
|
||||
}
|
||||
finally {
|
||||
pInput.seek(pos);
|
||||
}
|
||||
}
|
||||
|
||||
private void readValueInLine(ImageInputStream pInput) throws IOException {
|
||||
mValue = readValueDirect(pInput, mType, mCount);
|
||||
}
|
||||
|
||||
private static Object readValueDirect(final ImageInputStream pInput, final short pType, final int pCount) throws IOException {
|
||||
switch (pType) {
|
||||
case 2:
|
||||
// TODO: This might be UTF-8 or ISO-8859-1, even though against the spec
|
||||
byte[] ascii = new byte[pCount];
|
||||
pInput.readFully(ascii);
|
||||
return StringUtil.decode(ascii, 0, ascii.length, "ASCII");
|
||||
case 1:
|
||||
if (pCount == 1) {
|
||||
return pInput.readUnsignedByte();
|
||||
}
|
||||
case 6:
|
||||
if (pCount == 1) {
|
||||
return pInput.readByte();
|
||||
}
|
||||
case 7:
|
||||
byte[] bytes = new byte[pCount];
|
||||
pInput.readFully(bytes);
|
||||
return bytes;
|
||||
case 3:
|
||||
if (pCount == 1) {
|
||||
return pInput.readUnsignedShort();
|
||||
}
|
||||
case 8:
|
||||
if (pCount == 1) {
|
||||
return pInput.readShort();
|
||||
}
|
||||
|
||||
short[] shorts = new short[pCount];
|
||||
pInput.readFully(shorts, 0, shorts.length);
|
||||
return shorts;
|
||||
case 4:
|
||||
if (pCount == 1) {
|
||||
return pInput.readUnsignedInt();
|
||||
}
|
||||
case 9:
|
||||
if (pCount == 1) {
|
||||
return pInput.readInt();
|
||||
}
|
||||
|
||||
int[] ints = new int[pCount];
|
||||
pInput.readFully(ints, 0, ints.length);
|
||||
return ints;
|
||||
case 11:
|
||||
if (pCount == 1) {
|
||||
return pInput.readFloat();
|
||||
}
|
||||
|
||||
float[] floats = new float[pCount];
|
||||
pInput.readFully(floats, 0, floats.length);
|
||||
return floats;
|
||||
case 12:
|
||||
if (pCount == 1) {
|
||||
return pInput.readDouble();
|
||||
}
|
||||
|
||||
double[] doubles = new double[pCount];
|
||||
pInput.readFully(doubles, 0, doubles.length);
|
||||
return doubles;
|
||||
|
||||
// TODO: Consider using a Rational class
|
||||
case 5:
|
||||
if (pCount == 1) {
|
||||
return pInput.readUnsignedInt() / (double) pInput.readUnsignedInt();
|
||||
}
|
||||
|
||||
double[] rationals = new double[pCount];
|
||||
for (int i = 0; i < rationals.length; i++) {
|
||||
rationals[i] = pInput.readUnsignedInt() / (double) pInput.readUnsignedInt();
|
||||
}
|
||||
|
||||
return rationals;
|
||||
case 10:
|
||||
if (pCount == 1) {
|
||||
return pInput.readInt() / (double) pInput.readInt();
|
||||
}
|
||||
|
||||
double[] srationals = new double[pCount];
|
||||
for (int i = 0; i < srationals.length; i++) {
|
||||
srationals[i] = pInput.readInt() / (double) pInput.readInt();
|
||||
}
|
||||
|
||||
return srationals;
|
||||
|
||||
default:
|
||||
throw new IIOException(String.format("Unknown EXIF type '%s'", pType));
|
||||
}
|
||||
}
|
||||
|
||||
private int getValueLength() {
|
||||
if (mType > 0 && mType <= TYPE_LENGTHS.length) {
|
||||
return TYPE_LENGTHS[mType - 1] * mCount;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private String getTypeName() {
|
||||
if (mType > 0 && mType <= TYPE_NAMES.length) {
|
||||
return TYPE_NAMES[mType - 1];
|
||||
}
|
||||
return "Unknown type";
|
||||
}
|
||||
|
||||
// TODO: Tag names!
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("0x%04x: %s (%s, %d)", mTag, getValueAsString(), getTypeName(), mCount);
|
||||
}
|
||||
|
||||
public String getValueAsString() {
|
||||
if (mValue instanceof String) {
|
||||
return String.format("\"%s\"", mValue);
|
||||
}
|
||||
|
||||
if (mValue != null && mValue.getClass().isArray()) {
|
||||
Class<?> type = mValue.getClass().getComponentType();
|
||||
if (byte.class == type) {
|
||||
return Arrays.toString((byte[]) mValue);
|
||||
}
|
||||
if (short.class == type) {
|
||||
return Arrays.toString((short[]) mValue);
|
||||
}
|
||||
if (int.class == type) {
|
||||
return Arrays.toString((int[]) mValue);
|
||||
}
|
||||
if (float.class == type) {
|
||||
return Arrays.toString((float[]) mValue);
|
||||
}
|
||||
if (double.class == type) {
|
||||
return Arrays.toString((double[]) mValue);
|
||||
}
|
||||
}
|
||||
|
||||
return String.valueOf(mValue);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
/**
|
||||
* PSDGlobalLayerMask
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 int mColorSpace;
|
||||
final int mColor1;
|
||||
final int mColor2;
|
||||
final int mColor3;
|
||||
final int mColor4;
|
||||
final int mOpacity;
|
||||
final int mKind;
|
||||
|
||||
PSDGlobalLayerMask(final ImageInputStream pInput) throws IOException {
|
||||
mColorSpace = pInput.readUnsignedShort();
|
||||
|
||||
mColor1 = pInput.readUnsignedShort();
|
||||
mColor2 = pInput.readUnsignedShort();
|
||||
mColor3 = pInput.readUnsignedShort();
|
||||
mColor4 = pInput.readUnsignedShort();
|
||||
|
||||
mOpacity = pInput.readUnsignedShort();
|
||||
|
||||
mKind = pInput.readUnsignedByte();
|
||||
|
||||
pInput.readByte(); // Pad
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
builder.append("[");
|
||||
builder.append("color space: 0x").append(Integer.toHexString(mColorSpace));
|
||||
builder.append(", colors: [0x").append(Integer.toHexString(mColor1));
|
||||
builder.append(", 0x").append(Integer.toHexString(mColor2));
|
||||
builder.append(", 0x").append(Integer.toHexString(mColor3));
|
||||
builder.append(", 0x").append(Integer.toHexString(mColor4));
|
||||
builder.append("], opacity: ").append(mOpacity);
|
||||
builder.append(", kind: ").append(mKind);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDHeader
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDHeader.java,v 1.0 Apr 29, 2008 5:18:22 PM haraldk Exp$
|
||||
*/
|
||||
class PSDHeader {
|
||||
// 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 */
|
||||
// BYTE Reserved[6]; /* Reserved, must be zeroed */
|
||||
// WORD Channels; /* Number of color channels (1-24) 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) */
|
||||
// WORD Mode; /* Color mode */
|
||||
// } PSD_HEADER;
|
||||
|
||||
final short mChannels;
|
||||
final int mWidth;
|
||||
final int mHeight;
|
||||
final short mBits;
|
||||
final short mMode;
|
||||
|
||||
PSDHeader(final ImageInputStream 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) + ")");
|
||||
}
|
||||
|
||||
int version = pInput.readUnsignedShort();
|
||||
|
||||
switch (version) {
|
||||
case 1:
|
||||
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);
|
||||
|
||||
mChannels = pInput.readShort();
|
||||
mHeight = pInput.readInt(); // Rows
|
||||
mWidth = pInput.readInt(); // Columns
|
||||
mBits = pInput.readShort();
|
||||
mMode = pInput.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
builder.append("[Channels: ");
|
||||
builder.append(mChannels);
|
||||
builder.append(", width: ");
|
||||
builder.append(mWidth);
|
||||
builder.append(", height: ");
|
||||
builder.append(mHeight);
|
||||
builder.append(", depth: ");
|
||||
builder.append(mBits);
|
||||
builder.append(", mode: ");
|
||||
builder.append(mMode);
|
||||
switch (mMode) {
|
||||
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)");
|
||||
}
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.spi.ProviderInfo;
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* PSDImageReaderSpi
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 {
|
||||
|
||||
/**
|
||||
* Creates a {@code PSDImageReaderSpi}.
|
||||
*/
|
||||
public PSDImageReaderSpi() {
|
||||
this(IIOUtil.getProviderInfo(PSDImageReaderSpi.class));
|
||||
}
|
||||
|
||||
private PSDImageReaderSpi(final ProviderInfo pProviderInfo) {
|
||||
super(
|
||||
pProviderInfo.getVendorName(),
|
||||
pProviderInfo.getVersion(),
|
||||
new String[]{"psd", "PSD"},
|
||||
new String[]{"psd"},
|
||||
new String[]{
|
||||
"application/vnd.adobe.photoshop", // This one seems official, used in XMP
|
||||
"image/x-psd", "application/x-photoshop", "image/x-photoshop"
|
||||
},
|
||||
"com.twelvemkonkeys.imageio.plugins.psd.PSDImageReader",
|
||||
STANDARD_INPUT_TYPE,
|
||||
// new String[]{"com.twelvemkonkeys.imageio.plugins.psd.PSDImageWriterSpi"},
|
||||
null,
|
||||
true, // supports standard stream metadata
|
||||
null, null, // native stream format name and class
|
||||
null, null, // extra stream formats
|
||||
true, // supports standard image metadata
|
||||
PSDMetadata.NATIVE_METADATA_FORMAT_NAME, PSDMetadata.NATIVE_METADATA_FORMAT_CLASS_NAME,
|
||||
null, null // extra image metadata formats
|
||||
);
|
||||
}
|
||||
|
||||
public boolean canDecodeInput(final Object pSource) throws IOException {
|
||||
if (!(pSource instanceof ImageInputStream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ImageInputStream stream = (ImageInputStream) pSource;
|
||||
|
||||
stream.mark();
|
||||
try {
|
||||
return stream.readInt() == PSD.SIGNATURE_8BPS;
|
||||
// TODO: Test more of the header, see PSDImageReader#readHeader
|
||||
}
|
||||
finally {
|
||||
stream.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public ImageReader createReaderInstance(final Object pExtension) throws IOException {
|
||||
return new PSDImageReader(this);
|
||||
}
|
||||
|
||||
public String getDescription(final Locale pLocale) {
|
||||
return "Adobe Photoshop Document (PSD) image reader";
|
||||
}
|
||||
}
|
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.lang.StringUtil;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* PSDImageResource
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDImageResource.java,v 1.0 Apr 29, 2008 5:49:06 PM haraldk Exp$
|
||||
*/
|
||||
class PSDImageResource {
|
||||
final short mId;
|
||||
final String mName;
|
||||
final long mSize;
|
||||
|
||||
PSDImageResource(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
mId = pId;
|
||||
|
||||
mName = PSDUtil.readPascalString(pInput);
|
||||
|
||||
// Skip pad
|
||||
int nameSize = mName.length() + 1;
|
||||
if (nameSize % 2 != 0) {
|
||||
pInput.readByte();
|
||||
}
|
||||
|
||||
mSize = pInput.readUnsignedInt();
|
||||
readData(pInput);
|
||||
|
||||
// Data is even-padded
|
||||
if (mSize % 2 != 0) {
|
||||
pInput.read();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This default implementation simply skips the data.
|
||||
*
|
||||
* @param pInput the input
|
||||
* @throws IOException if an I/O exception occurs
|
||||
*/
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
// TODO: This design is ugly, as subclasses readData is invoked BEFORE their respective constructor...
|
||||
pInput.skipBytes(mSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", data length: ");
|
||||
builder.append(mSize);
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
protected StringBuilder toStringBuilder() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
|
||||
String fakeType = resourceTypeForId(mId);
|
||||
if (fakeType != null) {
|
||||
builder.append("(").append(fakeType).append(")");
|
||||
}
|
||||
|
||||
builder.append("[ID: 0x");
|
||||
builder.append(Integer.toHexString(mId));
|
||||
if (mName != null && mName.trim().length() != 0) {
|
||||
builder.append(", name: \"");
|
||||
builder.append(mName);
|
||||
builder.append("\"");
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static String resourceTypeForId(final short pId) {
|
||||
switch (pId) {
|
||||
case PSD.RES_RESOLUTION_INFO:
|
||||
case PSD.RES_ALPHA_CHANNEL_INFO:
|
||||
case PSD.RES_DISPLAY_INFO:
|
||||
case PSD.RES_PRINT_FLAGS:
|
||||
case PSD.RES_THUMBNAIL_PS4:
|
||||
case PSD.RES_THUMBNAIL:
|
||||
case PSD.RES_ICC_PROFILE:
|
||||
case PSD.RES_VERSION_INFO:
|
||||
case PSD.RES_EXIF_DATA_1:
|
||||
// case PSD.RES_EXIF_DATA_3:
|
||||
case PSD.RES_XMP_DATA:
|
||||
case PSD.RES_PRINT_FLAGS_INFORMATION:
|
||||
return null;
|
||||
default:
|
||||
try {
|
||||
for (Field field : PSD.class.getDeclaredFields()) {
|
||||
if (field.getName().startsWith("RES_") && field.getInt(null) == pId) {
|
||||
String name = field.getName().substring(4);
|
||||
return StringUtil.lispToCamel(name.replace("_", "-").toLowerCase(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IllegalAccessException ignore) {
|
||||
}
|
||||
|
||||
return "unknown resource";
|
||||
}
|
||||
}
|
||||
|
||||
public static PSDImageResource read(final ImageInputStream pInput) throws IOException {
|
||||
int type = pInput.readInt();
|
||||
if (type != PSD.RESOURCE_TYPE) {
|
||||
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.
|
||||
short id = pInput.readShort();
|
||||
switch (id) {
|
||||
case PSD.RES_RESOLUTION_INFO:
|
||||
return new PSDResolutionInfo(id, pInput);
|
||||
case PSD.RES_ALPHA_CHANNEL_INFO:
|
||||
return new PSDAlphaChannelInfo(id, pInput);
|
||||
case PSD.RES_DISPLAY_INFO:
|
||||
return new PSDDisplayInfo(id, pInput);
|
||||
case PSD.RES_PRINT_FLAGS:
|
||||
return new PSDPrintFlags(id, pInput);
|
||||
case PSD.RES_THUMBNAIL_PS4:
|
||||
case PSD.RES_THUMBNAIL:
|
||||
return new PSDThumbnail(id, pInput);
|
||||
case PSD.RES_ICC_PROFILE:
|
||||
return new ICCProfile(id, pInput);
|
||||
case PSD.RES_VERSION_INFO:
|
||||
return new PSDVersionInfo(id, pInput);
|
||||
case PSD.RES_EXIF_DATA_1:
|
||||
return new PSDEXIF1Data(id, pInput);
|
||||
case PSD.RES_XMP_DATA:
|
||||
return new PSDXMPData(id, pInput);
|
||||
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);
|
||||
}
|
||||
else {
|
||||
return new PSDImageResource(id, pInput);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDLayerBlendMode
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 int mBlendMode;
|
||||
final int mOpacity; // 0-255
|
||||
final int mClipping; // 0: base, 1: non-base
|
||||
final int mFlags;
|
||||
|
||||
public PSDLayerBlendMode(final ImageInputStream pInput) throws IOException {
|
||||
int blendModeSig = pInput.readInt();
|
||||
if (blendModeSig != PSD.RESOURCE_TYPE) { // TODO: Is this really just a resource?
|
||||
throw new IIOException("Illegal PSD Blend Mode signature, expected 8BIM: " + PSDUtil.intToStr(blendModeSig));
|
||||
}
|
||||
|
||||
mBlendMode = pInput.readInt();
|
||||
|
||||
mOpacity = pInput.readUnsignedByte();
|
||||
mClipping = pInput.readUnsignedByte();
|
||||
mFlags = pInput.readUnsignedByte();
|
||||
|
||||
pInput.readByte(); // Pad
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
|
||||
builder.append("[");
|
||||
builder.append("mode: \"").append(PSDUtil.intToStr(mBlendMode));
|
||||
builder.append("\", opacity: ").append(mOpacity);
|
||||
builder.append(", clipping: ").append(mClipping);
|
||||
switch (mClipping) {
|
||||
case 0:
|
||||
builder.append(" (base)");
|
||||
break;
|
||||
case 1:
|
||||
builder.append(" (non-base)");
|
||||
break;
|
||||
default:
|
||||
builder.append(" (unknown)");
|
||||
break;
|
||||
}
|
||||
builder.append(", flags: ").append(byteToBinary(mFlags));
|
||||
/*
|
||||
bit 0 = transparency protected; bit 1 = visible; bit 2 = obsolete;
|
||||
bit 3 = 1 for Photoshop 5.0 and later, tells if bit 4 has useful information;
|
||||
bit 4 = pixel data irrelevant to appearance of document
|
||||
*/
|
||||
builder.append(" (");
|
||||
if ((mFlags & 0x01) != 0) {
|
||||
builder.append("Transp. protected, ");
|
||||
}
|
||||
if ((mFlags & 0x02) != 0) {
|
||||
builder.append("Hidden, ");
|
||||
}
|
||||
if ((mFlags & 0x04) != 0) {
|
||||
builder.append("Obsolete bit, ");
|
||||
}
|
||||
if ((mFlags & 0x08) != 0) {
|
||||
builder.append("PS 5.0 data present, "); // "tells if next bit has useful information"...
|
||||
}
|
||||
if ((mFlags & 0x10) != 0) {
|
||||
builder.append("Pixel data irrelevant, ");
|
||||
}
|
||||
if ((mFlags & 0x20) != 0) {
|
||||
builder.append("Unknown bit 5, ");
|
||||
}
|
||||
if ((mFlags & 0x40) != 0) {
|
||||
builder.append("Unknown bit 6, ");
|
||||
}
|
||||
if ((mFlags & 0x80) != 0) {
|
||||
builder.append("Unknown bit 7, ");
|
||||
}
|
||||
|
||||
// Stupidity...
|
||||
if (mFlags != 0) {
|
||||
builder.delete(builder.length() - 2, builder.length());
|
||||
}
|
||||
|
||||
builder.append(")");
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static String byteToBinary(final int pFlags) {
|
||||
String flagStr = Integer.toBinaryString(pFlags);
|
||||
flagStr = "00000000".substring(flagStr.length()) + flagStr;
|
||||
return flagStr;
|
||||
}
|
||||
}
|
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* PSDLayerInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 int mTop;
|
||||
final int mLeft;
|
||||
final int mBottom;
|
||||
final int mRight;
|
||||
|
||||
final PSDChannelInfo[] mChannelInfo;
|
||||
final PSDLayerBlendMode mBlendMode;
|
||||
final PSDLayerMaskData mLayerMaskData;
|
||||
final PSDChannelSourceDestinationRange[] mRanges;
|
||||
final String mLayerName;
|
||||
|
||||
PSDLayerInfo(ImageInputStream pInput) throws IOException {
|
||||
mTop = pInput.readInt();
|
||||
mLeft = pInput.readInt();
|
||||
mBottom = pInput.readInt();
|
||||
mRight = pInput.readInt();
|
||||
|
||||
int channels = pInput.readUnsignedShort();
|
||||
|
||||
mChannelInfo = new PSDChannelInfo[channels];
|
||||
for (int i = 0; i < channels; i++) {
|
||||
short channelId = pInput.readShort();
|
||||
long length = pInput.readUnsignedInt();
|
||||
|
||||
mChannelInfo[i] = new PSDChannelInfo(channelId, length);
|
||||
}
|
||||
|
||||
mBlendMode = new PSDLayerBlendMode(pInput);
|
||||
|
||||
// Lenght of layer mask data
|
||||
long extraDataSize = pInput.readUnsignedInt();
|
||||
// TODO: Allow skipping the rest here?
|
||||
// pInput.skipBytes(extraDataSize);
|
||||
|
||||
// Layer mask/adjustment layer data
|
||||
int layerMaskDataSize = pInput.readInt(); // May be 0, 20 or 36 bytes...
|
||||
if (layerMaskDataSize != 0) {
|
||||
mLayerMaskData = new PSDLayerMaskData(pInput, layerMaskDataSize);
|
||||
}
|
||||
else {
|
||||
mLayerMaskData = null;
|
||||
}
|
||||
|
||||
int layerBlendingDataSize = pInput.readInt();
|
||||
if (layerBlendingDataSize % 8 != 0) {
|
||||
throw new IIOException("Illegal PSD Layer Blending Data size: " + layerBlendingDataSize + ", expected multiple of 8");
|
||||
}
|
||||
|
||||
mRanges = new PSDChannelSourceDestinationRange[layerBlendingDataSize / 8];
|
||||
for (int i = 0; i < mRanges.length; i++) {
|
||||
mRanges[i] = new PSDChannelSourceDestinationRange(pInput, (i == 0 ? "Gray" : "Channel " + (i - 1)));
|
||||
}
|
||||
|
||||
|
||||
mLayerName = PSDUtil.readPascalString(pInput);
|
||||
|
||||
int layerNameSize = mLayerName.length() + 1;
|
||||
|
||||
// Skip pad bytes for long word alignment
|
||||
if (layerNameSize % 4 != 0) {
|
||||
int skip = layerNameSize % 4;
|
||||
pInput.skipBytes(skip);
|
||||
layerNameSize += skip;
|
||||
}
|
||||
|
||||
// TODO: There's some data skipped here...
|
||||
// Adjustment layer info etc...
|
||||
pInput.skipBytes(extraDataSize - layerMaskDataSize - 4 - layerBlendingDataSize - 4 - layerNameSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
builder.append("[");
|
||||
builder.append("top: ").append(mTop);
|
||||
builder.append(", left: ").append(mLeft);
|
||||
builder.append(", bottom: ").append(mBottom);
|
||||
builder.append(", right: ").append(mRight);
|
||||
|
||||
builder.append(", channels: ").append(Arrays.toString(mChannelInfo));
|
||||
builder.append(", blend mode: ").append(mBlendMode);
|
||||
if (mLayerMaskData != null) {
|
||||
builder.append(", layer mask data: ").append(mLayerMaskData);
|
||||
}
|
||||
builder.append(", ranges: ").append(Arrays.toString(mRanges));
|
||||
builder.append(", layer name: \"").append(mLayerName).append("\"");
|
||||
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDLayerMaskData
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDLayerMaskData.java,v 1.0 May 6, 2008 5:15:05 PM haraldk Exp$
|
||||
*/
|
||||
class PSDLayerMaskData {
|
||||
private int mTop;
|
||||
private int mLeft;
|
||||
private int mBottom;
|
||||
private int mRight;
|
||||
private int mDefaultColor;
|
||||
private int mFlags;
|
||||
|
||||
private boolean mLarge;
|
||||
private int mRealFlags;
|
||||
private int mRealUserBackground;
|
||||
private int mRealTop;
|
||||
private int mRealLeft;
|
||||
private int mRealBottom;
|
||||
private int mRealRight;
|
||||
|
||||
PSDLayerMaskData(ImageInputStream pInput, int pSize) throws IOException {
|
||||
if (pSize != 20 && pSize != 36) {
|
||||
throw new IIOException("Illegal PSD Layer Mask data size: " + pSize + " (expeced 20 or 36)");
|
||||
}
|
||||
mTop = pInput.readInt();
|
||||
mLeft = pInput.readInt();
|
||||
mBottom = pInput.readInt();
|
||||
mRight = pInput.readInt();
|
||||
|
||||
mDefaultColor = pInput.readUnsignedByte();
|
||||
|
||||
mFlags = pInput.readUnsignedByte();
|
||||
|
||||
if (pSize == 20) {
|
||||
pInput.readShort(); // Pad
|
||||
}
|
||||
else {
|
||||
// TODO: What to make out of this?
|
||||
mLarge = true;
|
||||
|
||||
mRealFlags = pInput.readUnsignedByte();
|
||||
mRealUserBackground = pInput.readUnsignedByte();
|
||||
|
||||
mRealTop = pInput.readInt();
|
||||
mRealLeft = pInput.readInt();
|
||||
mRealBottom = pInput.readInt();
|
||||
mRealRight = pInput.readInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = new StringBuilder(getClass().getSimpleName());
|
||||
builder.append("[");
|
||||
builder.append("top: ").append(mTop);
|
||||
builder.append(", left: ").append(mLeft);
|
||||
builder.append(", bottom: ").append(mBottom);
|
||||
builder.append(", right: ").append(mRight);
|
||||
builder.append(", default color: ").append(mDefaultColor);
|
||||
builder.append(", flags: ").append(Integer.toBinaryString(mFlags));
|
||||
|
||||
// TODO: Maybe the flag bits have oposite order?
|
||||
builder.append(" (");
|
||||
if ((mFlags & 0x01) != 0) {
|
||||
builder.append("Pos. rel. to layer");
|
||||
}
|
||||
else {
|
||||
builder.append("Pos. abs.");
|
||||
}
|
||||
if ((mFlags & 0x02) != 0) {
|
||||
builder.append(", Mask disabled");
|
||||
}
|
||||
else {
|
||||
builder.append(", Mask enabled");
|
||||
}
|
||||
if ((mFlags & 0x04) != 0) {
|
||||
builder.append(", Invert mask");
|
||||
}
|
||||
if ((mFlags & 0x08) != 0) {
|
||||
builder.append(", Unknown bit 3");
|
||||
}
|
||||
if ((mFlags & 0x10) != 0) {
|
||||
builder.append(", Unknown bit 4");
|
||||
}
|
||||
if ((mFlags & 0x20) != 0) {
|
||||
builder.append(", Unknown bit 5");
|
||||
}
|
||||
if ((mFlags & 0x40) != 0) {
|
||||
builder.append(", Unknown bit 6");
|
||||
}
|
||||
if ((mFlags & 0x80) != 0) {
|
||||
builder.append(", Unknown bit 7");
|
||||
}
|
||||
builder.append(")");
|
||||
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,611 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
import com.twelvemonkeys.util.FilterIterator;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.xml.sax.InputSource;
|
||||
|
||||
import javax.imageio.metadata.IIOInvalidTreeException;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import java.awt.image.IndexColorModel;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PSDMetadata
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDMetadata.java,v 1.0 Nov 4, 2009 5:28:12 PM haraldk Exp$
|
||||
*/
|
||||
public final class PSDMetadata extends IIOMetadata implements Cloneable {
|
||||
|
||||
// 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";
|
||||
|
||||
PSDHeader mHeader;
|
||||
PSDColorData mColorData;
|
||||
int mCompression = -1;
|
||||
List<PSDImageResource> mImageResources;
|
||||
PSDGlobalLayerMask mGlobalLayerMask;
|
||||
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() {
|
||||
// TODO: Allow XMP, EXIF and IPTC as extra formats?
|
||||
super(true, NATIVE_METADATA_FORMAT_NAME, NATIVE_METADATA_FORMAT_CLASS_NAME, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReadOnly() {
|
||||
// TODO: Extract to abstract metadata impl class?
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getAsTree(final String pFormatName) {
|
||||
validateFormatName(pFormatName);
|
||||
|
||||
if (pFormatName.equals(nativeMetadataFormatName)) {
|
||||
return getNativeTree();
|
||||
}
|
||||
else if (pFormatName.equals(IIOMetadataFormatImpl.standardMetadataFormatName)) {
|
||||
return getStandardTree();
|
||||
}
|
||||
|
||||
throw new AssertionError("Unreachable");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mergeTree(final String pFormatName, final Node pRoot) throws IIOInvalidTreeException {
|
||||
// TODO: Extract to abstract metadata impl class?
|
||||
assertMutable();
|
||||
|
||||
validateFormatName(pFormatName);
|
||||
|
||||
if (!pRoot.getNodeName().equals(nativeMetadataFormatName)) {
|
||||
throw new IIOInvalidTreeException("Root must be " + nativeMetadataFormatName, pRoot);
|
||||
}
|
||||
|
||||
Node node = pRoot.getFirstChild();
|
||||
while (node != null) {
|
||||
// TODO: Merge values from node into this
|
||||
|
||||
// Move to the next sibling
|
||||
node = node.getNextSibling();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
// TODO: Extract to abstract metadata impl class?
|
||||
assertMutable();
|
||||
|
||||
throw new UnsupportedOperationException("Method reset not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
// TODO: Extract to abstract metadata impl class?
|
||||
private void assertMutable() {
|
||||
if (isReadOnly()) {
|
||||
throw new IllegalStateException("Metadata is read-only");
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Extract to abstract metadata impl class?
|
||||
private void validateFormatName(final String pFormatName) {
|
||||
String[] metadataFormatNames = getMetadataFormatNames();
|
||||
|
||||
if (metadataFormatNames != null) {
|
||||
for (String metadataFormatName : metadataFormatNames) {
|
||||
if (metadataFormatName.equals(pFormatName)) {
|
||||
return; // Found, we're ok!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Bad format name: \"%s\". Expected one of %s", pFormatName, Arrays.toString(metadataFormatNames))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
// TODO: Make it a deep clone
|
||||
try {
|
||||
return super.clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/// Native format support
|
||||
|
||||
private Node 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
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardChromaNode() {
|
||||
IIOMetadataNode chroma_node = new IIOMetadataNode("Chroma");
|
||||
IIOMetadataNode node; // scratch node
|
||||
|
||||
node = new IIOMetadataNode("ColorSpaceType");
|
||||
String cs;
|
||||
switch (mHeader.mMode) {
|
||||
case PSD.COLOR_MODE_MONOCHROME:
|
||||
case PSD.COLOR_MODE_GRAYSCALE:
|
||||
case PSD.COLOR_MODE_DUOTONE: // Rationale: Spec says treat as gray...
|
||||
cs = "GRAY";
|
||||
break;
|
||||
case PSD.COLOR_MODE_RGB:
|
||||
case PSD.COLOR_MODE_INDEXED:
|
||||
cs = "RGB";
|
||||
break;
|
||||
case PSD.COLOR_MODE_CMYK:
|
||||
cs = "CMYK";
|
||||
break;
|
||||
case PSD.COLOR_MODE_MULTICHANNEL:
|
||||
cs = getMultiChannelCS(mHeader.mChannels);
|
||||
break;
|
||||
case PSD.COLOR_MODE_LAB:
|
||||
cs = "Lab";
|
||||
break;
|
||||
default:
|
||||
throw new AssertionError("Unreachable");
|
||||
}
|
||||
node.setAttribute("name", cs);
|
||||
chroma_node.appendChild(node);
|
||||
|
||||
// TODO: Channels might be 5 for RGB + A + Mask... Probably not correct
|
||||
node = new IIOMetadataNode("NumChannels");
|
||||
node.setAttribute("value", Integer.toString(mHeader.mChannels));
|
||||
chroma_node.appendChild(node);
|
||||
|
||||
// TODO: Check if this is correct with bitmap (monchrome)
|
||||
node = new IIOMetadataNode("BlackIsZero");
|
||||
node.setAttribute("value", "true");
|
||||
chroma_node.appendChild(node);
|
||||
|
||||
if (mHeader.mMode == PSD.COLOR_MODE_INDEXED) {
|
||||
node = createPaletteNode();
|
||||
chroma_node.appendChild(node);
|
||||
}
|
||||
|
||||
// TODO: Hardcode background color to white?
|
||||
// if (bKGD_present) {
|
||||
// if (bKGD_colorType == PNGImageReader.PNG_COLOR_PALETTE) {
|
||||
// node = new IIOMetadataNode("BackgroundIndex");
|
||||
// node.setAttribute("value", Integer.toString(bKGD_index));
|
||||
// } else {
|
||||
// node = new IIOMetadataNode("BackgroundColor");
|
||||
// int r, g, b;
|
||||
//
|
||||
// if (bKGD_colorType == PNGImageReader.PNG_COLOR_GRAY) {
|
||||
// r = g = b = bKGD_gray;
|
||||
// } else {
|
||||
// r = bKGD_red;
|
||||
// g = bKGD_green;
|
||||
// b = bKGD_blue;
|
||||
// }
|
||||
// node.setAttribute("red", Integer.toString(r));
|
||||
// node.setAttribute("green", Integer.toString(g));
|
||||
// node.setAttribute("blue", Integer.toString(b));
|
||||
// }
|
||||
// chroma_node.appendChild(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
|
||||
protected IIOMetadataNode getStandardCompressionNode() {
|
||||
IIOMetadataNode compression_node = new IIOMetadataNode("Compression");
|
||||
IIOMetadataNode node; // scratch node
|
||||
|
||||
node = new IIOMetadataNode("CompressionTypeName");
|
||||
String compression;
|
||||
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);
|
||||
|
||||
node = new IIOMetadataNode("Lossless");
|
||||
node.setAttribute("value", "true");
|
||||
compression_node.appendChild(node);
|
||||
|
||||
return compression_node;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardDataNode() {
|
||||
IIOMetadataNode data_node = new IIOMetadataNode("Data");
|
||||
IIOMetadataNode node; // scratch node
|
||||
|
||||
node = new IIOMetadataNode("PlanarConfiguration");
|
||||
node.setAttribute("value", "PlaneInterleaved"); // TODO: Check with spec
|
||||
data_node.appendChild(node);
|
||||
|
||||
node = new IIOMetadataNode("SampleFormat");
|
||||
node.setAttribute("value", mHeader.mMode == PSD.COLOR_MODE_INDEXED ? "Index" : "UnsignedIntegral");
|
||||
data_node.appendChild(node);
|
||||
|
||||
String bitDepth = Integer.toString(mHeader.mBits); // bits per plane
|
||||
// TODO: Channels might be 5 for RGB + A + Mask...
|
||||
String[] bps = new String[mHeader.mChannels];
|
||||
Arrays.fill(bps, bitDepth);
|
||||
|
||||
node = new IIOMetadataNode("BitsPerSample");
|
||||
node.setAttribute("value", StringUtil.toCSVString(bps, " "));
|
||||
data_node.appendChild(node);
|
||||
|
||||
// TODO: SampleMSB? Or is network (aka Motorola/big endian) byte order assumed?
|
||||
|
||||
return data_node;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardDimensionNode() {
|
||||
IIOMetadataNode dimension_node = new IIOMetadataNode("Dimension");
|
||||
IIOMetadataNode node; // scratch node
|
||||
|
||||
node = new IIOMetadataNode("PixelAspectRatio");
|
||||
// TODO: This is not incorrect wrt resolution info
|
||||
float ratio = 1f;
|
||||
node.setAttribute("value", Float.toString(ratio));
|
||||
dimension_node.appendChild(node);
|
||||
|
||||
node = new IIOMetadataNode("ImageOrientation");
|
||||
node.setAttribute("value", "Normal");
|
||||
dimension_node.appendChild(node);
|
||||
|
||||
Iterator<PSDResolutionInfo> resolutionInfos = getResources(PSDResolutionInfo.class);
|
||||
if (!resolutionInfos.hasNext()) {
|
||||
PSDResolutionInfo resolutionInfo = resolutionInfos.next();
|
||||
|
||||
node = new IIOMetadataNode("HorizontalPixelSize");
|
||||
node.setAttribute("value", Float.toString(asMM(resolutionInfo.mHResUnit, resolutionInfo.mHRes)));
|
||||
dimension_node.appendChild(node);
|
||||
|
||||
node = new IIOMetadataNode("VerticalPixelSize");
|
||||
node.setAttribute("value", Float.toString(asMM(resolutionInfo.mVResUnit, resolutionInfo.mVRes)));
|
||||
dimension_node.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 dimension_node;
|
||||
}
|
||||
|
||||
private static float asMM(final short pUnit, final float pResolution) {
|
||||
// Unit: 1 -> pixels per inch, 2 -> pixels pr cm
|
||||
return (pUnit == 1 ? 25.4f : 10) / pResolution;
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
// Get EXIF data if present
|
||||
Iterator<PSDEXIF1Data> exif = getResources(PSDEXIF1Data.class);
|
||||
if (exif.hasNext()) {
|
||||
PSDEXIF1Data data = exif.next();
|
||||
|
||||
// Get the EXIF DateTime (aka ModifyDate) tag if present
|
||||
PSDEXIF1Data.Entry dateTime = data.mDirectory.get(0x0132); // TODO: Constant
|
||||
if (dateTime != null) {
|
||||
node = new IIOMetadataNode("ImageModificationTime");
|
||||
// Format: "YYYY:MM:DD hh:mm:ss" (with quotes! :-P)
|
||||
String value = dateTime.getValueAsString();
|
||||
|
||||
node.setAttribute("year", value.substring(1, 5));
|
||||
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
|
||||
protected IIOMetadataNode getStandardTextNode() {
|
||||
// TODO: CaptionDigest?, EXIF, XMP
|
||||
|
||||
Iterator<PSDImageResource> textResources = getResources(PSDEXIF1Data.class, PSDXMPData.class);
|
||||
|
||||
while (textResources.hasNext()) {
|
||||
PSDImageResource textResource = textResources.next();
|
||||
|
||||
}
|
||||
|
||||
// int numEntries = tEXt_keyword.size() +
|
||||
// iTXt_keyword.size() + zTXt_keyword.size();
|
||||
// if (numEntries == 0) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// IIOMetadataNode text_node = new IIOMetadataNode("Text");
|
||||
// IIOMetadataNode node = null; // scratch node
|
||||
//
|
||||
// for (int i = 0; i < tEXt_keyword.size(); i++) {
|
||||
// node = new IIOMetadataNode("TextEntry");
|
||||
// node.setAttribute("keyword", (String)tEXt_keyword.get(i));
|
||||
// node.setAttribute("value", (String)tEXt_text.get(i));
|
||||
// node.setAttribute("encoding", "ISO-8859-1");
|
||||
// node.setAttribute("compression", "none");
|
||||
//
|
||||
// text_node.appendChild(node);
|
||||
// }
|
||||
//
|
||||
// for (int i = 0; i < iTXt_keyword.size(); i++) {
|
||||
// node = new IIOMetadataNode("TextEntry");
|
||||
// node.setAttribute("keyword", iTXt_keyword.get(i));
|
||||
// node.setAttribute("value", iTXt_text.get(i));
|
||||
// node.setAttribute("language",
|
||||
// iTXt_languageTag.get(i));
|
||||
// if (iTXt_compressionFlag.get(i)) {
|
||||
// node.setAttribute("compression", "deflate");
|
||||
// } else {
|
||||
// node.setAttribute("compression", "none");
|
||||
// }
|
||||
//
|
||||
// text_node.appendChild(node);
|
||||
// }
|
||||
//
|
||||
// for (int i = 0; i < zTXt_keyword.size(); i++) {
|
||||
// node = new IIOMetadataNode("TextEntry");
|
||||
// node.setAttribute("keyword", (String)zTXt_keyword.get(i));
|
||||
// node.setAttribute("value", (String)zTXt_text.get(i));
|
||||
// node.setAttribute("compression", "deflate");
|
||||
//
|
||||
// text_node.appendChild(node);
|
||||
// }
|
||||
//
|
||||
// return text_node;
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardTileNode() {
|
||||
return super.getStandardTileNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIOMetadataNode getStandardTransparencyNode() {
|
||||
IIOMetadataNode transparency_node = new IIOMetadataNode("Transparency");
|
||||
IIOMetadataNode node; // scratch node
|
||||
|
||||
node = new IIOMetadataNode("Alpha");
|
||||
node.setAttribute("value", hasAlpha() ? "nonpremultipled" : "none"); // TODO: Check spec
|
||||
transparency_node.appendChild(node);
|
||||
|
||||
return transparency_node;
|
||||
}
|
||||
|
||||
private boolean hasAlpha() {
|
||||
return mHeader.mMode == PSD.COLOR_MODE_RGB && mHeader.mChannels >= 4 ||
|
||||
mHeader.mMode == PSD.COLOR_MODE_CMYK & mHeader.mChannels >= 5;
|
||||
}
|
||||
|
||||
<T extends PSDImageResource> Iterator<T> getResources(final Class<T> pResourceType) {
|
||||
// NOTE: The cast here is wrong, strictly speaking, but it does not matter...
|
||||
@SuppressWarnings({"unchecked"})
|
||||
Iterator<T> iterator = (Iterator<T>) mImageResources.iterator();
|
||||
|
||||
return new FilterIterator<T>(iterator, new FilterIterator.Filter<T>() {
|
||||
public boolean accept(final T pElement) {
|
||||
return pResourceType.isInstance(pElement);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@@ -0,0 +1,164 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadataFormatImpl;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* PSDMetadataFormat
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDMetadataFormat.java,v 1.0 Nov 4, 2009 5:27:53 PM haraldk Exp$
|
||||
*/
|
||||
public final class PSDMetadataFormat extends IIOMetadataFormatImpl {
|
||||
|
||||
private final static PSDMetadataFormat sInstance = new PSDMetadataFormat();
|
||||
|
||||
/**
|
||||
* Private constructor.
|
||||
* <p/>
|
||||
* The {@link javax.imageio.metadata.IIOMetadata} class will instantiate this class
|
||||
* by reflection, invoking the static {@code getInstance()} method.
|
||||
*
|
||||
* @see javax.imageio.metadata.IIOMetadata#getMetadataFormat
|
||||
* @see #getInstance()
|
||||
*/
|
||||
private PSDMetadataFormat() {
|
||||
// Defines the root element
|
||||
super(PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_SOME);
|
||||
|
||||
// root -> PSDHeader
|
||||
// TODO: How do I specify that the header is required?
|
||||
addElement("PSDHeader", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_EMPTY);
|
||||
|
||||
// TODO: Do the first two make sense?
|
||||
// addAttribute("PSDHeader", "signature", DATATYPE_STRING, false, "8BPS", Arrays.asList("8BPS"));
|
||||
addAttribute("PSDHeader", "version", DATATYPE_INTEGER, false, "1", Arrays.asList("1"));
|
||||
|
||||
addAttribute("PSDHeader", "channels", DATATYPE_INTEGER, true, null, "1", "24", true, true);
|
||||
// rows?
|
||||
addAttribute("PSDHeader", "height", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
||||
// columns?
|
||||
addAttribute("PSDHeader", "width", DATATYPE_INTEGER, true, null, "1", "30000", true, true);
|
||||
addAttribute("PSDHeader", "bits", DATATYPE_INTEGER, true, null, Arrays.asList("1", "8", "16"));
|
||||
// TODO: Consider using more readable names?!
|
||||
addAttribute("PSDHeader", "mode", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.COLOR_MODES));
|
||||
|
||||
/*
|
||||
Contains the required data to define the color mode.
|
||||
|
||||
For indexed color images, the count will be equal to 768, and the mode data
|
||||
will contain the color table for the image, in non-interleaved order.
|
||||
|
||||
For duotone images, the mode data will contain the duotone specification,
|
||||
the format of which is not documented. Non-Photoshop readers can treat
|
||||
the duotone image as a grayscale image, and keep the duotone specification
|
||||
around as a black box for use when saving the file.
|
||||
*/
|
||||
// root -> Palette
|
||||
// Color map for indexed, optional
|
||||
// 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?
|
||||
addElement("Palette", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, 256, 256); // 768 = 256 * 3
|
||||
addElement("PaletteEntry", "Palette", CHILD_POLICY_EMPTY);
|
||||
addAttribute("PaletteEntry", "index", 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", "blue", DATATYPE_INTEGER, true, null, "0", "255", true, true);
|
||||
// No alpha allowed in indexed color PSD
|
||||
|
||||
// TODO: Duotone spec, optional (use same element as palette?)
|
||||
// Or use object or raw bytes..
|
||||
|
||||
// root -> ImageResources
|
||||
// Image resources, optional
|
||||
addElement("ImageResources", PSDMetadata.NATIVE_METADATA_FORMAT_NAME, CHILD_POLICY_SEQUENCE); // SOME?
|
||||
|
||||
// root -> ImageResources -> ImageResource
|
||||
// Generic resource
|
||||
addElement("ImageResource", "ImageResources", CHILD_POLICY_ALL);
|
||||
// TODO: Allow arbitrary values to be added as a generic resource...
|
||||
|
||||
// root -> ImageResources -> AlphaChannelInfo
|
||||
addElement("AlphaChannelInfo", "ImageResources", 0, Integer.MAX_VALUE); // The format probably does not support that many layers..
|
||||
addElement("Name", "AlphaChannelInfo", CHILD_POLICY_EMPTY);
|
||||
addAttribute("Name", "value", DATATYPE_STRING, true, 0, Integer.MAX_VALUE);
|
||||
|
||||
// root -> ImageResources -> DisplayInfo
|
||||
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", "colors", DATATYPE_INTEGER, true, 4, 4);
|
||||
addAttribute("DisplayInfo", "opacity", DATATYPE_INTEGER, true, null, "0", "100", true, true);
|
||||
// TODO: Consider using human readable strings
|
||||
addAttribute("DisplayInfo", "kind", DATATYPE_INTEGER, true, null, Arrays.asList(PSDMetadata.DISPLAY_INFO_KINDS));
|
||||
|
||||
// root -> ImageResources -> EXIF1Data
|
||||
addElement("EXIF1Data", "ImageResources", CHILD_POLICY_ALL);
|
||||
// TODO: Incorporate EXIF / TIFF metadata here somehow... (or treat as opaque bytes?)
|
||||
|
||||
// root -> ImageResources -> PrintFlags
|
||||
addElement("PrintFlags", "ImageResources", CHILD_POLICY_EMPTY);
|
||||
addBooleanAttribute("PrintFlags", "labels", false, false);
|
||||
addBooleanAttribute("PrintFlags", "cropMasks", false, false);
|
||||
addBooleanAttribute("PrintFlags", "colorBars", false, false);
|
||||
addBooleanAttribute("PrintFlags", "registrationMarks", false, false);
|
||||
addBooleanAttribute("PrintFlags", "negative", false, false);
|
||||
addBooleanAttribute("PrintFlags", "flip", false, false);
|
||||
addBooleanAttribute("PrintFlags", "interpolate", false, false);
|
||||
addBooleanAttribute("PrintFlags", "caption", false, false);
|
||||
|
||||
// root -> ImageResources -> PrintFlagsInformation
|
||||
addElement("PrintFlagsInformation", "ImageResources", CHILD_POLICY_EMPTY);
|
||||
addAttribute("PrintFlagsInformation", "version", DATATYPE_INTEGER, true, null);
|
||||
addBooleanAttribute("PrintFlagsInformation", "cropMarks", false, false);
|
||||
addAttribute("PrintFlagsInformation", "field", DATATYPE_INTEGER, true, null);
|
||||
addAttribute("PrintFlagsInformation", "bleedWidth", DATATYPE_INTEGER, true, null, "0", String.valueOf(Long.MAX_VALUE), true, true); // TODO: LONG??!
|
||||
addAttribute("PrintFlagsInformation", "bleedScale", DATATYPE_INTEGER, true, null, "0", String.valueOf(Integer.MAX_VALUE), true, true);
|
||||
|
||||
// root -> ImageResources -> ResolutionInfo
|
||||
addElement("ResolutionInfo", "ImageResources", CHILD_POLICY_EMPTY);
|
||||
addAttribute("ResolutionInfo", "hRes", DATATYPE_FLOAT, true, null);
|
||||
// TODO: Or use string and more friendly names? "pixels/inch"/"pixels/cm" and "inch"/"cm"/"pt"/"pica"/"column"
|
||||
addAttribute("ResolutionInfo", "hResUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2"));
|
||||
addAttribute("ResolutionInfo", "widthUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2", "3", "4", "5"));
|
||||
addAttribute("ResolutionInfo", "vRes", DATATYPE_FLOAT, true, null);
|
||||
// TODO: Or use more friendly names?
|
||||
addAttribute("ResolutionInfo", "vResUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2"));
|
||||
addAttribute("ResolutionInfo", "heightUnit", DATATYPE_INTEGER, true, null, Arrays.asList("1", "2", "3", "4", "5"));
|
||||
|
||||
// ??? addElement("Thumbnail", "ImageResources", CHILD_POLICY_CHOICE);
|
||||
|
||||
// root -> ImageResources -> XMPData
|
||||
addElement("XMPData", "ImageResources", CHILD_POLICY_CHOICE);
|
||||
// TODO: Incorporate XMP metadata here somehow (or treat as opaque bytes?)
|
||||
addObjectValue("XMPData", Document.class, true, null);
|
||||
|
||||
// TODO: Layers
|
||||
//addElement("ChannelSourceDestinationRange", "LayerSomething", CHILD_POLICY_CHOICE);
|
||||
|
||||
// TODO: Global layer mask info
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean canNodeAppear(final String pElementName, final ImageTypeSpecifier pImageType) {
|
||||
// TODO: PSDColorData and PaletteEntry only for indexed color model
|
||||
throw new UnsupportedOperationException("Method canNodeAppear not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared instance of the {@code PSDMetadataFormat}.
|
||||
*
|
||||
* @return the shared instance.
|
||||
* @see javax.imageio.metadata.IIOMetadata#getMetadataFormat
|
||||
*/
|
||||
public static PSDMetadataFormat getInstance() {
|
||||
return sInstance;
|
||||
}
|
||||
}
|
@@ -0,0 +1,58 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDPrintFlagsInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
||||
*/
|
||||
final class PSDPrintFlags extends PSDImageResource {
|
||||
private boolean mLabels;
|
||||
private boolean mCropMasks;
|
||||
private boolean mColorBars;
|
||||
private boolean mRegistrationMarks;
|
||||
private boolean mNegative;
|
||||
private boolean mFlip;
|
||||
private boolean mInterpolate;
|
||||
private boolean mCaption;
|
||||
|
||||
PSDPrintFlags(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
mLabels = pInput.readBoolean();
|
||||
mCropMasks = pInput.readBoolean();
|
||||
mColorBars = pInput.readBoolean();
|
||||
mRegistrationMarks = pInput.readBoolean();
|
||||
mNegative = pInput.readBoolean();
|
||||
mFlip = pInput.readBoolean();
|
||||
mInterpolate = pInput.readBoolean();
|
||||
mCaption = pInput.readBoolean();
|
||||
|
||||
pInput.skipBytes(mSize - 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", labels: ").append(mLabels);
|
||||
builder.append(", crop masks: ").append(mCropMasks);
|
||||
builder.append(", color bars: ").append(mColorBars);
|
||||
builder.append(", registration marks: ").append(mRegistrationMarks);
|
||||
builder.append(", negative: ").append(mNegative);
|
||||
builder.append(", flip: ").append(mFlip);
|
||||
builder.append(", interpolate: ").append(mInterpolate);
|
||||
builder.append(", caption: ").append(mCaption);
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,49 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDPrintFlagsInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDPrintFlagsInfo.java,v 1.0 Jul 28, 2009 5:16:27 PM haraldk Exp$
|
||||
*/
|
||||
final class PSDPrintFlagsInformation extends PSDImageResource {
|
||||
private int mVersion;
|
||||
private boolean mCropMasks;
|
||||
private int mField;
|
||||
private long mBleedWidth;
|
||||
private int mBleedScale;
|
||||
|
||||
PSDPrintFlagsInformation(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
mVersion = pInput.readUnsignedShort();
|
||||
mCropMasks = pInput.readBoolean();
|
||||
mField = pInput.readUnsignedByte();
|
||||
mBleedWidth = pInput.readUnsignedInt();
|
||||
mBleedScale = pInput.readUnsignedShort();
|
||||
|
||||
pInput.skipBytes(mSize - 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", version: ").append(mVersion);
|
||||
builder.append(", crop masks: ").append(mCropMasks);
|
||||
builder.append(", field: ").append(mField);
|
||||
builder.append(", bleed width: ").append(mBleedWidth);
|
||||
builder.append(", bleed scale: ").append(mBleedScale);
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 javax.imageio.IIOException;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDResolutionInfo
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 {
|
||||
// typedef struct _ResolutionInfo
|
||||
// {
|
||||
// LONG hRes; /* Fixed-point number: pixels per inch */
|
||||
// WORD hResUnit; /* 1=pixels per inch, 2=pixels per centimeter */
|
||||
// WORD WidthUnit; /* 1=in, 2=cm, 3=pt, 4=picas, 5=columns */
|
||||
// LONG vRes; /* Fixed-point number: pixels per inch */
|
||||
// WORD vResUnit; /* 1=pixels per inch, 2=pixels per centimeter */
|
||||
// WORD HeightUnit; /* 1=in, 2=cm, 3=pt, 4=picas, 5=columns */
|
||||
// } RESOLUTIONINFO;
|
||||
|
||||
float mHRes;
|
||||
short mHResUnit;
|
||||
short mWidthUnit;
|
||||
float mVRes;
|
||||
short mVResUnit;
|
||||
short mHeightUnit;
|
||||
|
||||
PSDResolutionInfo(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(ImageInputStream pInput) throws IOException {
|
||||
if (mSize != 16) {
|
||||
throw new IIOException("Resolution info length expected to be 16: " + mSize);
|
||||
}
|
||||
|
||||
mHRes = PSDUtil.fixedPointToFloat(pInput.readInt());
|
||||
mHResUnit = pInput.readShort();
|
||||
mWidthUnit = pInput.readShort();
|
||||
mVRes = PSDUtil.fixedPointToFloat(pInput.readInt());
|
||||
mVResUnit = pInput.readShort();
|
||||
mHeightUnit = pInput.readShort();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", hRes: ").append(mHRes);
|
||||
builder.append(" ");
|
||||
builder.append(resUnit(mHResUnit));
|
||||
builder.append(", width unit: ");
|
||||
builder.append(dimUnit(mWidthUnit));
|
||||
builder.append(", vRes: ").append(mVRes);
|
||||
builder.append(" ");
|
||||
builder.append(resUnit(mVResUnit));
|
||||
builder.append(", height unit: ");
|
||||
builder.append(dimUnit(mHeightUnit));
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private String resUnit(final short pResUnit) {
|
||||
switch (pResUnit) {
|
||||
case 1:
|
||||
return "pixels/inch";
|
||||
case 2:
|
||||
return "pixels/cm";
|
||||
default:
|
||||
return "unknown unit " + pResUnit;
|
||||
}
|
||||
}
|
||||
|
||||
private String dimUnit(final short pUnit) {
|
||||
switch (pUnit) {
|
||||
case 1:
|
||||
return "in";
|
||||
case 2:
|
||||
return "cm";
|
||||
case 3:
|
||||
return "pt";
|
||||
case 4:
|
||||
return "pica";
|
||||
case 5:
|
||||
return "column";
|
||||
default:
|
||||
return "unknown unit " + pUnit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,100 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.IIOUtil;
|
||||
|
||||
import javax.imageio.IIOException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDThumbnail
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @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 {
|
||||
private BufferedImage mThumbnail;
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
|
||||
public PSDThumbnail(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
/*
|
||||
Thumbnail header, size 28
|
||||
4 Format. 1 = kJpegRGB . Also supports kRawRGB (0).
|
||||
4 Width of thumbnail in pixels.
|
||||
4 Height of thumbnail in pixels.
|
||||
4 Widthbytes: Padded row bytes = (width * bits per pixel + 31) / 32 * 4.
|
||||
4 Total size = widthbytes * height * planes
|
||||
4 Size after compression. Used for consistency check.
|
||||
2 Bits per pixel. = 24
|
||||
2 Number of planes. = 1
|
||||
*/
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
// TODO: Support for RAW RGB (format == 0): Extract RAW reader from PICT RAW QuickTime decompressor
|
||||
int format = pInput.readInt();
|
||||
switch (format) {
|
||||
case 0:
|
||||
// RAW RGB
|
||||
throw new IIOException("RAW RGB format thumbnail not supported yet");
|
||||
case 1:
|
||||
// JPEG
|
||||
break;
|
||||
default:
|
||||
throw new IIOException(String.format("Unsupported thumbnail format (%s) in PSD document", format));
|
||||
}
|
||||
|
||||
mWidth = pInput.readInt();
|
||||
mHeight = pInput.readInt();
|
||||
|
||||
// This data isn't really useful, unless we're dealing with raw bytes
|
||||
int widthBytes = pInput.readInt();
|
||||
int totalSize = pInput.readInt();
|
||||
|
||||
// Consistency check
|
||||
int sizeCompressed = pInput.readInt();
|
||||
if (sizeCompressed != (mSize - 28)) {
|
||||
throw new IIOException("Corrupt thumbnail in PSD document");
|
||||
}
|
||||
|
||||
// According to the spec, only 24 bits and 1 plane is supported
|
||||
int bits = pInput.readUnsignedShort();
|
||||
int planes = pInput.readUnsignedShort();
|
||||
if (bits != 24 && planes != 1) {
|
||||
// TODO: Warning/Exception
|
||||
}
|
||||
|
||||
// TODO: Defer decoding until getThumbnail?
|
||||
// TODO: Support BGR if id == RES_THUMBNAIL_PS4? Or is that already supported in the JPEG?
|
||||
mThumbnail = ImageIO.read(IIOUtil.createStreamAdapter(pInput, sizeCompressed));
|
||||
}
|
||||
|
||||
public final int getWidth() {
|
||||
return mWidth;
|
||||
}
|
||||
|
||||
public final int getHeight() {
|
||||
return mHeight;
|
||||
}
|
||||
|
||||
public final BufferedImage getThumbnail() {
|
||||
return mThumbnail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
builder.append(", ").append(mThumbnail);
|
||||
|
||||
builder.append("]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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.IIOUtil;
|
||||
import com.twelvemonkeys.io.enc.DecoderStream;
|
||||
import com.twelvemonkeys.io.enc.PackBitsDecoder;
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
/**
|
||||
* PSDUtil
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDUtil.java,v 1.0 Apr 29, 2008 5:05:00 PM haraldk Exp$
|
||||
*/
|
||||
final class PSDUtil {
|
||||
// TODO: Duplicated code from IFF plugin, move to some common util?
|
||||
static String intToStr(int pChunkId) {
|
||||
return new String(
|
||||
new byte[]{
|
||||
(byte) ((pChunkId & 0xff000000) >> 24),
|
||||
(byte) ((pChunkId & 0x00ff0000) >> 16),
|
||||
(byte) ((pChunkId & 0x0000ff00) >> 8),
|
||||
(byte) ((pChunkId & 0x000000ff))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Proably also useful for PICT reader, move to some common util?
|
||||
// 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();
|
||||
byte[] bytes = new byte[length];
|
||||
pInput.readFully(bytes);
|
||||
|
||||
return StringUtil.decode(bytes, 0, bytes.length, "ASCII");
|
||||
}
|
||||
|
||||
static String readUTF16String(final DataInput pInput) throws IOException {
|
||||
int length = pInput.readInt();
|
||||
byte[] bytes = new byte[length * 2];
|
||||
pInput.readFully(bytes);
|
||||
|
||||
return StringUtil.decode(bytes, 0, bytes.length, "UTF-16");
|
||||
}
|
||||
|
||||
static DataInputStream createPackBitsStream(final ImageInputStream pInput, long pLength) {
|
||||
return new DataInputStream(new DecoderStream(IIOUtil.createStreamAdapter(pInput, pLength), new PackBitsDecoder()));
|
||||
}
|
||||
|
||||
static DataInputStream createZipStream(final ImageInputStream pInput, long pLength) {
|
||||
//return new DataInputStream(new DecoderStream(IIOUtil.createStreamAdapter(pInput, pLength), new InflateDecoder()));
|
||||
return new DataInputStream(new ZipInputStream(IIOUtil.createStreamAdapter(pInput, pLength)));
|
||||
}
|
||||
|
||||
static DataInputStream createZipPredictorStream(final ImageInputStream pInput, long pLength) {
|
||||
throw new UnsupportedOperationException("Method createZipPredictonStream not implemented");
|
||||
}
|
||||
|
||||
public static float fixedPointToFloat(int pFP) {
|
||||
return ((pFP & 0xffff0000) >> 16) + (pFP & 0xffff) / (float) 0xffff;
|
||||
}
|
||||
}
|
@@ -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();
|
||||
}
|
||||
}
|
@@ -0,0 +1,60 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.lang.StringUtil;
|
||||
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* XMP metadata.
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: XMPData.java,v 1.0 Jul 28, 2009 5:50:34 PM haraldk Exp$
|
||||
*
|
||||
* @see <a href="http://www.adobe.com/products/xmp/">Adobe Extensible Metadata Platform (XMP)</a>
|
||||
* @see <a href="http://www.adobe.com/devnet/xmp/">Adobe XMP Developer Center</a>
|
||||
*/
|
||||
final class PSDXMPData extends PSDImageResource {
|
||||
protected byte[] mData;
|
||||
|
||||
PSDXMPData(final short pId, final ImageInputStream pInput) throws IOException {
|
||||
super(pId, pInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void readData(final ImageInputStream pInput) throws IOException {
|
||||
mData = new byte[(int) mSize]; // TODO: Fix potential overflow, or document why that can't happen (read spec)
|
||||
pInput.readFully(mData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder builder = toStringBuilder();
|
||||
|
||||
int length = Math.min(256, mData.length);
|
||||
String data = StringUtil.decode(mData, 0, length, "UTF-8").replace('\n', ' ').replaceAll("\\s+", " ");
|
||||
builder.append(", data: \"").append(data);
|
||||
|
||||
if (length < mData.length) {
|
||||
builder.append("...");
|
||||
}
|
||||
|
||||
builder.append("\"]");
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a character stream containing the XMP metadata (XML).
|
||||
*
|
||||
* @return the XMP metadata.
|
||||
*/
|
||||
public Reader getData() {
|
||||
return new InputStreamReader(new ByteArrayInputStream(mData), Charset.forName("UTF-8"));
|
||||
}
|
||||
}
|
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (c) 2008, 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 java.awt.color.ColorSpace;
|
||||
|
||||
/**
|
||||
* YCbCrColorSpace
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: YCbCrColorSpace.java,v 1.0 Jun 28, 2008 3:30:50 PM haraldk Exp$
|
||||
*/
|
||||
// TODO: Move to com.twlevemonkeys.image?
|
||||
// TODO: Read an ICC YCbCr profile from classpath resource? Is there such a thing?
|
||||
final class YCbCrColorSpace extends ColorSpace {
|
||||
|
||||
static final ColorSpace INSTANCE = new CMYKColorSpace();
|
||||
final ColorSpace sRGB = getInstance(CS_sRGB);
|
||||
|
||||
YCbCrColorSpace() {
|
||||
super(ColorSpace.TYPE_YCbCr, 3);
|
||||
}
|
||||
|
||||
public static ColorSpace getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
// http://www.w3.org/Graphics/JPEG/jfif.txt
|
||||
/*
|
||||
Conversion to and from RGB
|
||||
|
||||
Y, Cb, and Cr are converted from R, G, and B as defined in CCIR Recommendation 601
|
||||
but are normalized so as to occupy the full 256 levels of a 8-bit binary encoding. More
|
||||
precisely:
|
||||
|
||||
Y = 256 * E'y
|
||||
Cb = 256 * [ E'Cb ] + 128
|
||||
Cr = 256 * [ E'Cr ] + 128
|
||||
|
||||
where the E'y, E'Cb and E'Cb are defined as in CCIR 601. Since values of E'y have a
|
||||
range of 0 to 1.0 and those for E'Cb and E'Cr have a range of -0.5 to +0.5, Y, Cb, and Cr
|
||||
must be clamped to 255 when they are maximum value.
|
||||
|
||||
RGB to YCbCr Conversion
|
||||
|
||||
YCbCr (256 levels) can be computed directly from 8-bit RGB as follows:
|
||||
|
||||
Y = 0.299 R + 0.587 G + 0.114 B
|
||||
Cb = - 0.1687 R - 0.3313 G + 0.5 B + 128
|
||||
Cr = 0.5 R - 0.4187 G - 0.0813 B + 128
|
||||
|
||||
NOTE - Not all image file formats store image samples in the order R0, G0,
|
||||
B0, ... Rn, Gn, Bn. Be sure to verify the sample order before converting an
|
||||
RGB file to JFIF.
|
||||
|
||||
YCbCr to RGB Conversion
|
||||
|
||||
RGB can be computed directly from YCbCr (256 levels) as follows:
|
||||
|
||||
R = Y + 1.402 (Cr-128)
|
||||
G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
|
||||
B = Y + 1.772 (Cb-128)
|
||||
*/
|
||||
public float[] toRGB(float[] colorvalue) {
|
||||
// R = Y + 1.402 (Cr-128)
|
||||
// G = Y - 0.34414 (Cb-128) - 0.71414 (Cr-128)
|
||||
// B = Y + 1.772 (Cb-128)
|
||||
return new float[] {
|
||||
colorvalue[0] + 1.402f * (colorvalue[2] - .5f),
|
||||
colorvalue[0] - 0.34414f * (colorvalue[1] - .5f) - 0.71414f * (colorvalue[2] - .5f),
|
||||
colorvalue[0] + 1.772f * (colorvalue[1] - .5f),
|
||||
};
|
||||
// TODO: Convert via CIEXYZ space using sRGB space, as suggested in docs
|
||||
// return sRGB.fromCIEXYZ(toCIEXYZ(colorvalue));
|
||||
}
|
||||
|
||||
public float[] fromRGB(float[] rgbvalue) {
|
||||
// Y = 0.299 R + 0.587 G + 0.114 B
|
||||
// Cb = - 0.1687 R - 0.3313 G + 0.5 B + 128
|
||||
// Cr = 0.5 R - 0.4187 G - 0.0813 B + 128
|
||||
return new float[] {
|
||||
0.299f * rgbvalue[0] + 0.587f * rgbvalue[1] + 0.114f * rgbvalue[2],
|
||||
-0.1687f * rgbvalue[0] - 0.3313f * rgbvalue[1] + 0.5f * rgbvalue[2] + .5f,
|
||||
0.5f * rgbvalue[0] - 0.4187f * rgbvalue[1] - 0.0813f * rgbvalue[2] + .5f
|
||||
};
|
||||
}
|
||||
|
||||
public float[] toCIEXYZ(float[] colorvalue) {
|
||||
throw new UnsupportedOperationException("Method toCIEXYZ not implemented"); // TODO: Implement
|
||||
}
|
||||
|
||||
public float[] fromCIEXYZ(float[] colorvalue) {
|
||||
throw new UnsupportedOperationException("Method fromCIEXYZ not implemented"); // TODO: Implement
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
com.twelvemonkeys.imageio.plugins.psd.PSDImageReaderSpi
|
@@ -0,0 +1,215 @@
|
||||
package com.twelvemonkeys.imageio.plugins.psd;
|
||||
|
||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTestCase;
|
||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.ImageReader;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* PSDImageReaderTestCase
|
||||
*
|
||||
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a>
|
||||
* @author last modified by $Author: haraldk$
|
||||
* @version $Id: PSDImageReaderTestCase.java,v 1.0 Apr 1, 2008 10:39:17 PM haraldk Exp$
|
||||
*/
|
||||
public class PSDImageReaderTestCase extends ImageReaderAbstractTestCase<PSDImageReader> {
|
||||
|
||||
static ImageReaderSpi sProvider = new PSDImageReaderSpi();
|
||||
|
||||
protected List<TestData> getTestData() {
|
||||
return Arrays.asList(
|
||||
// 5 channel, RGB
|
||||
new TestData(getClassLoaderResource("/psd/photoshopping.psd"), new Dimension(300, 225)),
|
||||
// 1 channel, gray, 8 bit samples
|
||||
new TestData(getClassLoaderResource("/psd/buttons.psd"), new Dimension(20, 20)),
|
||||
// 5 channel, CMYK
|
||||
new TestData(getClassLoaderResource("/psd/escenic-liquid-logo.psd"), new Dimension(595, 420)),
|
||||
// 3 channel RGB, "no composite layer"
|
||||
new TestData(getClassLoaderResource("/psd/jugware-icon.psd"), new Dimension(128, 128)),
|
||||
// 3 channel RGB, old data, no layer info/mask
|
||||
new TestData(getClassLoaderResource("/psd/MARBLES.PSD"), new Dimension(1419, 1001)),
|
||||
// 1 channel, indexed color
|
||||
new TestData(getClassLoaderResource("/psd/coral_fish.psd"), new Dimension(800, 800)),
|
||||
// 1 channel, bitmap, 1 bit samples
|
||||
new TestData(getClassLoaderResource("/psd/test_bitmap.psd"), new Dimension(710, 512)),
|
||||
// 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))
|
||||
// TODO: Need uncompressed PSD
|
||||
// TODO: Need more recent ZIP compressed PSD files from CS2/CS3+
|
||||
);
|
||||
}
|
||||
|
||||
protected ImageReaderSpi createProvider() {
|
||||
return sProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PSDImageReader createReader() {
|
||||
return new PSDImageReader(sProvider);
|
||||
}
|
||||
|
||||
protected Class<PSDImageReader> getReaderClass() {
|
||||
return PSDImageReader.class;
|
||||
}
|
||||
|
||||
protected List<String> getFormatNames() {
|
||||
return Arrays.asList("psd");
|
||||
}
|
||||
|
||||
protected List<String> getSuffixes() {
|
||||
return Arrays.asList("psd");
|
||||
}
|
||||
|
||||
protected List<String> getMIMETypes() {
|
||||
return Arrays.asList("image/x-psd");
|
||||
}
|
||||
|
||||
public void testSupportsThumbnail() {
|
||||
PSDImageReader imageReader = createReader();
|
||||
assertTrue(imageReader.readerSupportsThumbnails());
|
||||
}
|
||||
|
||||
public void testThumbnailReading() throws IOException {
|
||||
PSDImageReader imageReader = createReader();
|
||||
|
||||
imageReader.setInput(getTestData().get(0).getInputStream());
|
||||
|
||||
assertEquals(1, imageReader.getNumThumbnails(0));
|
||||
|
||||
BufferedImage thumbnail = imageReader.readThumbnail(0, 0);
|
||||
assertNotNull(thumbnail);
|
||||
|
||||
assertEquals(128, thumbnail.getWidth());
|
||||
assertEquals(96, thumbnail.getHeight());
|
||||
}
|
||||
|
||||
public void testThumbnailReadingNoInput() throws IOException {
|
||||
PSDImageReader imageReader = createReader();
|
||||
|
||||
try {
|
||||
imageReader.getNumThumbnails(0);
|
||||
fail("Expected IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertTrue(expected.getMessage().toLowerCase().contains("input"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.getThumbnailWidth(0, 0);
|
||||
fail("Expected IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertTrue(expected.getMessage().toLowerCase().contains("input"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.getThumbnailHeight(0, 0);
|
||||
fail("Expected IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertTrue(expected.getMessage().toLowerCase().contains("input"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.readThumbnail(0, 0);
|
||||
fail("Expected IllegalStateException");
|
||||
}
|
||||
catch (IllegalStateException expected) {
|
||||
assertTrue(expected.getMessage().toLowerCase().contains("input"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThumbnailReadingOutOfBounds() throws IOException {
|
||||
PSDImageReader imageReader = createReader();
|
||||
|
||||
imageReader.setInput(getTestData().get(0).getInputStream());
|
||||
|
||||
try {
|
||||
imageReader.getNumThumbnails(2);
|
||||
fail("Expected IndexOutOfBoundsException");
|
||||
}
|
||||
catch (IndexOutOfBoundsException expected) {
|
||||
assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.getThumbnailWidth(-1, 0);
|
||||
fail("Expected IndexOutOfBoundsException");
|
||||
}
|
||||
catch (IndexOutOfBoundsException expected) {
|
||||
assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.getThumbnailHeight(0, -2);
|
||||
fail("Expected IndexOutOfBoundsException");
|
||||
}
|
||||
catch (IndexOutOfBoundsException expected) {
|
||||
// Sloppy...
|
||||
assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("-2"));
|
||||
}
|
||||
|
||||
try {
|
||||
imageReader.readThumbnail(99, 42);
|
||||
fail("Expected IndexOutOfBoundsException");
|
||||
}
|
||||
catch (IndexOutOfBoundsException expected) {
|
||||
assertTrue(expected.getMessage(), expected.getMessage().toLowerCase().contains("index"));
|
||||
}
|
||||
}
|
||||
|
||||
public void testThumbnailDimensions() throws IOException {
|
||||
PSDImageReader imageReader = createReader();
|
||||
|
||||
imageReader.setInput(getTestData().get(0).getInputStream());
|
||||
|
||||
assertEquals(1, imageReader.getNumThumbnails(0));
|
||||
|
||||
assertEquals(128, imageReader.getThumbnailWidth(0, 0));
|
||||
assertEquals(96, imageReader.getThumbnailHeight(0, 0));
|
||||
}
|
||||
|
||||
public void testThumbnailReadListeners() throws IOException {
|
||||
PSDImageReader imageReader = createReader();
|
||||
|
||||
imageReader.setInput(getTestData().get(0).getInputStream());
|
||||
|
||||
final List<Object> sequnce = new ArrayList<Object>();
|
||||
imageReader.addIIOReadProgressListener(new ProgressListenerBase() {
|
||||
private float mLastPercentageDone = 0;
|
||||
|
||||
@Override
|
||||
public void thumbnailStarted(final ImageReader pSource, final int pImageIndex, final int pThumbnailIndex) {
|
||||
sequnce.add("started");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailComplete(final ImageReader pSource) {
|
||||
sequnce.add("complete");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void thumbnailProgress(final ImageReader pSource, final float pPercentageDone) {
|
||||
// Optional
|
||||
assertTrue("Listener invoked out of sequence", sequnce.size() == 1);
|
||||
assertTrue(pPercentageDone >= mLastPercentageDone);
|
||||
}
|
||||
});
|
||||
|
||||
BufferedImage thumbnail = imageReader.readThumbnail(0, 0);
|
||||
assertNotNull(thumbnail);
|
||||
|
||||
assertEquals("Listeners not invoked", 2, sequnce.size());
|
||||
assertEquals("started", sequnce.get(0));
|
||||
assertEquals("complete", sequnce.get(1));
|
||||
}
|
||||
}
|
BIN
imageio/imageio-psd/src/test/resources/psd/AlphaChannelSample_720x480.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/AlphaChannelSample_720x480.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/MARBLES.PSD
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/MARBLES.PSD
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/buttons.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/buttons.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/circles.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/circles.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/cmyk_16bits.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/cmyk_16bits.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/cmyk_8bits.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/cmyk_8bits.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/coral_fish.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/coral_fish.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/escenic-liquid-logo.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/escenic-liquid-logo.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/jugware-icon.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/jugware-icon.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/photoshopping.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/photoshopping.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_bitmap.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_bitmap.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_gray.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_gray.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_gray16.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_gray16.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_indexed.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_indexed.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_original.psb
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_original.psb
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/test_original.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/test_original.psd
Executable file
Binary file not shown.
BIN
imageio/imageio-psd/src/test/resources/psd/transp.psd
Executable file
BIN
imageio/imageio-psd/src/test/resources/psd/transp.psd
Executable file
Binary file not shown.
5
imageio/imageio-psd/todo.txt
Executable file
5
imageio/imageio-psd/todo.txt
Executable file
@@ -0,0 +1,5 @@
|
||||
Implement source subsampling and region of interest
|
||||
Separate package for the resources (seems to be a lot)?
|
||||
Possibility to read only some resources? readResources(int[] resourceKeys)?
|
||||
- Probably faster when we only need the color space
|
||||
PSDImageWriter
|
Reference in New Issue
Block a user