diff --git a/CHANGELOG.md b/CHANGELOG.md index 836d41750..8862085e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ All notable changes to this project will be documented in this file. hilight float instruction blue - Icons for every tag type - [#2499] Information about frames which do not have ShowFrame tag +- [#2504] WebP image format for export/import (not animated) + Limitation: It's not available on Mac x86-64 platform ### Fixed - [#2474] Gotos incorrectly decompiled @@ -3951,6 +3953,7 @@ Major version of SWF to XML export changed to 2. [#2478]: https://www.free-decompiler.com/flash/issues/2478 [#2485]: https://www.free-decompiler.com/flash/issues/2485 [#2499]: https://www.free-decompiler.com/flash/issues/2499 +[#2504]: https://www.free-decompiler.com/flash/issues/2504 [#2474]: https://www.free-decompiler.com/flash/issues/2474 [#2480]: https://www.free-decompiler.com/flash/issues/2480 [#2338]: https://www.free-decompiler.com/flash/issues/2338 diff --git a/lib/webp4j-1.1.0.jar b/lib/webp4j-1.1.0.jar new file mode 100644 index 000000000..f072fb8b8 Binary files /dev/null and b/lib/webp4j-1.1.0.jar differ diff --git a/lib/webp4j.license.txt b/lib/webp4j.license.txt new file mode 100644 index 000000000..8e11a7dd4 --- /dev/null +++ b/lib/webp4j.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Mr Nanko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libsrc/ffdec_lib/README.md b/libsrc/ffdec_lib/README.md index ae179feac..d2a2c74bf 100644 --- a/libsrc/ffdec_lib/README.md +++ b/libsrc/ffdec_lib/README.md @@ -124,9 +124,10 @@ It uses modified code of these libraries: * UAB "DKD" NellyMoser ASAO codec (Decoding Nelly Moser sound format) - LGPL * [Animated GIF Writer] (Frames to GIF export) - Creative Commons Attribution 3.0 Unported * [Animated GIF Encoder] (Frames to GIF export) -* [gnujpdf] (PDF export) - LGPL License -* [openjdk8 Stroker] (Shapes - Miter clip drawing) - GPL License -* [Apache Flex SDK] (Decimal numbers support - Decimal128 class) - Apache Licence 2.0 +* [gnujpdf] (PDF export) - LGPL +* [openjdk8 Stroker] (Shapes - Miter clip drawing) - GPL +* [Apache Flex SDK] (Decimal numbers support - Decimal128 class) - Apache License 2.0 +* [webp4j] (WEBP format export/import) - MIT And also links to these libraries: @@ -166,3 +167,4 @@ And also links to these libraries: [FLA Compound Document Tools]: https://github.com/jindrapetrik/flacomdoc [TomlJ]: https://github.com/tomlj/tomlj [ANTLR]: https://www.antlr.org/ +[webp4j]: https://github.com/jindrapetrik/webp4j/tree/java8 \ No newline at end of file diff --git a/libsrc/ffdec_lib/lib/webp4j-1.1.0.jar b/libsrc/ffdec_lib/lib/webp4j-1.1.0.jar new file mode 100644 index 000000000..f072fb8b8 Binary files /dev/null and b/libsrc/ffdec_lib/lib/webp4j-1.1.0.jar differ diff --git a/libsrc/ffdec_lib/lib/webp4j.license.txt b/libsrc/ffdec_lib/lib/webp4j.license.txt new file mode 100644 index 000000000..8e11a7dd4 --- /dev/null +++ b/libsrc/ffdec_lib/lib/webp4j.license.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Mr Nanko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libsrc/ffdec_lib/nbproject/project.xml b/libsrc/ffdec_lib/nbproject/project.xml index f9b884508..ceb64bc37 100644 --- a/libsrc/ffdec_lib/nbproject/project.xml +++ b/libsrc/ffdec_lib/nbproject/project.xml @@ -242,7 +242,7 @@ auxiliary.show.customizer.message= src - ../../src;lib/LZMA.jar;lib/avi.jar;lib/cmykjpeg.jar;lib/ddsreader.jar;lib/gif.jar;lib/gnujpdf.jar;lib/jlayer-1.0.2.jar;lib/jpacker.jar;lib/nellymoser.jar;lib/sfntly.jar;lib/tga.jar;lib/ttf.jar;lib/vlcj-4.7.3.jar;lib/vlcj-natives-4.7.0.jar;lib/flashdebugger.jar;lib/jna-3.5.1.jar;lib/jna-platform-3.5.1.jar;lib/gifreader.jar;lib/miterstroke.jar;lib/decimal.jar;lib/flacomdoc.jar;lib/tomlj-1.1.1.jar;lib/decimal.jar + ../../src;lib/LZMA.jar;lib/avi.jar;lib/cmykjpeg.jar;lib/ddsreader.jar;lib/gif.jar;lib/gnujpdf.jar;lib/jlayer-1.0.2.jar;lib/jpacker.jar;lib/nellymoser.jar;lib/sfntly.jar;lib/tga.jar;lib/ttf.jar;lib/vlcj-4.7.3.jar;lib/vlcj-natives-4.7.0.jar;lib/flashdebugger.jar;lib/jna-3.5.1.jar;lib/jna-platform-3.5.1.jar;lib/gifreader.jar;lib/miterstroke.jar;lib/decimal.jar;lib/flacomdoc.jar;lib/tomlj-1.1.1.jar;lib/decimal.jar;lib/webp4j-1.1.0.jar build reports dist diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java index e3fa4bc34..38ed9dad8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -63,6 +63,7 @@ import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; +import dev.matrixlab.webp4j.WebPCodec; import gnu.jpdf.PDFGraphics; import gnu.jpdf.PDFJob; import java.awt.AlphaComposite; @@ -120,6 +121,9 @@ public class FrameExporter { case SVG: fem = FrameExportMode.SVG; break; + case WEBP: + fem = FrameExportMode.WEBP; + break; case SWF: fem = FrameExportMode.SWF; break; @@ -160,6 +164,9 @@ public class FrameExporter { case BMP: fem = FrameExportMode.BMP; break; + case WEBP: + fem = FrameExportMode.WEBP; + break; case SWF: fem = FrameExportMode.SWF; break; @@ -513,7 +520,9 @@ public class FrameExporter { } final Color fbackgroundColor = backgroundColor; - final boolean usesTransparency = settings.mode == FrameExportMode.PNG || settings.mode == FrameExportMode.GIF; + final boolean usesTransparency = settings.mode == FrameExportMode.PNG + || settings.mode == FrameExportMode.GIF + || settings.mode == FrameExportMode.WEBP; final MyFrameIterator frameImages = new MyFrameIterator(tim, fframes, evl, usesTransparency, backgroundColor, settings, subFramesLength); switch (settings.mode) { @@ -545,6 +554,26 @@ public class FrameExporter { } } break; + case WEBP: + for (File foutdir : foutdirs) { + frameImages.reset(); + for (int i = 0; frameImages.hasNext(); i++) { + final int fi = i; + new RetryTask(() -> { + int fileNum = subFramesLength > 1 ? fi + 1 : (fframes.get(fi) + 1); + + File f = new File(foutdir + File.separator + fileNum + ".webp"); + BufferedImage img = frameImages.next(); + if (img != null) { + try(FileOutputStream fos = new FileOutputStream(f)) { + fos.write(WebPCodec.encodeImage(img, 100f)); + } + } + ret.add(f); + }, handler).run(); + } + } + break; case PNG: for (File foutdir : foutdirs) { frameImages.reset(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java index 2457ada17..104ea88d2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java @@ -33,6 +33,7 @@ import com.jpexs.decompiler.graph.DottedChain; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; @@ -110,6 +111,11 @@ public class ImageExporter { if (settings.mode == ImageExportMode.BMP) { fileFormat = ImageFormat.BMP; } + + if (settings.mode == ImageExportMode.WEBP) { + fileFormat = ImageFormat.WEBP; + } + final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + ImageHelper.getImageFormatString(fileFormat))); final ImageFormat ffileFormat = fileFormat; @@ -121,6 +127,10 @@ public class ImageExporter { } } else if (ffileFormat == ImageFormat.BMP) { BMPFile.saveBitmap(imageTag.getImageCached().getBufferedImage(), file); + } else if (ffileFormat == ImageFormat.WEBP) { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + fos.write(WebPCodec.encodeImage(imageTag.getImageCached().getBufferedImage(), 100f)); + } } else { ImageHelper.write(imageTag.getImageCached().getBufferedImage(), ffileFormat, file); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java index 42aa928b3..be5f9c039 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java @@ -48,6 +48,7 @@ import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.Graphics2D; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; @@ -158,6 +159,7 @@ public class MorphShapeExporter { break; case PNG_START_END: case BMP_START_END: + case WEBP_START_END: double unzoom = settings.zoom; st = mst.getStartShapeTag(); rect = st.getRect(); @@ -178,6 +180,10 @@ public class MorphShapeExporter { st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true); if (settings.mode == MorphShapeExportMode.PNG_START_END) { ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, fileStart); + } else if (settings.mode == MorphShapeExportMode.WEBP_START_END) { + try(FileOutputStream fos = new FileOutputStream(fileStart)) { + fos.write(WebPCodec.encodeImage(img.getBufferedImage(), 100f)); + } } else { BMPFile.saveBitmap(img.getBufferedImage(), fileStart); } @@ -201,6 +207,10 @@ public class MorphShapeExporter { st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true); if (settings.mode == MorphShapeExportMode.PNG_START_END) { ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, fileEnd); + } else if (settings.mode == MorphShapeExportMode.WEBP_START_END) { + try(FileOutputStream fos = new FileOutputStream(fileEnd)) { + fos.write(WebPCodec.encodeImage(img.getBufferedImage(), 100f)); + } } else { BMPFile.saveBitmap(img.getBufferedImage(), fileEnd); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 557296b2e..b9e1fc276 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -46,6 +46,7 @@ import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.Graphics2D; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; @@ -122,6 +123,7 @@ public class ShapeExporter { break; case PNG: case BMP: + case WEBP: int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1; int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1; SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE); @@ -137,6 +139,10 @@ public class ShapeExporter { st.toImage(0, 0, 0, new RenderContext(), img, img, false, m, m, m, m, new CXFORMWITHALPHA(), unzoom, false, new ExportRectangle(rect), new ExportRectangle(rect), true, Timeline.DRAW_MODE_ALL, 0, true); if (settings.mode == ShapeExportMode.PNG) { ImageHelper.write(img.getBufferedImage(), ImageFormat.PNG, file); + } else if (settings.mode == ShapeExportMode.WEBP) { + try(FileOutputStream fos = new FileOutputStream(file)) { + fos.write(WebPCodec.encodeImage(img.getBufferedImage(), 100f)); + } } else { BMPFile.saveBitmap(img.getBufferedImage(), file); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ButtonExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ButtonExportMode.java index 3a827276e..98674cf63 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ButtonExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ButtonExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Button export mode. * @@ -34,8 +36,19 @@ public enum ButtonExportMode { * BMP - Windows Bitmap */ BMP, + /** + * WEBP + */ + WEBP, /** * SWF - Shockwave Flash */ - SWF, + SWF; + + public boolean available() { + if (this == WEBP) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FrameExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FrameExportMode.java index c47868df0..6efb9b712 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FrameExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FrameExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Frame export mode. * @@ -50,8 +52,19 @@ public enum FrameExportMode { * BMP - Windows Bitmap */ BMP, + /** + * WEBP + */ + WEBP, /** * SWF - Shockwave Flash */ - SWF, + SWF; + + public boolean available() { + if (this == WEBP) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java index 303983e8b..4fe6c2642 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Image export mode. * @@ -42,5 +44,16 @@ public enum ImageExportMode { /** * PNG, GIF or JPEG, depending on what suits the best, plus alpha channel */ - PNG_GIF_JPEG_ALPHA + PNG_GIF_JPEG_ALPHA, + /* + * WEBP + */ + WEBP; + + public boolean available() { + if (this == WEBP) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java index 4b73b4a1b..2b0ed59a7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Morph shape export mode. * @@ -44,10 +46,21 @@ public enum MorphShapeExportMode { * BMP start and end frames - Windows Bitmap */ BMP_START_END, + /** + * WEBP start and end frames + */ + WEBP_START_END, //GIF, //AVI, /** * SWF - Shockwave Flash */ - SWF, + SWF; + + public boolean available() { + if (this == WEBP_START_END) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java index 2447e1fa4..213014e5a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Shape export mode. * @@ -38,8 +40,19 @@ public enum ShapeExportMode { * BMP - Windows Bitmap */ BMP, + /** + * WEBP + */ + WEBP, /** * SWF - Shockwave Flash */ - SWF, + SWF; + + public boolean available() { + if (this == WEBP) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/SpriteExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/SpriteExportMode.java index e6ab76621..092427cf0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/SpriteExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/SpriteExportMode.java @@ -16,6 +16,8 @@ */ package com.jpexs.decompiler.flash.exporters.modes; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; + /** * Sprite export mode. * @@ -50,8 +52,19 @@ public enum SpriteExportMode { * BMP - Windows Bitmap */ BMP, + /** + * WEBP + */ + WEBP, /** * SWF - Shockwave Flash */ - SWF, + SWF; + + public boolean available() { + if (this == WEBP) { + return ImageFormat.WEBP.available(); + } + return true; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/MorphShapeExportSettings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/MorphShapeExportSettings.java index c5699c78e..e7d9a6950 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/MorphShapeExportSettings.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/MorphShapeExportSettings.java @@ -60,6 +60,8 @@ public class MorphShapeExportSettings { return ".png"; case BMP_START_END: return ".bmp"; + case WEBP_START_END: + return ".webp"; case SVG: case SVG_START_END: return ".svg"; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/ShapeExportSettings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/ShapeExportSettings.java index 80d7a57be..ab57c4465 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/ShapeExportSettings.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/ShapeExportSettings.java @@ -64,6 +64,8 @@ public class ShapeExportSettings { return ".bmp"; case CANVAS: return ".html"; + case WEBP: + return ".webp"; case SWF: return ".swf"; default: diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java index e3c4a2641..df125dc6b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/ImageHelper.java @@ -226,6 +226,8 @@ public class ImageHelper { return "png"; case BMP: return "bmp"; + case WEBP: + return "webp"; } throw new Error("Unsupported image format: " + format); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java index ac2dca61e..0a7d4e55c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java @@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; @@ -77,6 +78,20 @@ public class ImageImporter extends TagImporter { ImageHelper.write(b, ImageFormat.PNG, baos); newData = baos.toByteArray(); } + if (newData.length >= 4 + && newData[0] == 'R' + && newData[1] == 'I' + && newData[2] == 'F' + && newData[3] == 'F') + { + if (!ImageFormat.WEBP.available()) { + throw new RuntimeException("WEBP format is not supported on your platform"); + } + BufferedImage b = WebPCodec.decodeImage(newData); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageHelper.write(b, ImageFormat.PNG, baos); + newData = baos.toByteArray(); + } if (tagType == 0) { if (it instanceof DefineBitsTag) { @@ -94,7 +109,7 @@ public class ImageImporter extends TagImporter { && newData[3] == (byte) 0xe0) { tagType = DefineBitsJPEG2Tag.ID; } else { - tagType = DefineBitsLosslessTag.ID; + tagType = DefineBitsLossless2Tag.ID; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java index ca2838245..5d5d0075e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java @@ -38,10 +38,12 @@ import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.helpers.CancellableWorker; import com.jpexs.helpers.Helper; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.Dimension; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.util.ArrayList; @@ -162,6 +164,21 @@ public class ShapeImporter { ImageHelper.write(b, ImageFormat.PNG, baos); newData = baos.toByteArray(); } + + if (newData.length >= 4 + && newData[0] == 'R' + && newData[1] == 'I' + && newData[2] == 'F' + && newData[3] == 'F') + { + if (!ImageFormat.WEBP.available()) { + throw new RuntimeException("WEBP format is not supported on your platform"); + } + BufferedImage b = WebPCodec.decodeImage(newData); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ImageHelper.write(b, ImageFormat.PNG, baos); + newData = baos.toByteArray(); + } if (tagType == 0) { if (ImageTag.getImageFormat(newData) == ImageFormat.JPEG) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java index 3e1e875ec..9cefdf54e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/enums/ImageFormat.java @@ -16,6 +16,9 @@ */ package com.jpexs.decompiler.flash.tags.enums; +import dev.matrixlab.webp4j.NativeWebP; +import dev.matrixlab.webp4j.WebPCodec; + /** * Image format. * @@ -42,7 +45,11 @@ public enum ImageFormat { /** * BMP */ - BMP(".bmp"); + BMP(".bmp"), + /** + * WEBP + */ + WEBP(".webp"); private final String extension; @@ -57,4 +64,15 @@ public enum ImageFormat { public String getExtension() { return extension; } + + public boolean available() { + if (this == WEBP) { + try { + new NativeWebP(); + } catch (Throwable t) { + return false; + } + } + return true; + } } diff --git a/nbproject/project.xml b/nbproject/project.xml index 9c3252c19..849b5e675 100644 --- a/nbproject/project.xml +++ b/nbproject/project.xml @@ -329,7 +329,7 @@ src - lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-fix.jar;lib/substance-6.2.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar;lib/flashdebugger.jar;lib/treetable.jar;lib/minimal-json-0.9.5.jar;libsrc/ffdec_lib/lib/gnujpdf.jar;libsrc/ffdec_lib/lib/jna-3.5.1.jar;libsrc/ffdec_lib/lib/jna-platform-3.5.1.jar;libsrc/ffdec_lib/lib/flashdebugger.jar;lib/gifreader.jar;lib/jansi-2.4.0.jar;lib/decimal.jar + lib/jpproxy.jar;lib/trident-6.2.jar;lib/substance-flamingo-6.2.jar;lib/flamingo-6.2.jar;lib/substance-fix.jar;lib/substance-6.2.jar;libsrc/ffdec_lib/src;lib/tablelayout.jar;lib/jsyntaxpane-0.9.5.jar;lib/JavactiveX.jar;lib/flashdebugger.jar;lib/treetable.jar;lib/minimal-json-0.9.5.jar;libsrc/ffdec_lib/lib/gnujpdf.jar;libsrc/ffdec_lib/lib/jna-3.5.1.jar;libsrc/ffdec_lib/lib/jna-platform-3.5.1.jar;libsrc/ffdec_lib/lib/flashdebugger.jar;lib/gifreader.jar;lib/jansi-2.4.0.jar;lib/decimal.jar;lib/webp4j-1.1.0.jar build javadoc reports diff --git a/src/com/jpexs/decompiler/flash/console/help.txt b/src/com/jpexs/decompiler/flash/console/help.txt index ee4106806..023723bda 100644 --- a/src/com/jpexs/decompiler/flash/console/help.txt +++ b/src/com/jpexs/decompiler/flash/console/help.txt @@ -210,8 +210,7 @@ alias /? -format (optional, html is default) Selects output format is currently only html -locale (optional) Override default locale - is localization identifier, en for english for example - is currently only html + is localization identifier, en for english for example -getInstanceMetadata -instance [-outputFormat ] \ [-key ] [-datafile ] @@ -324,8 +323,12 @@ Pre-options: shape:png - PNG format for Shapes shape:canvas - HTML5 Canvas format for Shapes shape:bmp - BMP format for Shapes + shape:webp - WEBP format for Shapes morphshape:svg - SVG format for MorphShapes morphshape:canvas - HTML5 Canvas format for MorphShapes + morpshape:png_start_end - PNG start-end format for MorphShapes + morpshape:bmp_start_end - BMP start-end format for MorphShapes + morpshape:webp_start_end - WEBP start-end format for MorphShapes frame:png - PNG format for Frames frame:gif - GIF format for Frames frame:avi - AVI format for Frames @@ -333,6 +336,7 @@ Pre-options: frame:canvas - HTML5 Canvas format for Frames frame:pdf - PDF format for Frames frame:bmp - BMP format for Frames + frame:webp - WEBP format for Frames sprite:png - PNG format for Sprites sprite:gif - GIF format for Sprites sprite:avi - AVI format for Sprites @@ -340,14 +344,17 @@ Pre-options: sprite:canvas - HTML5 Canvas format for Sprites sprite:pdf - PDF format for Sprites sprite:bmp - BMP format for Sprites + sprite:webp - WEBP format for Sprites button:png - PNG format for Buttons button:svg - SVG format for Buttons button:bmp - BMP format for Buttons + button:webp - WEBP format for Buttons image:png_gif_jpeg - PNG/GIF/JPEG format for Images image:png - PNG format for Images image:jpeg - JPEG format for Images image:bmp - BMP format for Images image:png_gif_jpeg_alpha - PNG/GIF/JPEG+ALPHA format for Images + image:webp - WEBP format for Images text:plain - Plain text format for Texts text:formatted - Formatted text format for Texts text:svg - SVG format for Texts diff --git a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java index 12121113f..ea1904044 100644 --- a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java @@ -59,10 +59,14 @@ import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Window; import java.awt.event.ActionEvent; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JCheckBox; @@ -141,7 +145,7 @@ public class ExportDialog extends AppDialog { ButtonExportMode.class }; - private final JComboBox[] combos; + private final JComboBox[] combos; private final JCheckBox[] checkBoxes; @@ -157,9 +161,8 @@ public class ExportDialog extends AppDialog { public E getValue(Class option) { for (int i = 0; i < optionClasses.length; i++) { - if (option == optionClasses[i]) { - E[] values = option.getEnumConstants(); - return values[combos[i].getSelectedIndex()]; + if (option == optionClasses[i]) { + return (E) ((ComboValue) combos[i].getSelectedItem()).value; } } @@ -199,10 +202,9 @@ public class ExportDialog extends AppDialog { private void saveConfig() { StringBuilder cfg = new StringBuilder(); for (int i = 0; i < optionNames.length; i++) { - int selIndex = combos[i].getSelectedIndex(); + Object val = ((ComboValue) combos[i].getSelectedItem()).value; Class c = optionClasses[i]; - Object[] vals = c.getEnumConstants(); - String key = optionNames[i] + "." + vals[selIndex].toString().toLowerCase(Locale.ENGLISH); + String key = optionNames[i] + "." + val.toString().toLowerCase(Locale.ENGLISH); if (i > 0) { cfg.append(","); } @@ -321,17 +323,31 @@ public class ExportDialog extends AppDialog { for (int i = 0; i < optionNames.length; i++) { Class c = optionClasses[i]; Object[] vals = c.getEnumConstants(); - String[] names = new String[vals.length]; + List namesList = new ArrayList<>(); int itemIndex = -1; for (int j = 0; j < vals.length; j++) { - + try { + Method availableMethod = c.getMethod("available"); + if (!(Boolean)availableMethod.invoke(vals[j])) + { + continue; + } + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) { + //ignore + } + //ignore + //ignore + String key = optionNames[i] + "." + vals[j].toString().toLowerCase(Locale.ENGLISH); if (exportFormats.contains(key)) { itemIndex = j; } - names[j] = translate(key); + + namesList.add(new ComboValue(vals[j], translate(key))); } + ComboValue[] names = namesList.toArray(new ComboValue[0]); + combos[i] = new JComboBox<>(names); if (itemIndex > -1) { combos[i].setSelectedIndex(itemIndex); @@ -494,4 +510,19 @@ public class ExportDialog extends AppDialog { setVisible(true); return result; } + + private class ComboValue { + public Object value; + public String text; + + public ComboValue(Object value, String text) { + this.value = value; + this.text = text; + } + + @Override + public String toString() { + return text; + } + } } diff --git a/src/com/jpexs/decompiler/flash/gui/FileChooserImagePreview.java b/src/com/jpexs/decompiler/flash/gui/FileChooserImagePreview.java index 3fe1b072a..06846d589 100644 --- a/src/com/jpexs/decompiler/flash/gui/FileChooserImagePreview.java +++ b/src/com/jpexs/decompiler/flash/gui/FileChooserImagePreview.java @@ -16,14 +16,21 @@ */ package com.jpexs.decompiler.flash.gui; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; +import com.jpexs.helpers.Helper; +import dev.matrixlab.webp4j.WebPCodec; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.MediaTracker; +import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JFileChooser; @@ -87,9 +94,26 @@ public class FileChooserImagePreview extends JComponent return; } - ImageIcon tmpIcon = new ImageIcon(file.getPath()); + BufferedImage img = null; + if (file.getPath().toLowerCase().endsWith(".webp")) { + if (ImageFormat.WEBP.available()) { + try { + img = WebPCodec.decodeImage(Helper.readFile(file.getAbsolutePath())); + } catch (IOException ex) { + //ignore + } + } + } else { + try(FileInputStream fis = new FileInputStream(file)) { + img = ImageHelper.read(fis); + } catch (IOException ex) { + //ignore + } + } + + if (img != null) { + ImageIcon tmpIcon = new ImageIcon(img); - if (tmpIcon != null) { if (tmpIcon.getImageLoadStatus() == MediaTracker.COMPLETE) { if (tmpIcon.getIconWidth() > PREVIEW_SIZE) { thumbnail = new ImageIcon(tmpIcon.getImage().getScaledInstance(PREVIEW_SIZE, -1, Image.SCALE_DEFAULT)); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 5ee039b7c..611665ee2 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -182,6 +182,7 @@ import com.jpexs.decompiler.flash.tags.base.SymbolClassTypeTag; import com.jpexs.decompiler.flash.tags.base.TextImportErrorHandler; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.base.UnsupportedSamplingRateException; +import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.tags.gfx.DefineExternalStreamSound; import com.jpexs.decompiler.flash.tags.text.TextParseException; import com.jpexs.decompiler.flash.timeline.AS3Package; @@ -5253,10 +5254,19 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se //} } if (ti0 instanceof ImageTag) { - file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp", true, "importimage"); + String filters = "*.jpg;*.jpeg;*.gif;*.png;*.bmp"; + if (ImageFormat.WEBP.available()) { + filters += ";*.webp"; + } + file = showImportFileChooser("filter.images|" + filters, true, "importimage"); } if (ti0 instanceof ShapeTag) { - file = showImportFileChooser("filter.images|*.jpg;*.jpeg;*.gif;*.png;*.bmp;*.svg", true, "importshape"); + String filters = "*.jpg;*.jpeg;*.gif;*.png;*.bmp"; + if (ImageFormat.WEBP.available()) { + filters += ";*.webp"; + } + filters += ";*.svg"; + file = showImportFileChooser("filter.images|" + filters, true, "importshape"); } if (ti0 instanceof MorphShapeTag) { return replaceMorphShape((MorphShapeTag) ti0, create, true); diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties index b47a30381..9b4e19ab6 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties @@ -17,6 +17,7 @@ shapes = Shapes shapes.svg = SVG shapes.png = PNG shapes.bmp = BMP +shapes.webp = WEBP shapes.canvas = HTML5 Canvas shapes.swf = SWF texts = Texts @@ -28,6 +29,7 @@ images.png_gif_jpeg=PNG/GIF/JPEG images.png = PNG images.jpeg = JPEG images.bmp = BMP +images.webp = WEBP movies = Movies movies.flv = FLV (No audio) sounds = Sounds @@ -56,6 +58,7 @@ morphshapes.swf = SWF morphshapes.bmp_start_end=BMP (start, end) morphshapes.png_start_end=PNG (start, end) morphshapes.svg_start_end=SVG (start, end) +morphshapes.webp_start_end=WEBP (start, end) frames = Frames frames.png = PNG frames.gif = GIF @@ -64,6 +67,7 @@ frames.svg = SVG frames.canvas = HTML5 Canvas frames.pdf = PDF frames.bmp = BMP +frames.webp = WEBP frames.swf = SWF sprites = Sprites sprites.png = PNG @@ -73,11 +77,13 @@ sprites.svg = SVG sprites.canvas = HTML5 Canvas sprites.pdf = PDF sprites.bmp = BMP +sprites.webp = WEBP sprites.swf = SWF buttons = Buttons buttons.png = PNG buttons.svg = SVG buttons.bmp = BMP +buttons.webp = WEBP buttons.swf = SWF fonts = Fonts fonts.ttf = TTF