From c7f4aaddfbf87b42a13d6ce9ec61d6c9866cda1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 23 Sep 2023 23:42:57 +0200 Subject: [PATCH] Added Export DefineFont4 to OpenType CFF file --- CHANGELOG.md | 1 + .../flash/exporters/Font4Exporter.java | 123 ++++++++++++++++++ .../exporters/modes/Font4ExportMode.java | 26 ++++ .../settings/Font4ExportSettings.java | 35 +++++ .../console/CommandLineArgumentParser.java | 11 ++ .../decompiler/flash/gui/ExportDialog.java | 5 + .../jpexs/decompiler/flash/gui/MainPanel.java | 15 ++- .../flash/gui/locales/ExportDialog.properties | 6 +- 8 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/Font4Exporter.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/Font4ExportMode.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/Font4ExportSettings.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5605b233f..a81f20d4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Show font AS linkage class in its name in the tree (besides font name) - [#2057] Show all assigned AS linkage classes in the item name (instead just one) - Exporting ByteArrayRange in the raw editor with the Export button +- Export DefineFont4 to OpenType CFF file ### Fixed - [#2043] StartSound2 tag handling diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/Font4Exporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/Font4Exporter.java new file mode 100644 index 000000000..9dcfd0f24 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/Font4Exporter.java @@ -0,0 +1,123 @@ +/* + * 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.exporters; + +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.ReadOnlyTagList; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode; +import com.jpexs.decompiler.flash.exporters.settings.Font4ExportSettings; +import com.jpexs.decompiler.flash.tags.DefineFont4Tag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.FontTag; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class Font4Exporter { + + public List exportFonts(AbortRetryIgnoreHandler handler, String outdir, ReadOnlyTagList tags, final Font4ExportSettings settings, EventListener evl) throws IOException, InterruptedException { + List ret = new ArrayList<>(); + if (Thread.currentThread().isInterrupted()) { + return ret; + } + + if (tags.isEmpty()) { + return ret; + } + + File foutdir = new File(outdir); + Path.createDirectorySafe(foutdir); + + int count = 0; + for (Tag t : tags) { + if (t instanceof DefineFont4Tag) { + count++; + } + } + + if (count == 0) { + return ret; + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof DefineFont4Tag) { + if (evl != null) { + evl.handleExportingEvent("font", currentIndex, count, t.getName()); + } + + final DefineFont4Tag st = (DefineFont4Tag) t; + if (!st.fontFlagsHasFontData) { + continue; + } + String ext = ".cff"; + final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName() + ext)); + new RetryTask(() -> { + exportFont(st, settings.mode, file); + }, handler).run(); + + ret.add(file); + + if (Thread.currentThread().isInterrupted()) { + break; + } + + if (evl != null) { + evl.handleExportedEvent("font", currentIndex, count, t.getName()); + } + + currentIndex++; + } + } + + return ret; + } + + public byte[] exportFont(final DefineFont4Tag t, Font4ExportMode mode) { + try { + String ext = ".cff"; + + File f = File.createTempFile("temp", ext); + exportFont(t, mode, f); + return Helper.readFile(f.getPath()); + } catch (IOException ex) { + Logger.getLogger(Font4Exporter.class.getName()).log(Level.SEVERE, null, ex); + } + return SWFInputStream.BYTE_ARRAY_EMPTY; + } + + public void exportFont(DefineFont4Tag ft, Font4ExportMode mode, File file) throws IOException { + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + fos.write(ft.fontData.getArray(), ft.fontData.getPos(), ft.fontData.getLength()); + } + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/Font4ExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/Font4ExportMode.java new file mode 100644 index 000000000..a3c6493f3 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/Font4ExportMode.java @@ -0,0 +1,26 @@ +/* + * 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.exporters.modes; + +/** + * + * @author JPEXS + */ +public enum Font4ExportMode { + + CFF +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/Font4ExportSettings.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/Font4ExportSettings.java new file mode 100644 index 000000000..0ae50194f --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/settings/Font4ExportSettings.java @@ -0,0 +1,35 @@ +/* + * 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.exporters.settings; + +import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode; +import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; + +/** + * + * @author JPEXS + */ +public class Font4ExportSettings { + + public static final String EXPORT_FOLDER_NAME = "fonts"; + + public Font4ExportMode mode; + + public Font4ExportSettings(Font4ExportMode mode) { + this.mode = mode; + } +} diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index ab1c252cd..d4756e3ef 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -214,7 +214,10 @@ import java.util.logging.Level; import java.util.logging.Logger; import com.jpexs.decompiler.flash.Bundle; import com.jpexs.decompiler.flash.exporters.DualPdfGraphics2D; +import com.jpexs.decompiler.flash.exporters.Font4Exporter; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode; +import com.jpexs.decompiler.flash.exporters.settings.Font4ExportSettings; import com.jpexs.decompiler.flash.gui.translator.Translator; import com.jpexs.decompiler.flash.importers.MovieImporter; import com.jpexs.decompiler.flash.importers.SoundImporter; @@ -350,6 +353,7 @@ public class CommandLineArgumentParser { out.println(" morphshape - MorphShapes (Default format: SVG)"); out.println(" movie - Movies (Default format: FLV without sound)"); out.println(" font - Fonts (Default format: TTF)"); + out.println(" font4 - DefineFont4 (Default format: CFF)"); out.println(" frame - Frames (Default format: PNG)"); out.println(" sprite - Sprites (Default format: PNG)"); out.println(" button - Buttons (Default format: PNG)"); @@ -410,6 +414,7 @@ public class CommandLineArgumentParser { out.println(" sound:flv - FLV format for Sounds"); out.println(" font:ttf - TTF format for Fonts"); out.println(" font:woff - WOFF format for Fonts"); + out.println(" font4:cff - CFF format for DefineFont4"); out.println(" fla: or xfl: - Specify FLA format version"); out.println(" - values for : cs5,cs5.5,cs6,cc"); out.println(" You can set multiple formats at once using comma (,)"); @@ -2258,6 +2263,7 @@ public class CommandLineArgumentParser { "morphshape", "movie", "font", + "font4", "frame", "sprite", "button", @@ -2434,6 +2440,11 @@ public class CommandLineArgumentParser { new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); } + if (exportAll || exportFormats.contains("font4")) { + System.out.println("Exporting DefineFont4s..."); + new Font4Exporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + FontExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new Font4ExportSettings(enumFromStr(formats.get("font4"), Font4ExportMode.class)), evl); + } + if (exportAll || exportFormats.contains("sound")) { System.out.println("Exporting sounds..."); new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + SoundExportSettings.EXPORT_FOLDER_NAME : ""), new ReadOnlyTagList(extags), new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); diff --git a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java index 293d34a38..11cfcaedb 100644 --- a/src/com/jpexs/decompiler/flash/gui/ExportDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/ExportDialog.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.abc.ScriptPack; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode; +import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode; import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; @@ -33,6 +34,7 @@ import com.jpexs.decompiler.flash.exporters.modes.SymbolClassExportMode; import com.jpexs.decompiler.flash.exporters.modes.TextExportMode; import com.jpexs.decompiler.flash.gui.tagtree.TagTreeModel; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineFont4Tag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.base.ASMSource; @@ -84,6 +86,7 @@ public class ExportDialog extends AppDialog { TagTreeModel.FOLDER_SPRITES, TagTreeModel.FOLDER_BUTTONS, TagTreeModel.FOLDER_FONTS, + "fonts4", TagTreeModel.FOLDER_MORPHSHAPES, "symbolclass" }; @@ -101,6 +104,7 @@ public class ExportDialog extends AppDialog { {Frame.class}, {ButtonTag.class}, {FontTag.class}, + {DefineFont4Tag.class}, {MorphShapeTag.class}, {SymbolClassTypeTag.class} }; @@ -118,6 +122,7 @@ public class ExportDialog extends AppDialog { SpriteExportMode.class, ButtonExportMode.class, FontExportMode.class, + Font4ExportMode.class, MorphShapeExportMode.class, SymbolClassExportMode.class }; diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 5ed0b47c6..2dfecd957 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -46,6 +46,7 @@ import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration; import com.jpexs.decompiler.flash.dumpview.DumpInfo; import com.jpexs.decompiler.flash.dumpview.DumpInfoSwfNode; import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; +import com.jpexs.decompiler.flash.exporters.Font4Exporter; import com.jpexs.decompiler.flash.exporters.FontExporter; import com.jpexs.decompiler.flash.exporters.FrameExporter; import com.jpexs.decompiler.flash.exporters.ImageExporter; @@ -59,6 +60,7 @@ import com.jpexs.decompiler.flash.exporters.TextExporter; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode; import com.jpexs.decompiler.flash.exporters.modes.ButtonExportMode; +import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode; import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; @@ -74,6 +76,7 @@ import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; import com.jpexs.decompiler.flash.exporters.script.AS3ScriptExporter; import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings; +import com.jpexs.decompiler.flash.exporters.settings.Font4ExportSettings; import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings; import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; @@ -1872,6 +1875,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se List binaryData = new ArrayList<>(); Map> frames = new HashMap<>(); List fonts = new ArrayList<>(); + List fonts4 = new ArrayList<>(); List symbolNames = new ArrayList<>(); for (TreeItem d : sel) { @@ -1925,7 +1929,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (nodeType == TreeNodeType.TEXT) { texts.add((Tag) d); } - if (nodeType == TreeNodeType.FONT) { + if (d instanceof DefineFont4Tag) { + fonts4.add((Tag)d); + } else if (nodeType == TreeNodeType.FONT) { fonts.add((Tag) d); } if (nodeType == TreeNodeType.OTHER_TAG) { @@ -2008,6 +2014,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se new FontExportSettings(export.getValue(FontExportMode.class)), evl)); } + if (export.isOptionEnabled(Font4ExportMode.class)) { + ret.addAll(new Font4Exporter().exportFonts(handler, selFile2 + File.separator + Font4ExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(fonts4), + new Font4ExportSettings(export.getValue(Font4ExportMode.class)), evl)); + } + if (export.isOptionEnabled(SymbolClassExportMode.class)) { ret.addAll(new SymbolClassExporter().exportNames(handler, selFile2 + File.separator + SymbolClassExportSettings.EXPORT_FOLDER_NAME, new ReadOnlyTagList(symbolNames), new SymbolClassExportSettings(export.getValue(SymbolClassExportMode.class)), evl)); @@ -5035,6 +5046,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se swf.addTag(showFrameTag); showFrameTag.setTimelined(swf); previewPanel.showImagePanel(swf, swf, 0, true, true, !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, false); + } else if (treeItem instanceof DefineFont4Tag) { + previewPanel.showGenericTagPanel((Tag)treeItem); } else { previewPanel.showEmpty(); } diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties index 76acec3ee..58ca520cf 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties @@ -100,4 +100,8 @@ symbolclass = Symbol-Class mapping symbolclass.csv = CSV #after 18.0.0 -images.png_gif_jpeg_alpha = PNG/GIF/JPEG+alpha \ No newline at end of file +images.png_gif_jpeg_alpha = PNG/GIF/JPEG+alpha + +#after 18.5.0 +fonts4 = DefineFont4 +fonts4.cff = CFF