diff --git a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java index 6b2a43e2..ddb75270 100644 --- a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java +++ b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReader.java @@ -946,48 +946,8 @@ public final class PSDImageReader extends ImageReaderBase { metadata.layerCount = layerCount; if (pParseData && metadata.layerInfo == null) { - PSDLayerInfo[] layerInfos = new PSDLayerInfo[Math.abs(layerCount)]; - - Stack> groupStack = new Stack<>(); - List groupedLayerInfo = null; - - for (int i = 0; i < layerInfos.length; i++) { - PSDLayerInfo layerInfo = new PSDLayerInfo(header.largeFormat, imageInput); - layerInfos[i] = layerInfo; - - if (layerInfo.sectionDividerSettingType == PSDLayerInfo.SectionDividerSetting.BOUNDING_SECTION_DIVIDER) { - if (groupedLayerInfo == null) { - groupedLayerInfo = new LinkedList<>(); - groupStack.add(groupedLayerInfo); - } else { - groupStack.add(groupedLayerInfo); - groupedLayerInfo = new LinkedList<>(); - } - layerInfo.sectionDivider = true; - } - else if (layerInfo.sectionDividerSettingType == PSDLayerInfo.SectionDividerSetting.OPEN_FOLDER || - layerInfo.sectionDividerSettingType == PSDLayerInfo.SectionDividerSetting.CLOSED_FOLDER) { - // can't happen but for defense logic - if (groupedLayerInfo == null) { - continue; - } - for (PSDLayerInfo info : groupedLayerInfo) { - info.groupLayerId = layerInfo.getLayerId(); - } - groupedLayerInfo = groupStack.pop(); - groupedLayerInfo.add(layerInfo); - layerInfo.group = true; - } - else { - if (groupedLayerInfo != null) { - groupedLayerInfo.add(layerInfo); - } - } - } - - metadata.layerInfo = Arrays.asList(layerInfos); + metadata.layerInfo = readLayerInfo(Math.abs(layerCount)); metadata.layersStart = imageInput.getStreamPosition(); - } long read = imageInput.getStreamPosition() - pos; @@ -999,7 +959,6 @@ public final class PSDImageReader extends ImageReaderBase { metadata.layerInfo = Collections.emptyList(); } - // Global LayerMaskInfo (18 bytes or more..?) // 4 (length), 2 (colorSpace), 8 (4 * 2 byte color components), 2 (opacity %), 1 (kind), variable (pad) long globalLayerMaskInfoLength = imageInput.readUnsignedInt(); // NOTE: Not long for PSB! @@ -1030,6 +989,33 @@ public final class PSDImageReader extends ImageReaderBase { } } + private List readLayerInfo(int layerCount) throws IOException { + PSDLayerInfo[] layerInfos = new PSDLayerInfo[layerCount]; + + List groupedLayerInfo = Collections.emptyList(); + + for (int i = 0; i < layerInfos.length; i++) { + PSDLayerInfo layerInfo = new PSDLayerInfo(header.largeFormat, imageInput); + layerInfos[i] = layerInfo; + + if (layerInfo.isDivider) { + groupedLayerInfo = new LinkedList<>(); + } + else if (layerInfo.isGroup) { + for (PSDLayerInfo info : groupedLayerInfo) { + info.groupId = layerInfo.getLayerId(); + } + + groupedLayerInfo = Collections.emptyList(); + } + else if (groupedLayerInfo != Collections.EMPTY_LIST) { + groupedLayerInfo.add(layerInfo); + } + } + + return Arrays.asList(layerInfos); + } + private BufferedImage readLayerData(final int layerIndex, final ImageReadParam param) throws IOException { final int width = getLayerWidth(layerIndex); final int height = getLayerHeight(layerIndex); @@ -1044,7 +1030,7 @@ public final class PSDImageReader extends ImageReaderBase { // Even if raw/imageType has no alpha, the layers may still have alpha... ImageTypeSpecifier imageType = getRawImageTypeForLayer(layerIndex); - BufferedImage layer = getDestination(param, getImageTypes(layerIndex + 1), Math.max(1, width), Math.max(1, height)); + BufferedImage layer = getDestination(param, getImageTypes(layerIndex + 1), width, height); imageInput.seek(findLayerStartPos(layerIndex)); diff --git a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDLayerInfo.java b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDLayerInfo.java index f24a8fa4..6bb0fa14 100755 --- a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDLayerInfo.java +++ b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDLayerInfo.java @@ -52,16 +52,15 @@ final class PSDLayerInfo { final PSDLayerBlendMode blendMode; final PSDLayerMaskData layerMaskData; final PSDChannelSourceDestinationRange[] ranges; + private final String layerName; + private final String unicodeLayerName; - private String unicodeLayerName; - private int layerId; + private final int layerId; - Integer groupLayerId; - Boolean group = false; - Boolean sectionDivider = false; - - SectionDividerSetting sectionDividerSettingType; + int groupId = -1; + final boolean isGroup; + final boolean isDivider; PSDLayerInfo(final boolean largeFormat, final ImageInputStream pInput) throws IOException { top = pInput.readInt(); @@ -114,6 +113,10 @@ final class PSDLayerInfo { layerNameSize += skip; } + int layerId = -1; + String unicodeLayerName = null; + int sectionDividerSettingType = 0; + // Parse "Additional layer data" long additionalLayerInfoStart = pInput.getStreamPosition(); long expectedEnd = additionalLayerInfoStart + extraDataSize - layerMaskDataSize - 4 - layerBlendingDataSize - 4 - layerNameSize; @@ -138,7 +141,6 @@ final class PSDLayerInfo { // System.out.println("key: " + PSDUtil.intToStr(resourceKey)); // System.out.println("length: " + resourceLength); - switch (resourceKey) { case PSD.luni: unicodeLayerName = PSDUtil.readUnicodeString(pInput); @@ -149,24 +151,37 @@ final class PSDLayerInfo { if (resourceLength != 4) { throw new IIOException(String.format("Expected layerId length == 4: %d", resourceLength)); } + layerId = pInput.readInt(); break; + case PSD.lsct: - sectionDividerSettingType = SectionDividerSetting.valueOf(pInput.readInt()); + if (resourceLength < 4) { + throw new IIOException(String.format("Expected sectionDividerSetting length >= 4: %d", resourceLength)); + } + + sectionDividerSettingType = pInput.readInt(); + // length >= 12: '8BIM' + 4byte blend mode, length >= 16, 4byte sub type pInput.skipBytes(resourceLength - 4); break; + default: // TODO: Parse more data... pInput.skipBytes(resourceLength); break; } - // Re-align in case we got the length incorrect + // Re-align in case we got the resource length incorrect if (pInput.getStreamPosition() != resourceStart + resourceLength) { pInput.seek(resourceStart + resourceLength); } } + this.layerId = layerId; + this.unicodeLayerName = unicodeLayerName; + isGroup = sectionDividerSettingType == 1 || sectionDividerSettingType == 2; + isDivider = sectionDividerSettingType == 3; + // Re-align in case we got the length incorrect if (pInput.getStreamPosition() != expectedEnd) { pInput.seek(expectedEnd); @@ -197,26 +212,19 @@ final class PSDLayerInfo { } builder.append(", ranges: ").append(Arrays.toString(ranges)); builder.append(", layer name: \"").append(getLayerName()).append("\""); + builder.append(", layer id: ").append(getLayerId()); + + if (groupId != -1) { + builder.append(", group id: ").append(groupId); + } + if (isGroup) { + builder.append(", isGroup"); + } + if (isDivider) { + builder.append(", isDivider"); + } builder.append("]"); return builder.toString(); } - - public enum SectionDividerSetting { - LAYER(0), OPEN_FOLDER(1), CLOSED_FOLDER(2), BOUNDING_SECTION_DIVIDER(3); - SectionDividerSetting(int value) { this.value = value;} - - private final int value; - public int value() { return value; } - - public static SectionDividerSetting valueOf(int value){ - for(SectionDividerSetting rt : SectionDividerSetting.values()){ - if(rt.value == value){ - return rt; - } - } - - return null; - } - } } diff --git a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDMetadata.java b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDMetadata.java index f57a7c16..9792b5b4 100755 --- a/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDMetadata.java +++ b/imageio/imageio-psd/src/main/java/com/twelvemonkeys/imageio/plugins/psd/PSDMetadata.java @@ -37,6 +37,7 @@ import com.twelvemonkeys.imageio.metadata.iptc.IPTC; import com.twelvemonkeys.imageio.metadata.tiff.TIFF; import com.twelvemonkeys.lang.StringUtil; import com.twelvemonkeys.util.FilterIterator; + import org.w3c.dom.Node; import javax.imageio.metadata.IIOMetadataNode; @@ -388,21 +389,21 @@ public final class PSDMetadata extends AbstractMetadata { node.setAttribute("bottom", String.valueOf(psdLayerInfo.bottom)); node.setAttribute("right", String.valueOf(psdLayerInfo.right)); node.setAttribute("layerId", String.valueOf(psdLayerInfo.getLayerId())); - node.setAttribute("groupLayerId", String.valueOf(psdLayerInfo.groupLayerId)); + if (psdLayerInfo.groupId != -1) { + node.setAttribute("groupId", String.valueOf(psdLayerInfo.groupId)); + } node.setAttribute("blendMode", PSDUtil.intToStr(psdLayerInfo.blendMode.blendMode)); node.setAttribute("opacity", String.valueOf(psdLayerInfo.blendMode.opacity)); // 0-255 node.setAttribute("clipping", getClippingValue(psdLayerInfo.blendMode.clipping)); // Enum: 0: Base, 1: Non-base, n: unknown node.setAttribute("flags", String.valueOf(psdLayerInfo.blendMode.flags)); - if ((psdLayerInfo.group)){ - node.setAttribute("group", String.valueOf(psdLayerInfo.group)); + if ((psdLayerInfo.isGroup)) { + node.setAttribute("group", "true"); } - - if ((psdLayerInfo.sectionDivider)) { - node.setAttribute("sectionDivider", String.valueOf(psdLayerInfo.sectionDivider)); + if ((psdLayerInfo.isDivider)) { + node.setAttribute("sectionDivider", "true"); } - if ((psdLayerInfo.blendMode.flags & 0x01) != 0) { node.setAttribute("transparencyProtected", "true"); } diff --git a/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java b/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java index d2f5edd8..a1f525d7 100755 --- a/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java +++ b/imageio/imageio-psd/src/test/java/com/twelvemonkeys/imageio/plugins/psd/PSDImageReaderTest.java @@ -545,38 +545,24 @@ public class PSDImageReaderTest extends ImageReaderAbstractTest assertEquals(layerInfos.size(), 5); - PSDLayerInfo groupedLayer = null; - PSDLayerInfo groupLayer = null; - PSDLayerInfo sectionDividerLayer = null; - for (PSDLayerInfo layerInfo : layerInfos) { - if (layerInfo.getLayerId() == 5) { - groupedLayer = layerInfo; - } - - if (layerInfo.getLayerId() == 6) { - groupLayer = layerInfo; - } - - if (layerInfo.getLayerId() == 7) { - sectionDividerLayer = layerInfo; - } - } + PSDLayerInfo sectionDividerLayer = layerInfos.get(1); + PSDLayerInfo groupedLayer = layerInfos.get(2); + PSDLayerInfo groupLayer = layerInfos.get(3); assertNotNull(groupedLayer); - assertEquals((int) groupedLayer.groupLayerId, 6); - assertEquals(groupedLayer.group, false); - assertEquals(groupedLayer.sectionDivider, false); + assertEquals(groupedLayer.groupId, 6); + assertFalse(groupedLayer.isGroup); + assertFalse(groupedLayer.isDivider); assertNotNull(groupLayer); - assertNull(groupLayer.groupLayerId); - assertEquals(groupLayer.group, true); - assertEquals(groupLayer.sectionDivider, false); + assertEquals(-1, groupLayer.groupId); + assertTrue(groupLayer.isGroup); + assertFalse(groupLayer.isDivider); assertNotNull(sectionDividerLayer); - assertNull(sectionDividerLayer.groupLayerId); - assertEquals(sectionDividerLayer.group, false); - assertEquals(sectionDividerLayer.sectionDivider, true); - + assertEquals(-1, sectionDividerLayer.groupId); + assertFalse(sectionDividerLayer.isGroup); + assertTrue(sectionDividerLayer.isDivider); } } } \ No newline at end of file