From 25ec3e95161fb262164435e0f932c00af3926b14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 23 Mar 2024 11:04:41 +0100 Subject: [PATCH] Fixed #2212 GFX - Allow loading (DDS) images despite of set bitmapFormat --- CHANGELOG.md | 2 + .../flash/tags/gfx/AbstractGfxImageTag.java | 95 +++++++++++++++++++ .../flash/tags/gfx/DefineExternalImage.java | 85 +++++------------ .../flash/tags/gfx/DefineExternalImage2.java | 85 +++++------------ .../flash/tags/gfx/DefineSubImage.java | 94 +++++++----------- 5 files changed, 173 insertions(+), 188 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/AbstractGfxImageTag.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f5758e06..f9bbee532 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ All notable changes to this project will be documented in this file. - [#2190] AS1/2 - for..in inside switch before break - Raw edit of fonts - shape table was not visible - [#2211] PDF export, Font export - glyphs with no contours (advance only) +- [#2212] GFX - Allow loading (DDS) images despite of set bitmapFormat ### Changed - [#2185] MochiCrypt no longer offered for auto decrypt, user needs to choose variant from "Use unpacker" menu @@ -3398,6 +3399,7 @@ Major version of SWF to XML export changed to 2. [#2207]: https://www.free-decompiler.com/flash/issues/2207 [#2190]: https://www.free-decompiler.com/flash/issues/2190 [#2211]: https://www.free-decompiler.com/flash/issues/2211 +[#2212]: https://www.free-decompiler.com/flash/issues/2212 [#2206]: https://www.free-decompiler.com/flash/issues/2206 [#2100]: https://www.free-decompiler.com/flash/issues/2100 [#2123]: https://www.free-decompiler.com/flash/issues/2123 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/AbstractGfxImageTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/AbstractGfxImageTag.java new file mode 100644 index 000000000..bf98a7d4c --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/AbstractGfxImageTag.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2010-2023 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.gfx; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.gfx.TgaSupport; +import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.helpers.ByteArrayRange; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import javax.imageio.ImageIO; +import net.npe.dds.DDSReader; + +/** + * + * @author JPEXS + */ +public abstract class AbstractGfxImageTag extends ImageTag { + + public static final int BITMAP_FORMAT_DEFAULT = 0; + + public static final int BITMAP_FORMAT_TGA = 1; + + public static final int BITMAP_FORMAT_DDS = 2; + + //It looks like gfxexport produces BITMAP_FORMAT2_* values for format, + //but BITMAP_FORMAT_* works the same way + public static final int BITMAP_FORMAT2_JPEG = 10; + + public static final int BITMAP_FORMAT2_TGA = 13; + + public static final int BITMAP_FORMAT2_DDS = 14; + + + public AbstractGfxImageTag(SWF swf, int id, String name, ByteArrayRange data) { + super(swf, id, name, data); + } + + private BufferedImage loadDds(byte[] imageData) { + int[] pixels = DDSReader.read(imageData, DDSReader.ARGB, 0); + BufferedImage bufImage = new BufferedImage(DDSReader.getWidth(imageData), DDSReader.getHeight(imageData), BufferedImage.TYPE_INT_ARGB); + bufImage.getRaster().setDataElements(0, 0, bufImage.getWidth(), bufImage.getHeight(), pixels); + return bufImage; + } + + protected BufferedImage getExternalBufferedImage(String fileName, int bitmapFormat) { + Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName)); + if (imagePath == null || !imagePath.toFile().exists()) { + return null; + } + + byte[] imageData; + try { + imageData = Files.readAllBytes(imagePath); + } catch (IOException ex) { + return null; + } + if (imageData.length >= 4 && + imageData[0] == 0x44 && + imageData[1] == 0x44 && + imageData[2] == 0x53 && + imageData[3] == 0x20) { + return loadDds(imageData); + } + + if (fileName.toLowerCase().endsWith(".tga") + || bitmapFormat == BITMAP_FORMAT2_TGA + || bitmapFormat == BITMAP_FORMAT_TGA) { + TgaSupport.init(); + } + + try { + return ImageIO.read(imagePath.toFile()); + } catch (IOException ex) { + return null; + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java index c578cee7e..d117be42a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage.java @@ -44,7 +44,7 @@ import net.npe.dds.DDSReader; * * @author JPEXS */ -public class DefineExternalImage extends ImageTag { +public class DefineExternalImage extends AbstractGfxImageTag { public static final int ID = 1001; @@ -58,21 +58,7 @@ public class DefineExternalImage extends ImageTag { public String exportName; - public String fileName; - - public static final int BITMAP_FORMAT_DEFAULT = 0; - - public static final int BITMAP_FORMAT_TGA = 1; - - public static final int BITMAP_FORMAT_DDS = 2; - - //It looks like gfxexport produces BITMAP_FORMAT2_* values for format, - //but BITMAP_FORMAT_* works the same way - public static final int BITMAP_FORMAT2_JPEG = 10; - - public static final int BITMAP_FORMAT2_TGA = 13; - - public static final int BITMAP_FORMAT2_DDS = 14; + public String fileName; @HideInRawEdit private SerializableImage serImage; @@ -176,54 +162,27 @@ public class DefineExternalImage extends ImageTag { } private void initImage() { - if (!Objects.equals(cachedImageFilename, fileName) - || (serImage != null && (serImage.getWidth() != targetWidth || serImage.getHeight() != targetHeight))) { - - if (targetWidth <= 0 || targetHeight <= 0) { - serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); - serImage.fillTransparent(); - } else if (bitmapFormat == BITMAP_FORMAT2_JPEG || bitmapFormat == BITMAP_FORMAT2_TGA || bitmapFormat == BITMAP_FORMAT_TGA) { - Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName)); - if (imagePath != null && imagePath.toFile().exists()) { - try { - if (bitmapFormat == BITMAP_FORMAT2_TGA || bitmapFormat == BITMAP_FORMAT_TGA) { - TgaSupport.init(); - } - BufferedImage bufImage = ImageIO.read(imagePath.toFile()); - Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, 0, 0, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = fileName; - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } else if (bitmapFormat == BITMAP_FORMAT2_DDS || bitmapFormat == BITMAP_FORMAT_DDS) { - Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName)); - if (imagePath != null && imagePath.toFile().exists()) { - try { - byte[] imageData = Files.readAllBytes(imagePath); - int[] pixels = DDSReader.read(imageData, DDSReader.ARGB, 0); - BufferedImage bufImage = new BufferedImage(DDSReader.getWidth(imageData), DDSReader.getHeight(imageData), BufferedImage.TYPE_INT_ARGB); - bufImage.getRaster().setDataElements(0, 0, bufImage.getWidth(), bufImage.getHeight(), pixels); - Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, 0, 0, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = fileName; - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } else { - createFailedImage(); - } + if (Objects.equals(cachedImageFilename, fileName) + && serImage != null && (serImage.getWidth() == targetWidth && serImage.getHeight() == targetHeight)) { + return; } + + if (targetWidth <= 0 || targetHeight <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } + + BufferedImage bufImage = getExternalBufferedImage(fileName, bitmapFormat); + if (bufImage == null) { + createFailedImage(); + return; + } + Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); + bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); + bufImage.getGraphics().drawImage(scaled, 0, 0, null); + serImage = new SerializableImage(bufImage); + cachedImageFilename = fileName; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java index 4fd8823ea..f8718b1e6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineExternalImage2.java @@ -44,7 +44,7 @@ import net.npe.dds.DDSReader; * * @author JPEXS */ -public class DefineExternalImage2 extends ImageTag { +public class DefineExternalImage2 extends AbstractGfxImageTag { public static final int ID = 1009; @@ -73,21 +73,7 @@ public class DefineExternalImage2 extends ImageTag { public String fileName; - public byte[] extraData; //? - - public static final int BITMAP_FORMAT_DEFAULT = 0; - - public static final int BITMAP_FORMAT_TGA = 1; - - public static final int BITMAP_FORMAT_DDS = 2; - - //It looks like gfxexport produces BITMAP_FORMAT2_* values for format, - //but BITMAP_FORMAT_* works the same way - public static final int BITMAP_FORMAT2_JPEG = 10; - - public static final int BITMAP_FORMAT2_TGA = 13; - - public static final int BITMAP_FORMAT2_DDS = 14; + public byte[] extraData; //? @HideInRawEdit private SerializableImage serImage; @@ -202,54 +188,27 @@ public class DefineExternalImage2 extends ImageTag { } private void initImage() { - if (!Objects.equals(cachedImageFilename, fileName) - || (serImage != null && (serImage.getWidth() != targetWidth || serImage.getHeight() != targetHeight))) { - - if (targetWidth <= 0 || targetHeight <= 0) { - serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); - serImage.fillTransparent(); - } else if (bitmapFormat == BITMAP_FORMAT2_JPEG || bitmapFormat == BITMAP_FORMAT2_TGA || bitmapFormat == BITMAP_FORMAT_TGA) { - Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName)); - if (imagePath != null && imagePath.toFile().exists()) { - try { - if (bitmapFormat == BITMAP_FORMAT2_TGA || bitmapFormat == BITMAP_FORMAT_TGA) { - TgaSupport.init(); - } - BufferedImage bufImage = ImageIO.read(imagePath.toFile()); - Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, 0, 0, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = fileName; - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } else if (bitmapFormat == BITMAP_FORMAT2_DDS || bitmapFormat == BITMAP_FORMAT_DDS) { - Path imagePath = getSwf().getFile() == null ? null : Paths.get(getSwf().getFile()).getParent().resolve(Paths.get(fileName)); - if (imagePath != null && imagePath.toFile().exists()) { - try { - byte[] imageData = Files.readAllBytes(imagePath); - int[] pixels = DDSReader.read(imageData, DDSReader.ARGB, 0); - BufferedImage bufImage = new BufferedImage(DDSReader.getWidth(imageData), DDSReader.getHeight(imageData), BufferedImage.TYPE_INT_ARGB); - bufImage.getRaster().setDataElements(0, 0, bufImage.getWidth(), bufImage.getHeight(), pixels); - Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, 0, 0, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = fileName; - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } else { - createFailedImage(); - } + if (Objects.equals(cachedImageFilename, fileName) + && serImage != null && (serImage.getWidth() == targetWidth && serImage.getHeight() == targetHeight)) { + return; } + + if (targetWidth <= 0 || targetHeight <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } + + BufferedImage bufImage = getExternalBufferedImage(fileName, bitmapFormat); + if (bufImage == null) { + createFailedImage(); + return; + } + Image scaled = bufImage.getScaledInstance(targetWidth, targetHeight, Image.SCALE_DEFAULT); + bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); + bufImage.getGraphics().drawImage(scaled, 0, 0, null); + serImage = new SerializableImage(bufImage); + cachedImageFilename = fileName; } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java index 45c46e7e5..1e4dd2387 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/gfx/DefineSubImage.java @@ -43,7 +43,7 @@ import net.npe.dds.DDSReader; * * @author JPEXS */ -public class DefineSubImage extends ImageTag { +public class DefineSubImage extends AbstractGfxImageTag { public static final int ID = 1008; @@ -186,68 +186,38 @@ public class DefineSubImage extends ImageTag { int targetHeight = y2 - y1; int bitmapFormat = image.bitmapFormat; - if (!Objects.equals(cachedImageFilename, image.fileName) - || !Objects.equals(cachedX1, (Integer) x1) - || !Objects.equals(cachedX2, (Integer) x2) - || !Objects.equals(cachedY1, (Integer) y1) - || !Objects.equals(cachedY2, (Integer) y2) - || (serImage != null && (serImage.getWidth() != targetWidth || serImage.getHeight() != targetHeight))) { - - if (targetWidth <= 0 || targetHeight <= 0) { - serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); - serImage.fillTransparent(); - return; - } - - Path imagePath = image.getSwf().getFile() == null ? null : Paths.get(image.getSwf().getFile()).getParent().resolve(Paths.get(image.fileName)); - if (imagePath != null && imagePath.toFile().exists()) { - if (bitmapFormat == DefineExternalImage2.BITMAP_FORMAT2_JPEG - || bitmapFormat == DefineExternalImage2.BITMAP_FORMAT2_TGA - || bitmapFormat == DefineExternalImage2.BITMAP_FORMAT_TGA) { - try { - if (bitmapFormat == DefineExternalImage2.BITMAP_FORMAT2_TGA - || bitmapFormat == DefineExternalImage2.BITMAP_FORMAT_TGA) { - TgaSupport.init(); - } - BufferedImage bufImage = ImageIO.read(imagePath.toFile()); - Image scaled = bufImage.getScaledInstance(image.targetWidth, image.targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, -x1, -y1, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = image.fileName; - cachedX1 = x1; - cachedX2 = x2; - cachedY1 = y1; - cachedY2 = y2; - } catch (IOException ex) { - createFailedImage(); - } - } else if (bitmapFormat == DefineExternalImage2.BITMAP_FORMAT2_DDS - || bitmapFormat == DefineExternalImage2.BITMAP_FORMAT_DDS) { - try { - byte[] imageData = Files.readAllBytes(imagePath); - int[] pixels = DDSReader.read(imageData, DDSReader.ARGB, 0); - BufferedImage bufImage = new BufferedImage(DDSReader.getWidth(imageData), DDSReader.getHeight(imageData), BufferedImage.TYPE_INT_ARGB); - bufImage.getRaster().setDataElements(0, 0, bufImage.getWidth(), bufImage.getHeight(), pixels); - Image scaled = bufImage.getScaledInstance(image.targetWidth, image.targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, -x1, -y1, null); - serImage = new SerializableImage(bufImage); - cachedImageFilename = image.fileName; - cachedX1 = x1; - cachedX2 = x2; - cachedY1 = y1; - cachedY2 = y2; - } catch (IOException e) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } else { - createFailedImage(); - } + if (Objects.equals(cachedImageFilename, image.fileName) + && Objects.equals(cachedX1, (Integer) x1) + && Objects.equals(cachedX2, (Integer) x2) + && Objects.equals(cachedY1, (Integer) y1) + && Objects.equals(cachedY2, (Integer) y2) + && serImage != null + && serImage.getWidth() == targetWidth + && serImage.getHeight() == targetHeight) { + return; } + + if (targetWidth <= 0 || targetHeight <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } + + BufferedImage bufImage = getExternalBufferedImage(image.fileName, bitmapFormat); + if (bufImage == null) { + createFailedImage(); + return; + } + + Image scaled = bufImage.getScaledInstance(image.targetWidth, image.targetHeight, Image.SCALE_DEFAULT); + bufImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB); + bufImage.getGraphics().drawImage(scaled, -x1, -y1, null); + serImage = new SerializableImage(bufImage); + cachedImageFilename = image.fileName; + cachedX1 = x1; + cachedX2 = x2; + cachedY1 = y1; + cachedY2 = y2; } @Override