mirror of
https://github.com/haraldk/TwelveMonkeys.git
synced 2025-08-05 04:25:29 -04:00
#214 PSDImageReader: Read long layer names
This commit is contained in:
parent
1449155987
commit
eeeb22666c
@ -51,6 +51,7 @@ interface PSD {
|
|||||||
|
|
||||||
/** PSD Resource type identifier "8BIM" */
|
/** PSD Resource type identifier "8BIM" */
|
||||||
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
|
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
|
||||||
|
int RESOURCE_TYPE_LONG = ('8' << 24) + ('B' << 16) + ('6' << 8) + '4';;
|
||||||
|
|
||||||
// Blending modes
|
// Blending modes
|
||||||
/** Pass through blending mode "pass"*/
|
/** Pass through blending mode "pass"*/
|
||||||
@ -689,4 +690,22 @@ interface PSD {
|
|||||||
|
|
||||||
/** Plug-In resource(s). Resources added by a plug-in. See the plug-in API found in the SDK documentation */
|
/** Plug-In resource(s). Resources added by a plug-in. See the plug-in API found in the SDK documentation */
|
||||||
int RES_PLUGIN_MAX = 0x1387;
|
int RES_PLUGIN_MAX = 0x1387;
|
||||||
|
|
||||||
|
// TODO: Better naming of these.. It's a kind of resource blocks as well..
|
||||||
|
// "Additional Layer Information"
|
||||||
|
int LMsk = 'L' << 24 | 'M' << 16 | 's' << 8 | 'k';
|
||||||
|
int Lr16 = 'L' << 24 | 'r' << 16 | '1' << 8 | '6';
|
||||||
|
int Lr32 = 'L' << 24 | 'r' << 16 | '3' << 8 | '2';
|
||||||
|
int Layr = 'L' << 24 | 'a' << 16 | 'y' << 8 | 'r';
|
||||||
|
int Mt16 = 'M' << 24 | 't' << 16 | '1' << 8 | '6';
|
||||||
|
int Mt32 = 'M' << 24 | 't' << 16 | '3' << 8 | '2';
|
||||||
|
int Mtrn = 'M' << 24 | 't' << 16 | 'r' << 8 | 'n';
|
||||||
|
int Alph = 'A' << 24 | 'l' << 16 | 'p' << 8 | 'h';
|
||||||
|
int FMsk = 'F' << 24 | 'M' << 16 | 's' << 8 | 'k';
|
||||||
|
int lnk2 = 'l' << 24 | 'n' << 16 | 'k' << 8 | '2';
|
||||||
|
int FEid = 'F' << 24 | 'E' << 16 | 'i' << 8 | 'd';
|
||||||
|
int FXid = 'F' << 24 | 'X' << 16 | 'i' << 8 | 'd';
|
||||||
|
int PxSD = 'P' << 24 | 'x' << 16 | 'S' << 8 | 'D';
|
||||||
|
int luni = 'l' << 24 | 'u' << 16 | 'n' << 8 | 'i';
|
||||||
|
int lyid = 'l' << 24 | 'y' << 16 | 'i' << 8 | 'd';
|
||||||
}
|
}
|
||||||
|
@ -50,7 +50,10 @@ final class PSDLayerInfo {
|
|||||||
final PSDLayerBlendMode blendMode;
|
final PSDLayerBlendMode blendMode;
|
||||||
final PSDLayerMaskData layerMaskData;
|
final PSDLayerMaskData layerMaskData;
|
||||||
final PSDChannelSourceDestinationRange[] ranges;
|
final PSDChannelSourceDestinationRange[] ranges;
|
||||||
final String layerName;
|
private final String layerName;
|
||||||
|
|
||||||
|
private String unicodeLayerName;
|
||||||
|
private int layerId;
|
||||||
|
|
||||||
PSDLayerInfo(final boolean largeFormat, final ImageInputStream pInput) throws IOException {
|
PSDLayerInfo(final boolean largeFormat, final ImageInputStream pInput) throws IOException {
|
||||||
top = pInput.readInt();
|
top = pInput.readInt();
|
||||||
@ -70,7 +73,7 @@ final class PSDLayerInfo {
|
|||||||
|
|
||||||
blendMode = new PSDLayerBlendMode(pInput);
|
blendMode = new PSDLayerBlendMode(pInput);
|
||||||
|
|
||||||
// Length of layer mask data
|
// Length of layer extra data
|
||||||
long extraDataSize = pInput.readUnsignedInt();
|
long extraDataSize = pInput.readUnsignedInt();
|
||||||
|
|
||||||
// Layer mask/adjustment layer data
|
// Layer mask/adjustment layer data
|
||||||
@ -92,19 +95,78 @@ final class PSDLayerInfo {
|
|||||||
ranges[i] = new PSDChannelSourceDestinationRange(pInput, (i == 0 ? "Gray" : "Channel " + (i - 1)));
|
ranges[i] = new PSDChannelSourceDestinationRange(pInput, (i == 0 ? "Gray" : "Channel " + (i - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Layer name
|
||||||
layerName = PSDUtil.readPascalString(pInput);
|
layerName = PSDUtil.readPascalString(pInput);
|
||||||
|
|
||||||
int layerNameSize = layerName.length() + 1;
|
int layerNameSize = layerName.length() + 1;
|
||||||
|
|
||||||
// Skip pad bytes for long word alignment
|
// Skip pad bytes for long word alignment
|
||||||
if (layerNameSize % 4 != 0) {
|
if (layerNameSize % 4 != 0) {
|
||||||
int skip = layerNameSize % 4;
|
int skip = 4 - (layerNameSize % 4);
|
||||||
pInput.skipBytes(skip);
|
pInput.skipBytes(skip);
|
||||||
layerNameSize += skip;
|
layerNameSize += skip;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Consider reading this: Adjustment layer info etc...
|
// Parse "Additional layer data"
|
||||||
pInput.skipBytes(extraDataSize - layerMaskDataSize - 4 - layerBlendingDataSize - 4 - layerNameSize);
|
long additionalLayerInfoStart = pInput.getStreamPosition();
|
||||||
|
long expectedEnd = additionalLayerInfoStart + extraDataSize - layerMaskDataSize - 4 - layerBlendingDataSize - 4 - layerNameSize;
|
||||||
|
while (pInput.getStreamPosition() < expectedEnd) {
|
||||||
|
// 8BIM or 8B64
|
||||||
|
int resourceSignature = pInput.readInt();
|
||||||
|
|
||||||
|
if (resourceSignature != PSD.RESOURCE_TYPE && resourceSignature != PSD.RESOURCE_TYPE_LONG) {
|
||||||
|
// Could be a corrupt document, or some new resource (type) we don't know about,
|
||||||
|
// we'll just leave it and carry on, as this is all secondary information for the reader.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int resourceKey = pInput.readInt();
|
||||||
|
|
||||||
|
// NOTE: Only SOME resources have long length fields...
|
||||||
|
boolean largeResource = resourceSignature != PSD.RESOURCE_TYPE;
|
||||||
|
long resourceLength = largeResource ? pInput.readLong() : pInput.readUnsignedInt();
|
||||||
|
long resourceStart = pInput.getStreamPosition();
|
||||||
|
|
||||||
|
// System.out.printf("signature: %s 0x%08x\n", PSDUtil.intToStr(resourceSignature), resourceSignature);
|
||||||
|
// System.out.println("key: " + PSDUtil.intToStr(resourceKey));
|
||||||
|
// System.out.println("length: " + resourceLength);
|
||||||
|
|
||||||
|
switch (resourceKey) {
|
||||||
|
case PSD.luni:
|
||||||
|
unicodeLayerName = PSDUtil.readUnicodeString(pInput);
|
||||||
|
// There's usually a 0-pad here, but it is skipped in the general re-aligning code below
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PSD.lyid:
|
||||||
|
if (resourceLength != 4) {
|
||||||
|
throw new IIOException(String.format("Expected layerId length == 4: %d", resourceLength));
|
||||||
|
}
|
||||||
|
layerId = pInput.readInt();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// TODO: Parse more data...
|
||||||
|
pInput.skipBytes(resourceLength);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-align in case we got the length incorrect
|
||||||
|
if (pInput.getStreamPosition() != resourceStart + resourceLength) {
|
||||||
|
pInput.seek(resourceStart + resourceLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-align in case we got the length incorrect
|
||||||
|
if (pInput.getStreamPosition() != expectedEnd) {
|
||||||
|
pInput.seek(expectedEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String getLayerName() {
|
||||||
|
return unicodeLayerName != null ? unicodeLayerName : layerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLayerId() {
|
||||||
|
return layerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -122,7 +184,7 @@ final class PSDLayerInfo {
|
|||||||
builder.append(", layer mask data: ").append(layerMaskData);
|
builder.append(", layer mask data: ").append(layerMaskData);
|
||||||
}
|
}
|
||||||
builder.append(", ranges: ").append(Arrays.toString(ranges));
|
builder.append(", ranges: ").append(Arrays.toString(ranges));
|
||||||
builder.append(", layer name: \"").append(layerName).append("\"");
|
builder.append(", layer name: \"").append(getLayerName()).append("\"");
|
||||||
|
|
||||||
builder.append("]");
|
builder.append("]");
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
@ -375,7 +375,7 @@ public final class PSDMetadata extends AbstractMetadata {
|
|||||||
for (PSDLayerInfo psdLayerInfo : layerInfo) {
|
for (PSDLayerInfo psdLayerInfo : layerInfo) {
|
||||||
// TODO: Group in layer and use sub node for blend mode?
|
// TODO: Group in layer and use sub node for blend mode?
|
||||||
node = new IIOMetadataNode("LayerInfo");
|
node = new IIOMetadataNode("LayerInfo");
|
||||||
node.setAttribute("name", psdLayerInfo.layerName);
|
node.setAttribute("name", psdLayerInfo.getLayerName());
|
||||||
node.setAttribute("top", String.valueOf(psdLayerInfo.top));
|
node.setAttribute("top", String.valueOf(psdLayerInfo.top));
|
||||||
node.setAttribute("left", String.valueOf(psdLayerInfo.left));
|
node.setAttribute("left", String.valueOf(psdLayerInfo.left));
|
||||||
node.setAttribute("bottom", String.valueOf(psdLayerInfo.bottom));
|
node.setAttribute("bottom", String.valueOf(psdLayerInfo.bottom));
|
||||||
|
@ -31,11 +31,16 @@ package com.twelvemonkeys.imageio.plugins.psd;
|
|||||||
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
import com.twelvemonkeys.imageio.util.ImageReaderAbstractTest;
|
||||||
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
import com.twelvemonkeys.imageio.util.ProgressListenerBase;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.w3c.dom.NodeList;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReadParam;
|
import javax.imageio.ImageReadParam;
|
||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.ImageTypeSpecifier;
|
import javax.imageio.ImageTypeSpecifier;
|
||||||
|
import javax.imageio.metadata.IIOMetadata;
|
||||||
|
import javax.imageio.metadata.IIOMetadataNode;
|
||||||
import javax.imageio.spi.ImageReaderSpi;
|
import javax.imageio.spi.ImageReaderSpi;
|
||||||
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -385,4 +390,20 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest<PSDImageReader>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadUnicodeLayerName() throws IOException {
|
||||||
|
PSDImageReader imageReader = createReader();
|
||||||
|
|
||||||
|
try (ImageInputStream stream = ImageIO.createImageInputStream(getClassLoaderResource("/psd/long-layer-names.psd"))) {
|
||||||
|
imageReader.setInput(stream);
|
||||||
|
|
||||||
|
IIOMetadata metadata = imageReader.getImageMetadata(0);
|
||||||
|
IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(PSDMetadata.NATIVE_METADATA_FORMAT_NAME);
|
||||||
|
NodeList layerInfo = root.getElementsByTagName("LayerInfo");
|
||||||
|
|
||||||
|
assertEquals(1, layerInfo.getLength()); // Sanity
|
||||||
|
assertEquals("If_The_Layer_Name_Is_Really_Long_Oh_No_What_Do_I_Do", ((IIOMetadataNode) layerInfo.item(0)).getAttribute("name"));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
BIN
imageio/imageio-psd/src/test/resources/psd/long-layer-names.psd
Normal file
BIN
imageio/imageio-psd/src/test/resources/psd/long-layer-names.psd
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user