diff --git a/CHANGELOG.md b/CHANGELOG.md index ec2d871ee..ab7b274a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this project will be documented in this file. - GFX: DefineExternalImage2 properly saving characterId - Hex view refreshing after selecting Unknown tag - [#1818] GFX: Importing XML +- GFX: Correct refreshing image when raw editing DefineExternalImage/2, DefineSubImage ## [16.0.4] - 2022-11-03 ### Fixed 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 55e24d6ac..bc42a7c8d 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 @@ -35,6 +35,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; import net.npe.dds.DDSReader; /** @@ -66,6 +67,9 @@ public class DefineExternalImage extends ImageTag { @HideInRawEdit private SerializableImage serImage; + @HideInRawEdit + private String cachedImageFilename = null; + /** * Gets data bytes * @@ -102,8 +106,6 @@ public class DefineExternalImage extends ImageTag { targetHeight = 1; createFailedImage(); } - - @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { @@ -113,39 +115,20 @@ public class DefineExternalImage extends ImageTag { targetHeight = sis.readUI16("targetHeight"); exportName = sis.readNetString("exportName"); fileName = sis.readNetString("fileName"); - - if (bitmapFormat == BITMAP_FORMAT_TGA) { - serImage = new SerializableImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB_PRE); - Graphics g = serImage.getGraphics(); - g.setColor(Color.red); - g.fillRect(0, 0, targetWidth, targetHeight); - return; - } - - Path imagePath = sis.getSwf().getFile() == null ? null : Paths.get(sis.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); - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } } private void createFailedImage() { + if (targetWidth <= 0 || targetHeight <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } + serImage = new SerializableImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB_PRE); Graphics g = serImage.getGraphics(); g.setColor(Color.red); g.fillRect(0, 0, targetWidth, targetHeight); + cachedImageFilename = null; } @Override @@ -172,11 +155,47 @@ public class DefineExternalImage extends ImageTag { @Override protected SerializableImage getImage() { + initImage(); return serImage; } @Override public Dimension getImageDimension() { - return new Dimension(serImage.getWidth(), serImage.getHeight()); + return new Dimension(targetWidth, targetHeight); + } + + 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(); + return; + } + + if (bitmapFormat == BITMAP_FORMAT_TGA) { + createFailedImage(); + return; + } + + 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); + } catch (IOException ex) { + createFailedImage(); + } + } else { + createFailedImage(); + } + } } } 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 a1dd958fb..8ba4f2892 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 @@ -35,6 +35,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; import net.npe.dds.DDSReader; /** @@ -69,7 +70,10 @@ public class DefineExternalImage2 extends ImageTag { @HideInRawEdit private SerializableImage serImage; - + + @HideInRawEdit + private String cachedImageFilename = null; + /** * Gets data bytes * @@ -109,7 +113,7 @@ public class DefineExternalImage2 extends ImageTag { targetWidth = 1; targetHeight = 1; createFailedImage(); - } + } @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { @@ -123,38 +127,20 @@ public class DefineExternalImage2 extends ImageTag { if (sis.available() > 0) { //there is usually one zero byte, god knows why extraData = sis.readBytesEx(sis.available(), "extraData"); } - if (bitmapFormat == BITMAP_FORMAT_TGA) { - serImage = new SerializableImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB_PRE); - Graphics g = serImage.getGraphics(); - g.setColor(Color.red); - g.fillRect(0, 0, targetWidth, targetHeight); - return; - } - - Path imagePath = sis.getSwf().getFile() == null ? null : Paths.get(sis.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); - } catch (IOException ex) { - createFailedImage(); - } - } else { - createFailedImage(); - } } private void createFailedImage() { + if (targetWidth <= 0 || targetHeight <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } + serImage = new SerializableImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_ARGB_PRE); Graphics g = serImage.getGraphics(); g.setColor(Color.red); g.fillRect(0, 0, targetWidth, targetHeight); + cachedImageFilename = null; } @Override @@ -181,11 +167,47 @@ public class DefineExternalImage2 extends ImageTag { @Override public SerializableImage getImage() { + initImage(); return serImage; } @Override public Dimension getImageDimension() { - return new Dimension(serImage.getWidth(), serImage.getHeight()); + return new Dimension(targetWidth, targetHeight); + } + + 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(); + return; + } + + if (bitmapFormat == BITMAP_FORMAT_TGA) { + createFailedImage(); + return; + } + 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(); + } + } } } 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 3dc77cb1c..9c23fc1e3 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 @@ -35,6 +35,7 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Objects; import java.util.Set; import net.npe.dds.DDSReader; @@ -61,6 +62,18 @@ public class DefineSubImage extends ImageTag { @HideInRawEdit private SerializableImage serImage; + @HideInRawEdit + private String cachedImageFilename = null; + + @HideInRawEdit + private Integer cachedX1 = null; + @HideInRawEdit + private Integer cachedY1 = null; + @HideInRawEdit + private Integer cachedX2 = null; + @HideInRawEdit + private Integer cachedY2 = null; + /** * Gets data bytes * @@ -95,11 +108,9 @@ public class DefineSubImage extends ImageTag { x1 = 0; x2 = 1; y1 = 0; - y2 = 1; + y2 = 1; createFailedImage(); } - - @Override public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { @@ -135,35 +146,25 @@ public class DefineSubImage extends ImageTag { @Override protected SerializableImage getImage() { - if (serImage == null) { - DefineExternalImage2 image = (DefineExternalImage2) swf.getImage(imageCharacterId | 0x8000); - - Path imagePath = image.getSwf().getFile() == null ? null : Paths.get(image.getSwf().getFile()).getParent().resolve(Paths.get(image.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(image.targetWidth, image.targetHeight, Image.SCALE_DEFAULT); - bufImage = new BufferedImage(x2 - x1, y2 - y1, BufferedImage.TYPE_INT_ARGB); - bufImage.getGraphics().drawImage(scaled, -x1, -y1, null); - serImage = new SerializableImage(bufImage); - } catch (IOException e) { - createFailedImage(); - } - } else { - createFailedImage(); - } - } + initImage(); return serImage; } private void createFailedImage() { + if (x2 - x1 <= 0 || y2 - y1 <= 0) { + serImage = new SerializableImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR_PRE); + serImage.fillTransparent(); + return; + } serImage = new SerializableImage(x2 - x1, y2 - y1, BufferedImage.TYPE_INT_ARGB_PRE); Graphics g = serImage.getGraphics(); g.setColor(Color.red); g.fillRect(0, 0, x2 - x1, y2 - y1); + cachedImageFilename = null; + cachedX1 = x1; + cachedX2 = x2; + cachedY1 = y1; + cachedY2 = y2; } @Override @@ -175,4 +176,52 @@ public class DefineSubImage extends ImageTag { public void getNeededCharacters(Set needed) { needed.add(imageCharacterId | 0x8000); } + + private void initImage() { + DefineExternalImage2 image = (DefineExternalImage2) swf.getImage(imageCharacterId | 0x8000); + + if (image == null) { + createFailedImage(); + return; + } + int targetWidth = x2 - x1; + int targetHeight = y2 - y1; + + 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()) { + 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(); + } + } + } }