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" */
|
||||
int RESOURCE_TYPE = ('8' << 24) + ('B' << 16) + ('I' << 8) + 'M';
|
||||
int RESOURCE_TYPE_LONG = ('8' << 24) + ('B' << 16) + ('6' << 8) + '4';;
|
||||
|
||||
// Blending modes
|
||||
/** 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 */
|
||||
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 PSDLayerMaskData layerMaskData;
|
||||
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 {
|
||||
top = pInput.readInt();
|
||||
@ -70,7 +73,7 @@ final class PSDLayerInfo {
|
||||
|
||||
blendMode = new PSDLayerBlendMode(pInput);
|
||||
|
||||
// Length of layer mask data
|
||||
// Length of layer extra data
|
||||
long extraDataSize = pInput.readUnsignedInt();
|
||||
|
||||
// Layer mask/adjustment layer data
|
||||
@ -92,19 +95,78 @@ final class PSDLayerInfo {
|
||||
ranges[i] = new PSDChannelSourceDestinationRange(pInput, (i == 0 ? "Gray" : "Channel " + (i - 1)));
|
||||
}
|
||||
|
||||
// Layer name
|
||||
layerName = PSDUtil.readPascalString(pInput);
|
||||
|
||||
int layerNameSize = layerName.length() + 1;
|
||||
|
||||
// Skip pad bytes for long word alignment
|
||||
if (layerNameSize % 4 != 0) {
|
||||
int skip = layerNameSize % 4;
|
||||
int skip = 4 - (layerNameSize % 4);
|
||||
pInput.skipBytes(skip);
|
||||
layerNameSize += skip;
|
||||
}
|
||||
|
||||
// TODO: Consider reading this: Adjustment layer info etc...
|
||||
pInput.skipBytes(extraDataSize - layerMaskDataSize - 4 - layerBlendingDataSize - 4 - layerNameSize);
|
||||
// Parse "Additional layer data"
|
||||
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
|
||||
@ -122,7 +184,7 @@ final class PSDLayerInfo {
|
||||
builder.append(", layer mask data: ").append(layerMaskData);
|
||||
}
|
||||
builder.append(", ranges: ").append(Arrays.toString(ranges));
|
||||
builder.append(", layer name: \"").append(layerName).append("\"");
|
||||
builder.append(", layer name: \"").append(getLayerName()).append("\"");
|
||||
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
|
@ -375,7 +375,7 @@ public final class PSDMetadata extends AbstractMetadata {
|
||||
for (PSDLayerInfo psdLayerInfo : layerInfo) {
|
||||
// TODO: Group in layer and use sub node for blend mode?
|
||||
node = new IIOMetadataNode("LayerInfo");
|
||||
node.setAttribute("name", psdLayerInfo.layerName);
|
||||
node.setAttribute("name", psdLayerInfo.getLayerName());
|
||||
node.setAttribute("top", String.valueOf(psdLayerInfo.top));
|
||||
node.setAttribute("left", String.valueOf(psdLayerInfo.left));
|
||||
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.ProgressListenerBase;
|
||||
import org.junit.Test;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReadParam;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.ImageTypeSpecifier;
|
||||
import javax.imageio.metadata.IIOMetadata;
|
||||
import javax.imageio.metadata.IIOMetadataNode;
|
||||
import javax.imageio.spi.ImageReaderSpi;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
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