From 914bb09355ec66c136355b7fcc338988c6a5a067 Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Wed, 11 Feb 2015 22:25:53 +0100 Subject: [PATCH] #798 ffdec doesn't show what it's exporting --- .../jpexs/decompiler/flash/EventListener.java | 13 +- .../src/com/jpexs/decompiler/flash/SWF.java | 591 +---------------- .../flash/exporters/BinaryDataExporter.java | 23 +- .../flash/exporters/FontExporter.java | 34 +- .../flash/exporters/FrameExporter.java | 624 ++++++++++++++++++ .../flash/exporters/ImageExporter.java | 32 +- .../flash/exporters/MorphShapeExporter.java | 22 +- .../flash/exporters/MovieExporter.java | 30 +- .../flash/exporters/ShapeExporter.java | 21 +- .../flash/exporters/SoundExporter.java | 31 +- .../flash/exporters/TextExporter.java | 31 +- .../exporters/script/AS2ScriptExporter.java | 18 +- .../decompiler/flash/timeline/Timeline.java | 3 +- .../decompiler/flash/xfl/XFLConverter.java | 2 +- .../console/CommandLineArgumentParser.java | 50 +- src/com/jpexs/decompiler/flash/gui/Main.java | 24 +- .../jpexs/decompiler/flash/gui/MainPanel.java | 55 +- 17 files changed, 956 insertions(+), 648 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/EventListener.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/EventListener.java index 810324239..f34e258af 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/EventListener.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/EventListener.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 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. */ + * License along with this library. + */ package com.jpexs.decompiler.flash; /** @@ -21,5 +22,9 @@ package com.jpexs.decompiler.flash; */ public interface EventListener { + public void handleExportingEvent(String type, int index, int count, Object data); + + public void handleExportedEvent(String type, int index, int count, Object data); + public void handleEvent(String event, Object data); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index b29566dcb..6954cd10d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -18,7 +18,6 @@ package com.jpexs.decompiler.flash; import SevenZip.Compression.LZMA.Decoder; import SevenZip.Compression.LZMA.Encoder; -import com.jpacker.JPacker; import com.jpexs.decompiler.flash.abc.ABC; import com.jpexs.decompiler.flash.abc.CachedDecompilation; import com.jpexs.decompiler.flash.abc.ClassPath; @@ -61,12 +60,8 @@ import com.jpexs.decompiler.flash.ecma.Null; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.modes.FramesExportMode; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.exporters.script.AS2ScriptExporter; -import com.jpexs.decompiler.flash.exporters.settings.FramesExportSettings; -import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; -import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.helpers.ImageHelper; @@ -83,7 +78,6 @@ import com.jpexs.decompiler.flash.tags.EndTag; import com.jpexs.decompiler.flash.tags.ExportAssetsTag; import com.jpexs.decompiler.flash.tags.FileAttributesTag; import com.jpexs.decompiler.flash.tags.JPEGTablesTag; -import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.SymbolClassTag; import com.jpexs.decompiler.flash.tags.Tag; @@ -118,18 +112,9 @@ import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.RGB; -import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.annotations.Internal; -import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; import com.jpexs.decompiler.flash.types.filters.BlendComposite; -import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; -import com.jpexs.decompiler.flash.types.filters.CONVOLUTIONFILTER; -import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; import com.jpexs.decompiler.flash.types.filters.FILTER; -import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; -import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; -import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; import com.jpexs.decompiler.flash.xfl.FLAVersion; import com.jpexs.decompiler.flash.xfl.XFLConverter; import com.jpexs.decompiler.graph.Graph; @@ -146,23 +131,17 @@ import com.jpexs.helpers.NulStream; import com.jpexs.helpers.ProgressListener; import com.jpexs.helpers.SerializableImage; import com.jpexs.helpers.utf8.Utf8Helper; -import gnu.jpdf.PDFJob; import java.awt.AlphaComposite; import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; -import java.awt.print.PageFormat; -import java.awt.print.Paper; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -1064,7 +1043,7 @@ public final class SWF implements SWFContainerItem, Timelined { return true; } - public boolean exportAS3Class(String className, String outdir, ScriptExportMode exportMode, boolean parallel) throws Exception { + public boolean exportAS3Class(String className, String outdir, ScriptExportMode exportMode, boolean parallel, EventListener evl) throws Exception { boolean exported = false; List abcList = getAbcList(); @@ -1077,11 +1056,10 @@ public final class SWF implements SWFContainerItem, Timelined { if (scrs.size() > 1) { cnt = "script " + (j + 1) + "/" + scrs.size() + " "; } - String exStr = "Exporting " + "tag " + (i + 1) + "/" + abcList.size() + " " + cnt + scr.getPath() + " ..."; - informListeners("exporting", exStr); + String eventData = cnt + scr.getPath() + " ..."; + evl.handleExportingEvent("tag", i + 1, abcList.size(), eventData); scr.export(outdir, exportMode, parallel); - exStr = "Exported " + "tag " + (i + 1) + "/" + abcList.size() + " " + cnt + scr.getPath() + " ..."; - informListeners("exported", exStr); + evl.handleExportedEvent("tag", i + 1, abcList.size(), eventData); exported = true; } } @@ -1142,7 +1120,9 @@ public final class SWF implements SWFContainerItem, Timelined { long stopTime; - public ExportPackTask(AbortRetryIgnoreHandler handler, AtomicInteger index, int count, ClassPath path, ScriptPack pack, String directory, ScriptExportMode exportMode, boolean parallel) { + EventListener eventListener; + + public ExportPackTask(AbortRetryIgnoreHandler handler, AtomicInteger index, int count, ClassPath path, ScriptPack pack, String directory, ScriptExportMode exportMode, boolean parallel, EventListener evl) { this.pack = pack; this.directory = directory; this.exportMode = exportMode; @@ -1151,6 +1131,7 @@ public final class SWF implements SWFContainerItem, Timelined { this.count = count; this.parallel = parallel; this.handler = handler; + this.eventListener = evl; } @Override @@ -1165,12 +1146,12 @@ public final class SWF implements SWFContainerItem, Timelined { }; int currentIndex = index.getAndIncrement(); synchronized (ABC.class) { - informListeners("exporting", "Exporting script " + currentIndex + "/" + count + " " + path); + eventListener.handleExportingEvent("script", currentIndex, count, path); } new RetryTask(rio, handler).run(); synchronized (ABC.class) { long time = stopTime - startTime; - informListeners("exported", "Exported script " + currentIndex + "/" + count + " " + path + ", " + Helper.formatTimeSec(time)); + eventListener.handleExportedEvent("script", currentIndex, count, path + ", " + Helper.formatTimeSec(time)); } return rio.result; } @@ -1188,7 +1169,7 @@ public final class SWF implements SWFContainerItem, Timelined { return ret; } - private List exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ScriptExportMode exportMode, final boolean parallel) { + private List exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ScriptExportMode exportMode, final boolean parallel, final EventListener evl) { final AtomicInteger cnt = new AtomicInteger(1); final List ret = new ArrayList<>(); @@ -1200,7 +1181,7 @@ public final class SWF implements SWFContainerItem, Timelined { @Override public Void call() throws Exception { for (MyEntry item : packs) { - ExportPackTask task = new ExportPackTask(handler, cnt, packs.size(), item.getKey(), item.getValue(), outdir, exportMode, parallel); + ExportPackTask task = new ExportPackTask(handler, cnt, packs.size(), item.getKey(), item.getValue(), outdir, exportMode, parallel, evl); ret.add(task.call()); } return null; @@ -1215,7 +1196,7 @@ public final class SWF implements SWFContainerItem, Timelined { ExecutorService executor = Executors.newFixedThreadPool(Configuration.getParallelThreadCount()); List> futureResults = new ArrayList<>(); for (MyEntry item : packs) { - Future future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.getKey(), item.getValue(), outdir, exportMode, parallel)); + Future future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.getKey(), item.getValue(), outdir, exportMode, parallel, evl)); futureResults.add(future); } @@ -1247,22 +1228,33 @@ public final class SWF implements SWFContainerItem, Timelined { public EventListener getExportEventListener() { EventListener evl = new EventListener() { @Override - public void handleEvent(String event, Object data) { - if (event.equals("exporting") || event.equals("exported")) { - informListeners(event, data); + public void handleExportingEvent(String type, int index, int count, Object data) { + for (EventListener listener : listeners) { + listener.handleExportingEvent(type, index, count, data); } } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + for (EventListener listener : listeners) { + listener.handleExportedEvent(type, index, count, data); + } + } + + @Override + public void handleEvent(String event, Object data) { + informListeners(event, data); + } }; return evl; } - public List exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportMode exportMode, boolean parallel) throws IOException { + public List exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportMode exportMode, boolean parallel, EventListener evl) throws IOException { List ret = new ArrayList<>(); - final EventListener evl = getExportEventListener(); if (isAS3()) { - ret.addAll(exportActionScript3(handler, outdir, exportMode, parallel)); + ret.addAll(exportActionScript3(handler, outdir, exportMode, parallel, evl)); } else { ret.addAll(exportActionScript2(handler, outdir, exportMode, parallel, evl)); } @@ -1486,7 +1478,7 @@ public final class SWF implements SWFContainerItem, Timelined { fos.write(chunkBytes); } - private static void makeAVI(Iterator images, int frameRate, File file) throws IOException { + public static void makeAVI(Iterator images, int frameRate, File file) throws IOException { if (!images.hasNext()) { return; } @@ -1504,7 +1496,7 @@ public final class SWF implements SWFContainerItem, Timelined { } - private static void makeGIF(Iterator images, int frameRate, File file) throws IOException { + public static void makeGIF(Iterator images, int frameRate, File file) throws IOException { if (!images.hasNext()) { return; } @@ -1521,7 +1513,7 @@ public final class SWF implements SWFContainerItem, Timelined { } } - private static String getTypePrefix(CharacterTag c) { + public static String getTypePrefix(CharacterTag c) { if (c instanceof ShapeTag) { return "shape"; } @@ -1579,290 +1571,6 @@ public final class SWF implements SWFContainerItem, Timelined { } } - public List exportFrames(AbortRetryIgnoreHandler handler, String outdir, int containerId, List frames, final FramesExportSettings settings) throws IOException { - final List ret = new ArrayList<>(); - if (tags.isEmpty()) { - return ret; - } - Timeline tim = null; - String path = ""; - if (containerId == 0) { - tim = getTimeline(); - } else { - tim = ((Timelined) getCharacter(containerId)).getTimeline(); - path = File.separator + Helper.makeFileName(getCharacter(containerId).getExportFileName()); - } - if (frames == null) { - int frameCnt = tim.getFrameCount(); - frames = new ArrayList<>(); - for (int i = 0; i < frameCnt; i++) { - frames.add(i); - } - } - - final File foutdir = new File(outdir + path); - if (!foutdir.exists()) { - if (!foutdir.mkdirs()) { - if (!foutdir.exists()) { - throw new IOException("Cannot create directory " + outdir); - } - } - } - - final List fframes = frames; - - Color backgroundColor = null; - if (settings.mode == FramesExportMode.AVI) { - for (Tag t : tags) { - if (t instanceof SetBackgroundColorTag) { - SetBackgroundColorTag sb = (SetBackgroundColorTag) t; - backgroundColor = sb.backgroundColor.toColor(); - } - } - } - - if (settings.mode == FramesExportMode.SVG) { - for (int i = 0; i < frames.size(); i++) { - final int fi = i; - final Timeline ftim = tim; - final Color fbackgroundColor = backgroundColor; - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - int frame = fframes.get(fi); - File f = new File(foutdir + File.separator + frame + ".svg"); - try (FileOutputStream fos = new FileOutputStream(f)) { - ExportRectangle rect = new ExportRectangle(ftim.displayRect); - rect.xMax *= settings.zoom; - rect.yMax *= settings.zoom; - rect.xMin *= settings.zoom; - rect.yMin *= settings.zoom; - SVGExporter exporter = new SVGExporter(rect); - if (fbackgroundColor != null) { - exporter.setBackGroundColor(fbackgroundColor); - } - frameToSvg(ftim, frame, 0, null, 0, exporter, new ColorTransform(), 0, settings.zoom); - fos.write(Utf8Helper.getBytes(exporter.getSVG())); - } - ret.add(f); - } - }, handler).run(); - } - return ret; - } - - if (settings.mode == FramesExportMode.CANVAS) { - final Timeline ftim = tim; - final Color fbackgroundColor = backgroundColor; - final SWF fswf = this; - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File fcanvas = new File(foutdir + File.separator + "canvas.js"); - Helper.saveStream(SWF.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/canvas.js"), fcanvas); - ret.add(fcanvas); - - File f = new File(foutdir + File.separator + "frames.js"); - File fmin = new File(foutdir + File.separator + "frames.min.js"); - int width = (int) (ftim.displayRect.getWidth() * settings.zoom / SWF.unitDivisor); - int height = (int) (ftim.displayRect.getHeight() * settings.zoom / SWF.unitDivisor); - try (FileOutputStream fos = new FileOutputStream(f)) { - fos.write(Utf8Helper.getBytes("\r\n")); - Set library = new HashSet<>(); - ftim.getNeededCharacters(fframes, library); - - writeLibrary(fswf, library, fos); - - String currentName = ftim.id == 0 ? "main" : getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id; - - fos.write(Utf8Helper.getBytes("function " + currentName + "(ctx,ctrans,frame,ratio,time){\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.save();\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.transform(1,0,0,1," + (-ftim.displayRect.Xmin * settings.zoom / unitDivisor) + "," + (-ftim.displayRect.Ymin * settings.zoom / unitDivisor) + ");\r\n")); - fos.write(Utf8Helper.getBytes(framesToHtmlCanvas(unitDivisor / settings.zoom, ftim, fframes, 0, null, 0, ftim.displayRect, new ColorTransform(), fbackgroundColor))); - fos.write(Utf8Helper.getBytes("\tctx.restore();\r\n")); - fos.write(Utf8Helper.getBytes("}\r\n\r\n")); - - fos.write(Utf8Helper.getBytes("var frame = -1;\r\n")); - fos.write(Utf8Helper.getBytes("var time = 0;\r\n")); - fos.write(Utf8Helper.getBytes("var frames = [];\r\n")); - for (int i : fframes) { - fos.write(Utf8Helper.getBytes("frames.push(" + i + ");\r\n")); - } - fos.write(Utf8Helper.getBytes("\r\n")); - RGB backgroundColor = new RGB(255, 255, 255); - for (Tag t : fswf.tags) { - if (t instanceof SetBackgroundColorTag) { - SetBackgroundColorTag sb = (SetBackgroundColorTag) t; - backgroundColor = sb.backgroundColor; - } - } - - fos.write(Utf8Helper.getBytes("var backgroundColor = \"" + backgroundColor.toHexRGB() + "\";\r\n")); - fos.write(Utf8Helper.getBytes("var originalWidth = " + width + ";\r\n")); - fos.write(Utf8Helper.getBytes("var originalHeight= " + height + ";\r\n")); - fos.write(Utf8Helper.getBytes("function nextFrame(ctx,ctrans){\r\n")); - fos.write(Utf8Helper.getBytes("\tvar oldframe = frame;\r\n")); - fos.write(Utf8Helper.getBytes("\tframe = (frame+1)%frames.length;\r\n")); - fos.write(Utf8Helper.getBytes("\tif(frame==oldframe){time++;}else{time=0;};\r\n")); - fos.write(Utf8Helper.getBytes("\tdrawFrame();\r\n")); - fos.write(Utf8Helper.getBytes("}\r\n\r\n")); - - fos.write(Utf8Helper.getBytes("function drawFrame(){\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.fillStyle = backgroundColor;\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.fillRect(0,0,canvas.width,canvas.height);\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.save();\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n")); - fos.write(Utf8Helper.getBytes("\t" + currentName + "(ctx,ctrans,frames[frame],0,time);\r\n")); - fos.write(Utf8Helper.getBytes("\tctx.restore();\r\n")); - fos.write(Utf8Helper.getBytes("}\r\n\r\n")); - if (ftim.swf.frameRate > 0) { - fos.write(Utf8Helper.getBytes("window.setInterval(function(){nextFrame(ctx,ctrans);}," + (int) (1000.0 / ftim.swf.frameRate) + ");\r\n")); - } - fos.write(Utf8Helper.getBytes("nextFrame(ctx,ctrans);\r\n")); - } - - boolean packed = false; - if (Configuration.packJavaScripts.get()) { - try { - JPacker.main(new String[]{"-q", "-b", "62", "-o", fmin.getAbsolutePath(), f.getAbsolutePath()}); - f.delete(); - packed = true; - } catch (Exception | Error e) { // Something wrong in the packer - logger.log(Level.WARNING, "JPacker: Cannot minimize script"); - f.renameTo(fmin); - } - } else { - f.renameTo(fmin); - } - - File fh = new File(foutdir + File.separator + "frames.html"); - try (FileOutputStream fos = new FileOutputStream(fh); FileInputStream fis = new FileInputStream(fmin)) { - fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlPrefix(width, height))); - fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsPrefix())); - byte buf[] = new byte[1000]; - int cnt; - while ((cnt = fis.read(buf)) > 0) { - fos.write(buf, 0, cnt); - } - if (packed) { - fos.write(Utf8Helper.getBytes(";")); - } - fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsSuffix())); - fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlSuffix())); - } - fmin.delete(); - - ret.add(f); - } - }, handler).run(); - - return ret; - } - - final Timeline ftim = tim; - final Color fbackgroundColor = backgroundColor; - final Iterator frameImages = new Iterator() { - - private int pos = 0; - - @Override - public boolean hasNext() { - return fframes.size() > pos; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - - @Override - public BufferedImage next() { - if (!hasNext()) { - return null; - } - return frameToImageGet(ftim, fframes.get(pos++), 0, null, 0, ftim.displayRect, new Matrix(), new ColorTransform(), fbackgroundColor, false, settings.zoom).getBufferedImage(); - } - }; - - switch (settings.mode) { - case GIF: - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File f = new File(foutdir + File.separator + "frames.gif"); - makeGIF(frameImages, frameRate, f); - ret.add(f); - } - }, handler).run(); - break; - case BMP: - for (int i = 0; frameImages.hasNext(); i++) { - final int fi = i; - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".bmp"); - BMPFile.saveBitmap(frameImages.next(), f); - ret.add(f); - } - }, handler).run(); - } - break; - case PNG: - for (int i = 0; frameImages.hasNext(); i++) { - final int fi = i; - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png"); - try (FileOutputStream fos = new FileOutputStream(f)) { - ImageHelper.write(frameImages.next(), "PNG", fos); - } - ret.add(f); - } - }, handler).run(); - } - break; - case PDF: - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File f = new File(foutdir + File.separator + "frames.pdf"); - PDFJob job = new PDFJob(new FileOutputStream(f)); - PageFormat pf = new PageFormat(); - pf.setOrientation(PageFormat.PORTRAIT); - Paper p = new Paper(); - BufferedImage img0 = frameImages.next(); - p.setSize(img0.getWidth() + 10, img0.getHeight() + 10); - pf.setPaper(p); - - for (int i = 0; frameImages.hasNext(); i++) { - BufferedImage img = frameImages.next(); - Graphics g = job.getGraphics(pf); - g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null); - g.dispose(); - } - - job.end(); - ret.add(f); - } - }, handler).run(); - break; - case AVI: - new RetryTask(new RunnableIOEx() { - @Override - public void run() throws IOException { - File f = new File(foutdir + File.separator + "frames.avi"); - makeAVI(frameImages, frameRate, f); - ret.add(f); - } - }, handler).run(); - break; - } - - return ret; - } - private static void getVariables(ConstantPool constantPool, BaseLocalData localData, TranslateStack stack, List output, ActionGraphSource code, int ip, List> variables, List functions, HashMap strings, List visited, HashMap usageTypes, String path) throws InterruptedException { boolean debugMode = false; while ((ip > -1) && ip < code.size()) { @@ -2509,239 +2217,6 @@ public final class SWF implements SWFContainerItem, Timelined { return ret; } - private static String jsArrColor(RGB rgb) { - return "[" + rgb.red + "," + rgb.green + "," + rgb.blue + "," + ((rgb instanceof RGBA) ? ((RGBA) rgb).getAlphaFloat() : 1) + "]"; - } - - public static String framesToHtmlCanvas(double unitDivisor, Timeline timeline, List frames, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, ColorTransform colorTransform, Color backGroundColor) { - StringBuilder sb = new StringBuilder(); - if (frames == null) { - frames = new ArrayList<>(); - for (int i = 0; i < timeline.getFrameCount(); i++) { - frames.add(i); - } - } - sb.append("\tvar clips = [];\r\n"); - sb.append("\tvar frame_cnt = ").append(timeline.getFrameCount()).append(";\r\n"); - sb.append("\tframe = frame % frame_cnt;\r\n"); - sb.append("\tswitch(frame){\r\n"); - int maxDepth = timeline.getMaxDepth(); - Stack clipDepths = new Stack<>(); - for (int frame : frames) { - sb.append("\t\tcase ").append(frame).append(":\r\n"); - Frame frameObj = timeline.getFrame(frame); - for (int i = 1; i <= maxDepth + 1; i++) { - while (!clipDepths.isEmpty() && clipDepths.peek() <= i) { - clipDepths.pop(); - sb.append("\t\t\tvar o = clips.pop();\r\n"); - sb.append("\t\t\tctx.globalCompositeOperation = \"destination-in\";\r\n"); - sb.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); - sb.append("\t\t\tctx.drawImage(o.clipCanvas,0,0);\r\n"); - sb.append("\t\t\tvar ms=o.ctx._matrix;\r\n"); - sb.append("\t\t\to.ctx.setTransform(1,0,0,1,0,0);\r\n"); - sb.append("\t\t\to.ctx.globalCompositeOperation = \"source-over\";\r\n"); - sb.append("\t\t\to.ctx.drawImage(canvas,0,0);\r\n"); - sb.append("\t\t\to.ctx.applyTransforms(ms);\r\n"); - sb.append("\t\t\tctx = o.ctx;\r\n"); - sb.append("\t\t\tcanvas = o.canvas;\r\n"); - } - if (!frameObj.layers.containsKey(i)) { - continue; - } - DepthState layer = frameObj.layers.get(i); - if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { - continue; - } - if (!layer.isVisible) { - continue; - } - CharacterTag character = timeline.swf.getCharacter(layer.characterId); - - if (colorTransform == null) { - colorTransform = new ColorTransform(); - } - Matrix placeMatrix = new Matrix(layer.matrix); - placeMatrix.scaleX /= unitDivisor; - placeMatrix.scaleY /= unitDivisor; - placeMatrix.rotateSkew0 /= unitDivisor; - placeMatrix.rotateSkew1 /= unitDivisor; - placeMatrix.translateX /= unitDivisor; - placeMatrix.translateY /= unitDivisor; - - int f = 0; - String fstr = "0"; - if (character instanceof DefineSpriteTag) { - DefineSpriteTag sp = (DefineSpriteTag) character; - Timeline tim = sp.getTimeline(); - if (tim.getFrameCount() > 0) { - f = layer.time % tim.getFrameCount(); - fstr = "(" + f + "+time)%" + tim.getFrameCount(); - } - } - - if (layer.clipDepth != -1) { - clipDepths.push(layer.clipDepth); - sb.append("\t\t\tclips.push({ctx:ctx,canvas:canvas});\r\n"); - sb.append("\t\t\tvar ccanvas = createCanvas(canvas.width,canvas.height);\r\n"); - sb.append("\t\t\tvar cctx = ccanvas.getContext(\"2d\");\r\n"); - sb.append("\t\t\tenhanceContext(cctx);\r\n"); - sb.append("\t\t\tcctx.applyTransforms(ctx._matrix);\r\n"); - sb.append("\t\t\tcanvas = ccanvas;\r\n"); - sb.append("\t\t\tctx = cctx;\r\n"); - } - - if (layer.filters != null && layer.filters.size() > 0) { - sb.append("\t\t\tvar oldctx = ctx;\r\n"); - sb.append("\t\t\tvar fcanvas = createCanvas(canvas.width,canvas.height);"); - sb.append("\t\t\tvar fctx = fcanvas.getContext(\"2d\");\r\n"); - sb.append("\t\t\tenhanceContext(fctx);\r\n"); - sb.append("\t\t\tfctx.applyTransforms(ctx._matrix);\r\n"); - sb.append("\t\t\tctx = fctx;\r\n"); - } - - ColorTransform ctrans = layer.colorTransForm; - String ctrans_str = "ctrans"; - if (ctrans == null) { - ctrans = new ColorTransform(); - } else { - ctrans_str = "ctrans.merge(new cxform(" - + ctrans.getRedAdd() + "," + ctrans.getGreenAdd() + "," + ctrans.getBlueAdd() + "," + ctrans.getAlphaAdd() + "," - + ctrans.getRedMulti() + "," + ctrans.getGreenMulti() + "," + ctrans.getBlueMulti() + "," + ctrans.getAlphaMulti() - + "))"; - } - sb.append("\t\t\tplace(\"").append(getTypePrefix(character)).append(layer.characterId).append("\",canvas,ctx,[").append(placeMatrix.scaleX).append(",") - .append(placeMatrix.rotateSkew0).append(",") - .append(placeMatrix.rotateSkew1).append(",") - .append(placeMatrix.scaleY).append(",") - .append(placeMatrix.translateX).append(",") - .append(placeMatrix.translateY).append("],").append(ctrans_str).append(",").append("").append(layer.blendMode < 1 ? 1 : layer.blendMode).append(",").append(fstr).append(",").append(layer.ratio < 0 ? 0 : layer.ratio).append(",time").append(");\r\n"); - - if (layer.filters != null && layer.filters.size() > 0) { - for (FILTER filter : layer.filters) { - if (filter instanceof COLORMATRIXFILTER) { - COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter; - String mat = "["; - for (int k = 0; k < cmf.matrix.length; k++) { - if (k > 0) { - mat += ","; - } - mat += cmf.matrix[k]; - } - mat += "]"; - sb.append("\t\t\tfcanvas = Filters.colorMatrix(fcanvas,fcanvas.getContext(\"2d\"),").append(mat).append(");\r\n"); - } - - if (filter instanceof CONVOLUTIONFILTER) { - CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) filter; - int height = cf.matrix.length; - int width = cf.matrix[0].length; - float[] matrix2 = new float[width * height]; - for (int y = 0; y < height; y++) { - for (int x = 0; x < width; x++) { - matrix2[y * width + x] = cf.matrix[x][y] * cf.divisor + cf.bias; - } - } - String mat = "["; - for (int k = 0; k < matrix2.length; k++) { - if (k > 0) { - mat += ","; - } - mat += matrix2[k]; - } - mat += "]"; - sb.append("\t\t\tfcanvas = Filters.convolution(fcanvas,fcanvas.getContext(\"2d\"),").append(mat).append(",false);\r\n"); - } - - if (filter instanceof GLOWFILTER) { - GLOWFILTER gf = (GLOWFILTER) filter; - sb.append("\t\t\tfcanvas = Filters.glow(fcanvas,fcanvas.getContext(\"2d\"),").append(gf.blurX).append(",").append(gf.blurY).append(",").append(gf.strength).append(",").append(jsArrColor(gf.glowColor)).append(",").append(gf.innerGlow ? "true" : "false").append(",").append(gf.knockout ? "true" : "false").append(",").append(gf.passes).append(");\r\n"); - } - - if (filter instanceof DROPSHADOWFILTER) { - DROPSHADOWFILTER ds = (DROPSHADOWFILTER) filter; - sb.append("\t\t\tfcanvas = Filters.dropShadow(fcanvas,fcanvas.getContext(\"2d\"),").append(ds.blurX).append(",").append(ds.blurY).append(",").append((int) (ds.angle * 180 / Math.PI)).append(",").append(ds.distance).append(",").append(jsArrColor(ds.dropShadowColor)).append(",").append(ds.innerShadow ? "true" : "false").append(",").append(ds.passes).append(",").append(ds.strength).append(",").append(ds.knockout ? "true" : "false").append(");\r\n"); - } - if (filter instanceof BEVELFILTER) { - BEVELFILTER bv = (BEVELFILTER) filter; - String type = "Filters.INNER"; - if (bv.onTop && !bv.innerShadow) { - type = "Filters.FULL"; - } else if (!bv.innerShadow) { - type = "Filters.OUTER"; - } - sb.append("\t\t\tfcanvas = Filters.bevel(fcanvas,fcanvas.getContext(\"2d\"),").append(bv.blurX).append(",").append(bv.blurY).append(",").append(bv.strength).append(",").append(type).append(",").append(jsArrColor(bv.highlightColor)).append(",").append(jsArrColor(bv.shadowColor)).append(",").append((int) (bv.angle * 180 / Math.PI)).append(",").append(bv.distance).append(",").append(bv.knockout ? "true" : "false").append(",").append(bv.passes).append(");\r\n"); - } - - if (filter instanceof GRADIENTBEVELFILTER) { - GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter; - String colArr = "["; - String ratArr = "["; - for (int k = 0; k < gbf.gradientColors.length; k++) { - if (k > 0) { - colArr += ","; - ratArr += ","; - } - colArr += jsArrColor(gbf.gradientColors[k]); - ratArr += gbf.gradientRatio[k] / 255f; - } - colArr += "]"; - ratArr += "]"; - String type = "Filters.INNER"; - if (gbf.onTop && !gbf.innerShadow) { - type = "Filters.FULL"; - } else if (!gbf.innerShadow) { - type = "Filters.OUTER"; - } - - sb.append("\t\t\tfcanvas = Filters.gradientBevel(fcanvas,fcanvas.getContext(\"2d\"),").append(colArr).append(",").append(ratArr).append(",").append(gbf.blurX).append(",").append(gbf.blurY).append(",").append(gbf.strength).append(",").append(type).append(",").append((int) (gbf.angle * 180 / Math.PI)).append(",").append(gbf.distance).append(",").append(gbf.knockout ? "true" : "false").append(",").append(gbf.passes).append(");\r\n"); - } - - if (filter instanceof GRADIENTGLOWFILTER) { - GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter; - String colArr = "["; - String ratArr = "["; - for (int k = 0; k < ggf.gradientColors.length; k++) { - if (k > 0) { - colArr += ","; - ratArr += ","; - } - colArr += jsArrColor(ggf.gradientColors[k]); - ratArr += ggf.gradientRatio[k] / 255f; - } - colArr += "]"; - ratArr += "]"; - String type = "Filters.INNER"; - if (ggf.onTop && !ggf.innerShadow) { - type = "Filters.FULL"; - } else if (!ggf.innerShadow) { - type = "Filters.OUTER"; - } - - sb.append("\t\t\tfcanvas = Filters.gradientGlow(fcanvas,fcanvas.getContext(\"2d\"),").append(ggf.blurX).append(",").append(ggf.blurY).append(",").append((int) (ggf.angle * 180 / Math.PI)).append(",").append(ggf.distance).append(",").append(colArr).append(",").append(ratArr).append(",").append(type).append(",").append(ggf.passes).append(",").append(ggf.strength).append(",").append(ggf.knockout ? "true" : "false").append(");\r\n"); - } - } - sb.append("\t\t\tctx = oldctx;\r\n"); - sb.append("\t\t\tvar ms=ctx._matrix;\r\n"); - sb.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); - sb.append("\t\t\tctx.drawImage(fcanvas,0,0);\r\n"); - sb.append("\t\t\tctx.applyTransforms(ms);\r\n"); - } - - if (layer.clipDepth != -1) { - sb.append("\t\t\tclips[clips.length-1].clipCanvas = canvas;\r\n"); - sb.append("\t\t\tcanvas = createCanvas(canvas.width,canvas.height);\r\n"); - sb.append("\t\t\tvar nctx = canvas.getContext(\"2d\");\r\n"); - sb.append("\t\t\tenhanceContext(nctx);\r\n"); - sb.append("\t\t\tnctx.applyTransforms(ctx._matrix);\r\n"); - sb.append("\t\t\tctx = nctx;\r\n"); - } - } - sb.append("\t\t\tbreak;\r\n"); - } - sb.append("\t}\r\n"); - return sb.toString(); - } - public static void frameToSvg(Timeline timeline, int frame, int time, DepthState stateUnderCursor, int mouseButton, SVGExporter exporter, ColorTransform colorTransform, int level, double zoom) throws IOException { if (timeline.getFrameCount() <= frame) { return; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java index cccb94fcf..04425cd09 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/BinaryDataExporter.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings; @@ -34,7 +35,7 @@ import java.util.List; */ public class BinaryDataExporter { - public List exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List tags, BinaryDataExportSettings settings) throws IOException { + public List exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List tags, BinaryDataExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -48,9 +49,22 @@ public class BinaryDataExporter { } } + int count = 0; + for (Tag t : tags) { + if (t instanceof DefineBinaryDataTag) { + count++; + } + } + + int currentIndex = 1; for (final Tag t : tags) { if (t instanceof DefineBinaryDataTag) { + if (evl != null) { + evl.handleExportingEvent("binarydata", currentIndex, count, t.getName()); + } + int characterID = ((DefineBinaryDataTag) t).getCharacterId(); + final File file = new File(outdir + File.separator + characterID + ".bin"); new RetryTask(new RunnableIOEx() { @Override @@ -61,8 +75,15 @@ public class BinaryDataExporter { } }, handler).run(); ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("binarydata", currentIndex, count, t.getName()); + } + + currentIndex++; } } + return ret; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java index f17f101d4..cc8aafd23 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FontExporter.java @@ -22,6 +22,7 @@ import com.google.typography.font.sfntly.data.WritableFontData; import com.google.typography.font.tools.conversion.woff.WoffWriter; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.exporters.modes.FontExportMode; @@ -51,7 +52,7 @@ import java.util.logging.Logger; */ public class FontExporter { - public List exportFonts(AbortRetryIgnoreHandler handler, String outdir, List tags, final FontExportSettings settings) throws IOException { + public List exportFonts(AbortRetryIgnoreHandler handler, String outdir, List tags, final FontExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -64,16 +65,27 @@ public class FontExporter { } } } + + int count = 0; for (Tag t : tags) { - File newfile = null; if (t instanceof FontTag) { + count++; + } + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof FontTag) { + if (evl != null) { + evl.handleExportingEvent("font", currentIndex, count, t.getName()); + } + final FontTag st = (FontTag) t; String ext = ".ttf"; if (settings.mode == FontExportMode.WOFF) { ext = ".woff"; } final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName() + ext)); - newfile = file; new RetryTask(new RunnableIOEx() { @Override public void run() throws IOException { @@ -81,11 +93,16 @@ public class FontExporter { } }, handler).run(); - ret.add(newfile); + ret.add(file); + if (evl != null) { + evl.handleExportedEvent("font", currentIndex, count, t.getName()); + } + + currentIndex++; } - } + return ret; } @@ -120,7 +137,12 @@ public class FontExporter { ttfFile = File.createTempFile("ffdec_export", ".ttf"); } - Fontastic f = new Fontastic(t.getFontNameIntag(), ttfFile); + String fontName = t.getFontNameIntag(); + if (fontName.length() == 0) { + fontName = "noname"; + } + + Fontastic f = new Fontastic(fontName, ttfFile); String cop = t.getCopyright(); f.getEngine().setCopyrightYear(cop == null ? "" : cop); 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 new file mode 100644 index 000000000..0d75ef547 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/FrameExporter.java @@ -0,0 +1,624 @@ +/* + * Copyright (C) 2010-2015 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.jpacker.JPacker; +import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.RunnableIOEx; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.configuration.Configuration; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.modes.FramesExportMode; +import com.jpexs.decompiler.flash.exporters.settings.FramesExportSettings; +import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.helpers.BMPFile; +import com.jpexs.decompiler.flash.helpers.ImageHelper; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.timeline.DepthState; +import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Timeline; +import com.jpexs.decompiler.flash.timeline.Timelined; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.RGB; +import com.jpexs.decompiler.flash.types.RGBA; +import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; +import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; +import com.jpexs.decompiler.flash.types.filters.CONVOLUTIONFILTER; +import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; +import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; +import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; +import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.utf8.Utf8Helper; +import gnu.jpdf.PDFJob; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.image.BufferedImage; +import java.awt.print.PageFormat; +import java.awt.print.Paper; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.Stack; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author JPEXS + */ +public class FrameExporter { + + private static final Logger logger = Logger.getLogger(FrameExporter.class.getName()); + + public List exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List frames, final FramesExportSettings settings, final EventListener evl) throws IOException { + final List ret = new ArrayList<>(); + if (swf.tags.isEmpty()) { + return ret; + } + Timeline tim0; + String path = ""; + if (containerId == 0) { + tim0 = swf.getTimeline(); + } else { + tim0 = ((Timelined) swf.getCharacter(containerId)).getTimeline(); + path = File.separator + Helper.makeFileName(swf.getCharacter(containerId).getExportFileName()); + } + + final Timeline tim = tim0; + + if (frames == null) { + int frameCnt = tim.getFrameCount(); + frames = new ArrayList<>(); + for (int i = 0; i < frameCnt; i++) { + frames.add(i); + } + } + + final File foutdir = new File(outdir + path); + if (!foutdir.exists()) { + if (!foutdir.mkdirs()) { + if (!foutdir.exists()) { + throw new IOException("Cannot create directory " + outdir); + } + } + } + + final List fframes = frames; + + Color backgroundColor = null; + if (settings.mode == FramesExportMode.AVI) { + for (Tag t : swf.tags) { + if (t instanceof SetBackgroundColorTag) { + SetBackgroundColorTag sb = (SetBackgroundColorTag) t; + backgroundColor = sb.backgroundColor.toColor(); + } + } + } + + if (settings.mode == FramesExportMode.SVG) { + for (int i = 0; i < frames.size(); i++) { + if (evl != null) { + evl.handleExportingEvent("frame", i, frames.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + } + + final int fi = i; + final Color fbackgroundColor = backgroundColor; + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + int frame = fframes.get(fi); + File f = new File(foutdir + File.separator + frame + ".svg"); + try (FileOutputStream fos = new FileOutputStream(f)) { + ExportRectangle rect = new ExportRectangle(tim.displayRect); + rect.xMax *= settings.zoom; + rect.yMax *= settings.zoom; + rect.xMin *= settings.zoom; + rect.yMin *= settings.zoom; + SVGExporter exporter = new SVGExporter(rect); + if (fbackgroundColor != null) { + exporter.setBackGroundColor(fbackgroundColor); + } + SWF.frameToSvg(tim, frame, 0, null, 0, exporter, new ColorTransform(), 0, settings.zoom); + fos.write(Utf8Helper.getBytes(exporter.getSVG())); + } + ret.add(f); + } + }, handler).run(); + + if (evl != null) { + evl.handleExportedEvent("frame", i, frames.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + } + } + + return ret; + } + + if (settings.mode == FramesExportMode.CANVAS) { + if (evl != null) { + evl.handleExportingEvent("canvas", 1, 1, tim.parentTag == null ? "" : tim.parentTag.getName()); + } + + final Timeline ftim = tim; + final Color fbackgroundColor = backgroundColor; + final SWF fswf = swf; + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File fcanvas = new File(foutdir + File.separator + "canvas.js"); + Helper.saveStream(SWF.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/canvas.js"), fcanvas); + ret.add(fcanvas); + + File f = new File(foutdir + File.separator + "frames.js"); + File fmin = new File(foutdir + File.separator + "frames.min.js"); + int width = (int) (ftim.displayRect.getWidth() * settings.zoom / SWF.unitDivisor); + int height = (int) (ftim.displayRect.getHeight() * settings.zoom / SWF.unitDivisor); + try (FileOutputStream fos = new FileOutputStream(f)) { + fos.write(Utf8Helper.getBytes("\r\n")); + Set library = new HashSet<>(); + ftim.getNeededCharacters(fframes, library); + + SWF.writeLibrary(fswf, library, fos); + + String currentName = ftim.id == 0 ? "main" : SWF.getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id; + + fos.write(Utf8Helper.getBytes("function " + currentName + "(ctx,ctrans,frame,ratio,time){\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.save();\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.transform(1,0,0,1," + (-ftim.displayRect.Xmin * settings.zoom / SWF.unitDivisor) + "," + (-ftim.displayRect.Ymin * settings.zoom / SWF.unitDivisor) + ");\r\n")); + fos.write(Utf8Helper.getBytes(framesToHtmlCanvas(SWF.unitDivisor / settings.zoom, ftim, fframes, 0, null, 0, ftim.displayRect, new ColorTransform(), fbackgroundColor))); + fos.write(Utf8Helper.getBytes("\tctx.restore();\r\n")); + fos.write(Utf8Helper.getBytes("}\r\n\r\n")); + + fos.write(Utf8Helper.getBytes("var frame = -1;\r\n")); + fos.write(Utf8Helper.getBytes("var time = 0;\r\n")); + fos.write(Utf8Helper.getBytes("var frames = [];\r\n")); + for (int i : fframes) { + fos.write(Utf8Helper.getBytes("frames.push(" + i + ");\r\n")); + } + fos.write(Utf8Helper.getBytes("\r\n")); + RGB backgroundColor = new RGB(255, 255, 255); + for (Tag t : fswf.tags) { + if (t instanceof SetBackgroundColorTag) { + SetBackgroundColorTag sb = (SetBackgroundColorTag) t; + backgroundColor = sb.backgroundColor; + } + } + + fos.write(Utf8Helper.getBytes("var backgroundColor = \"" + backgroundColor.toHexRGB() + "\";\r\n")); + fos.write(Utf8Helper.getBytes("var originalWidth = " + width + ";\r\n")); + fos.write(Utf8Helper.getBytes("var originalHeight= " + height + ";\r\n")); + fos.write(Utf8Helper.getBytes("function nextFrame(ctx,ctrans){\r\n")); + fos.write(Utf8Helper.getBytes("\tvar oldframe = frame;\r\n")); + fos.write(Utf8Helper.getBytes("\tframe = (frame+1)%frames.length;\r\n")); + fos.write(Utf8Helper.getBytes("\tif(frame==oldframe){time++;}else{time=0;};\r\n")); + fos.write(Utf8Helper.getBytes("\tdrawFrame();\r\n")); + fos.write(Utf8Helper.getBytes("}\r\n\r\n")); + + fos.write(Utf8Helper.getBytes("function drawFrame(){\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.fillStyle = backgroundColor;\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.fillRect(0,0,canvas.width,canvas.height);\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.save();\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n")); + fos.write(Utf8Helper.getBytes("\t" + currentName + "(ctx,ctrans,frames[frame],0,time);\r\n")); + fos.write(Utf8Helper.getBytes("\tctx.restore();\r\n")); + fos.write(Utf8Helper.getBytes("}\r\n\r\n")); + if (ftim.swf.frameRate > 0) { + fos.write(Utf8Helper.getBytes("window.setInterval(function(){nextFrame(ctx,ctrans);}," + (int) (1000.0 / ftim.swf.frameRate) + ");\r\n")); + } + fos.write(Utf8Helper.getBytes("nextFrame(ctx,ctrans);\r\n")); + } + + boolean packed = false; + if (Configuration.packJavaScripts.get()) { + try { + JPacker.main(new String[]{"-q", "-b", "62", "-o", fmin.getAbsolutePath(), f.getAbsolutePath()}); + f.delete(); + packed = true; + } catch (Exception | Error e) { // Something wrong in the packer + logger.log(Level.WARNING, "JPacker: Cannot minimize script"); + f.renameTo(fmin); + } + } else { + f.renameTo(fmin); + } + + File fh = new File(foutdir + File.separator + "frames.html"); + try (FileOutputStream fos = new FileOutputStream(fh); FileInputStream fis = new FileInputStream(fmin)) { + fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlPrefix(width, height))); + fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsPrefix())); + byte buf[] = new byte[1000]; + int cnt; + while ((cnt = fis.read(buf)) > 0) { + fos.write(buf, 0, cnt); + } + if (packed) { + fos.write(Utf8Helper.getBytes(";")); + } + fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsSuffix())); + fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlSuffix())); + } + fmin.delete(); + + ret.add(f); + } + }, handler).run(); + + if (evl != null) { + evl.handleExportedEvent("canvas", 1, 1, tim.parentTag == null ? "" : tim.parentTag.getName()); + } + return ret; + } + + final Timeline ftim = tim; + final Color fbackgroundColor = backgroundColor; + final Iterator frameImages = new Iterator() { + + private int pos = 0; + + @Override + public boolean hasNext() { + return fframes.size() > pos; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + @Override + public BufferedImage next() { + if (!hasNext()) { + return null; + } + + if (evl != null) { + evl.handleExportingEvent("frame", pos + 1, fframes.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + } + return SWF.frameToImageGet(ftim, fframes.get(pos++), 0, null, 0, ftim.displayRect, new Matrix(), new ColorTransform(), fbackgroundColor, false, settings.zoom).getBufferedImage(); + } + }; + + switch (settings.mode) { + case GIF: + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + "frames.gif"); + SWF.makeGIF(frameImages, swf.frameRate, f); + ret.add(f); + } + }, handler).run(); + break; + case BMP: + for (int i = 0; frameImages.hasNext(); i++) { + final int fi = i; + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".bmp"); + BMPFile.saveBitmap(frameImages.next(), f); + ret.add(f); + } + }, handler).run(); + } + break; + case PNG: + for (int i = 0; frameImages.hasNext(); i++) { + final int fi = i; + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png"); + try (FileOutputStream fos = new FileOutputStream(f)) { + ImageHelper.write(frameImages.next(), "PNG", fos); + } + ret.add(f); + } + }, handler).run(); + } + break; + case PDF: + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + "frames.pdf"); + PDFJob job = new PDFJob(new FileOutputStream(f)); + PageFormat pf = new PageFormat(); + pf.setOrientation(PageFormat.PORTRAIT); + Paper p = new Paper(); + BufferedImage img0 = frameImages.next(); + p.setSize(img0.getWidth() + 10, img0.getHeight() + 10); + pf.setPaper(p); + + for (int i = 0; frameImages.hasNext(); i++) { + BufferedImage img = frameImages.next(); + Graphics g = job.getGraphics(pf); + g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null); + g.dispose(); + } + + job.end(); + ret.add(f); + } + }, handler).run(); + break; + case AVI: + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + "frames.avi"); + SWF.makeAVI(frameImages, swf.frameRate, f); + ret.add(f); + } + }, handler).run(); + break; + } + + if (evl != null) { + evl.handleExportedEvent("frame", fframes.size(), fframes.size(), tim.parentTag == null ? "" : tim.parentTag.getName()); + } + return ret; + } + + private static String jsArrColor(RGB rgb) { + return "[" + rgb.red + "," + rgb.green + "," + rgb.blue + "," + ((rgb instanceof RGBA) ? ((RGBA) rgb).getAlphaFloat() : 1) + "]"; + } + + public static String framesToHtmlCanvas(double unitDivisor, Timeline timeline, List frames, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, ColorTransform colorTransform, Color backGroundColor) { + StringBuilder sb = new StringBuilder(); + if (frames == null) { + frames = new ArrayList<>(); + for (int i = 0; i < timeline.getFrameCount(); i++) { + frames.add(i); + } + } + sb.append("\tvar clips = [];\r\n"); + sb.append("\tvar frame_cnt = ").append(timeline.getFrameCount()).append(";\r\n"); + sb.append("\tframe = frame % frame_cnt;\r\n"); + sb.append("\tswitch(frame){\r\n"); + int maxDepth = timeline.getMaxDepth(); + Stack clipDepths = new Stack<>(); + for (int frame : frames) { + sb.append("\t\tcase ").append(frame).append(":\r\n"); + Frame frameObj = timeline.getFrame(frame); + for (int i = 1; i <= maxDepth + 1; i++) { + while (!clipDepths.isEmpty() && clipDepths.peek() <= i) { + clipDepths.pop(); + sb.append("\t\t\tvar o = clips.pop();\r\n"); + sb.append("\t\t\tctx.globalCompositeOperation = \"destination-in\";\r\n"); + sb.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); + sb.append("\t\t\tctx.drawImage(o.clipCanvas,0,0);\r\n"); + sb.append("\t\t\tvar ms=o.ctx._matrix;\r\n"); + sb.append("\t\t\to.ctx.setTransform(1,0,0,1,0,0);\r\n"); + sb.append("\t\t\to.ctx.globalCompositeOperation = \"source-over\";\r\n"); + sb.append("\t\t\to.ctx.drawImage(canvas,0,0);\r\n"); + sb.append("\t\t\to.ctx.applyTransforms(ms);\r\n"); + sb.append("\t\t\tctx = o.ctx;\r\n"); + sb.append("\t\t\tcanvas = o.canvas;\r\n"); + } + if (!frameObj.layers.containsKey(i)) { + continue; + } + DepthState layer = frameObj.layers.get(i); + if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { + continue; + } + if (!layer.isVisible) { + continue; + } + CharacterTag character = timeline.swf.getCharacter(layer.characterId); + + if (colorTransform == null) { + colorTransform = new ColorTransform(); + } + Matrix placeMatrix = new Matrix(layer.matrix); + placeMatrix.scaleX /= unitDivisor; + placeMatrix.scaleY /= unitDivisor; + placeMatrix.rotateSkew0 /= unitDivisor; + placeMatrix.rotateSkew1 /= unitDivisor; + placeMatrix.translateX /= unitDivisor; + placeMatrix.translateY /= unitDivisor; + + int f = 0; + String fstr = "0"; + if (character instanceof DefineSpriteTag) { + DefineSpriteTag sp = (DefineSpriteTag) character; + Timeline tim = sp.getTimeline(); + if (tim.getFrameCount() > 0) { + f = layer.time % tim.getFrameCount(); + fstr = "(" + f + "+time)%" + tim.getFrameCount(); + } + } + + if (layer.clipDepth != -1) { + clipDepths.push(layer.clipDepth); + sb.append("\t\t\tclips.push({ctx:ctx,canvas:canvas});\r\n"); + sb.append("\t\t\tvar ccanvas = createCanvas(canvas.width,canvas.height);\r\n"); + sb.append("\t\t\tvar cctx = ccanvas.getContext(\"2d\");\r\n"); + sb.append("\t\t\tenhanceContext(cctx);\r\n"); + sb.append("\t\t\tcctx.applyTransforms(ctx._matrix);\r\n"); + sb.append("\t\t\tcanvas = ccanvas;\r\n"); + sb.append("\t\t\tctx = cctx;\r\n"); + } + + if (layer.filters != null && layer.filters.size() > 0) { + sb.append("\t\t\tvar oldctx = ctx;\r\n"); + sb.append("\t\t\tvar fcanvas = createCanvas(canvas.width,canvas.height);"); + sb.append("\t\t\tvar fctx = fcanvas.getContext(\"2d\");\r\n"); + sb.append("\t\t\tenhanceContext(fctx);\r\n"); + sb.append("\t\t\tfctx.applyTransforms(ctx._matrix);\r\n"); + sb.append("\t\t\tctx = fctx;\r\n"); + } + + ColorTransform ctrans = layer.colorTransForm; + String ctrans_str = "ctrans"; + if (ctrans == null) { + ctrans = new ColorTransform(); + } else { + ctrans_str = "ctrans.merge(new cxform(" + + ctrans.getRedAdd() + "," + ctrans.getGreenAdd() + "," + ctrans.getBlueAdd() + "," + ctrans.getAlphaAdd() + "," + + ctrans.getRedMulti() + "," + ctrans.getGreenMulti() + "," + ctrans.getBlueMulti() + "," + ctrans.getAlphaMulti() + + "))"; + } + sb.append("\t\t\tplace(\"").append(SWF.getTypePrefix(character)).append(layer.characterId).append("\",canvas,ctx,[").append(placeMatrix.scaleX).append(",") + .append(placeMatrix.rotateSkew0).append(",") + .append(placeMatrix.rotateSkew1).append(",") + .append(placeMatrix.scaleY).append(",") + .append(placeMatrix.translateX).append(",") + .append(placeMatrix.translateY).append("],").append(ctrans_str).append(",").append("").append(layer.blendMode < 1 ? 1 : layer.blendMode).append(",").append(fstr).append(",").append(layer.ratio < 0 ? 0 : layer.ratio).append(",time").append(");\r\n"); + + if (layer.filters != null && layer.filters.size() > 0) { + for (FILTER filter : layer.filters) { + if (filter instanceof COLORMATRIXFILTER) { + COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter; + String mat = "["; + for (int k = 0; k < cmf.matrix.length; k++) { + if (k > 0) { + mat += ","; + } + mat += cmf.matrix[k]; + } + mat += "]"; + sb.append("\t\t\tfcanvas = Filters.colorMatrix(fcanvas,fcanvas.getContext(\"2d\"),").append(mat).append(");\r\n"); + } + + if (filter instanceof CONVOLUTIONFILTER) { + CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) filter; + int height = cf.matrix.length; + int width = cf.matrix[0].length; + float[] matrix2 = new float[width * height]; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + matrix2[y * width + x] = cf.matrix[x][y] * cf.divisor + cf.bias; + } + } + String mat = "["; + for (int k = 0; k < matrix2.length; k++) { + if (k > 0) { + mat += ","; + } + mat += matrix2[k]; + } + mat += "]"; + sb.append("\t\t\tfcanvas = Filters.convolution(fcanvas,fcanvas.getContext(\"2d\"),").append(mat).append(",false);\r\n"); + } + + if (filter instanceof GLOWFILTER) { + GLOWFILTER gf = (GLOWFILTER) filter; + sb.append("\t\t\tfcanvas = Filters.glow(fcanvas,fcanvas.getContext(\"2d\"),").append(gf.blurX).append(",").append(gf.blurY).append(",").append(gf.strength).append(",").append(jsArrColor(gf.glowColor)).append(",").append(gf.innerGlow ? "true" : "false").append(",").append(gf.knockout ? "true" : "false").append(",").append(gf.passes).append(");\r\n"); + } + + if (filter instanceof DROPSHADOWFILTER) { + DROPSHADOWFILTER ds = (DROPSHADOWFILTER) filter; + sb.append("\t\t\tfcanvas = Filters.dropShadow(fcanvas,fcanvas.getContext(\"2d\"),").append(ds.blurX).append(",").append(ds.blurY).append(",").append((int) (ds.angle * 180 / Math.PI)).append(",").append(ds.distance).append(",").append(jsArrColor(ds.dropShadowColor)).append(",").append(ds.innerShadow ? "true" : "false").append(",").append(ds.passes).append(",").append(ds.strength).append(",").append(ds.knockout ? "true" : "false").append(");\r\n"); + } + if (filter instanceof BEVELFILTER) { + BEVELFILTER bv = (BEVELFILTER) filter; + String type = "Filters.INNER"; + if (bv.onTop && !bv.innerShadow) { + type = "Filters.FULL"; + } else if (!bv.innerShadow) { + type = "Filters.OUTER"; + } + sb.append("\t\t\tfcanvas = Filters.bevel(fcanvas,fcanvas.getContext(\"2d\"),").append(bv.blurX).append(",").append(bv.blurY).append(",").append(bv.strength).append(",").append(type).append(",").append(jsArrColor(bv.highlightColor)).append(",").append(jsArrColor(bv.shadowColor)).append(",").append((int) (bv.angle * 180 / Math.PI)).append(",").append(bv.distance).append(",").append(bv.knockout ? "true" : "false").append(",").append(bv.passes).append(");\r\n"); + } + + if (filter instanceof GRADIENTBEVELFILTER) { + GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter; + String colArr = "["; + String ratArr = "["; + for (int k = 0; k < gbf.gradientColors.length; k++) { + if (k > 0) { + colArr += ","; + ratArr += ","; + } + colArr += jsArrColor(gbf.gradientColors[k]); + ratArr += gbf.gradientRatio[k] / 255f; + } + colArr += "]"; + ratArr += "]"; + String type = "Filters.INNER"; + if (gbf.onTop && !gbf.innerShadow) { + type = "Filters.FULL"; + } else if (!gbf.innerShadow) { + type = "Filters.OUTER"; + } + + sb.append("\t\t\tfcanvas = Filters.gradientBevel(fcanvas,fcanvas.getContext(\"2d\"),").append(colArr).append(",").append(ratArr).append(",").append(gbf.blurX).append(",").append(gbf.blurY).append(",").append(gbf.strength).append(",").append(type).append(",").append((int) (gbf.angle * 180 / Math.PI)).append(",").append(gbf.distance).append(",").append(gbf.knockout ? "true" : "false").append(",").append(gbf.passes).append(");\r\n"); + } + + if (filter instanceof GRADIENTGLOWFILTER) { + GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter; + String colArr = "["; + String ratArr = "["; + for (int k = 0; k < ggf.gradientColors.length; k++) { + if (k > 0) { + colArr += ","; + ratArr += ","; + } + colArr += jsArrColor(ggf.gradientColors[k]); + ratArr += ggf.gradientRatio[k] / 255f; + } + colArr += "]"; + ratArr += "]"; + String type = "Filters.INNER"; + if (ggf.onTop && !ggf.innerShadow) { + type = "Filters.FULL"; + } else if (!ggf.innerShadow) { + type = "Filters.OUTER"; + } + + sb.append("\t\t\tfcanvas = Filters.gradientGlow(fcanvas,fcanvas.getContext(\"2d\"),").append(ggf.blurX).append(",").append(ggf.blurY).append(",").append((int) (ggf.angle * 180 / Math.PI)).append(",").append(ggf.distance).append(",").append(colArr).append(",").append(ratArr).append(",").append(type).append(",").append(ggf.passes).append(",").append(ggf.strength).append(",").append(ggf.knockout ? "true" : "false").append(");\r\n"); + } + } + sb.append("\t\t\tctx = oldctx;\r\n"); + sb.append("\t\t\tvar ms=ctx._matrix;\r\n"); + sb.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); + sb.append("\t\t\tctx.drawImage(fcanvas,0,0);\r\n"); + sb.append("\t\t\tctx.applyTransforms(ms);\r\n"); + } + + if (layer.clipDepth != -1) { + sb.append("\t\t\tclips[clips.length-1].clipCanvas = canvas;\r\n"); + sb.append("\t\t\tcanvas = createCanvas(canvas.width,canvas.height);\r\n"); + sb.append("\t\t\tvar nctx = canvas.getContext(\"2d\");\r\n"); + sb.append("\t\t\tenhanceContext(nctx);\r\n"); + sb.append("\t\t\tnctx.applyTransforms(ctx._matrix);\r\n"); + sb.append("\t\t\tctx = nctx;\r\n"); + } + } + sb.append("\t\t\tbreak;\r\n"); + } + sb.append("\t}\r\n"); + return sb.toString(); + } +} 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 8c6eae198..a2d050e0e 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 @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; @@ -39,7 +40,7 @@ import java.util.Locale; */ public class ImageExporter { - public List exportImages(AbortRetryIgnoreHandler handler, String outdir, List tags, final ImageExportSettings settings) throws IOException { + public List exportImages(AbortRetryIgnoreHandler handler, String outdir, List tags, ImageExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -52,10 +53,24 @@ public class ImageExporter { } } } - for (final Tag t : tags) { - if (t instanceof ImageTag) { - String fileFormat = ((ImageTag) t).getImageFormat().toUpperCase(Locale.ENGLISH); + int count = 0; + for (Tag t : tags) { + if (t instanceof ImageTag) { + count++; + } + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof ImageTag) { + if (evl != null) { + evl.handleExportingEvent("image", currentIndex, count, t.getName()); + } + + final ImageTag imageTag = (ImageTag) t; + + String fileFormat = imageTag.getImageFormat().toUpperCase(Locale.ENGLISH); if (settings.mode == ImageExportMode.PNG) { fileFormat = "png"; } @@ -66,9 +81,8 @@ public class ImageExporter { if (settings.mode == ImageExportMode.BMP) { fileFormat = "bmp"; } - { - final ImageTag imageTag = (ImageTag) t; + { final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + fileFormat)); final String ffileFormat = fileFormat; @@ -87,8 +101,14 @@ public class ImageExporter { ret.add(file); } + if (evl != null) { + evl.handleExportedEvent("image", currentIndex, count, t.getName()); + } + + currentIndex++; } } + return ret; } } 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 543d2bc1e..80ba257c7 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 @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.SWF; @@ -48,7 +49,7 @@ import java.util.Set; public class MorphShapeExporter { //TODO: implement morphshape export. How to handle 65536 frames? - public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final MorphShapeExportSettings settings) throws IOException { + public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -62,8 +63,20 @@ public class MorphShapeExporter { } } + int count = 0; + for (Tag t : tags) { + if (t instanceof MorphShapeTag) { + count++; + } + } + + int currentIndex = 1; for (final Tag t : tags) { if (t instanceof MorphShapeTag) { + if (evl != null) { + evl.handleExportingEvent("morphshape", currentIndex, count, t.getName()); + } + int characterID = 0; if (t instanceof CharacterTag) { characterID = ((CharacterTag) t).getCharacterId(); @@ -71,7 +84,6 @@ public class MorphShapeExporter { String ext = settings.mode == MorphShapeExportMode.CANVAS ? "html" : "svg"; final File file = new File(outdir + File.separator + characterID + "." + ext); - final int fcharacterID = characterID; new RetryTask(new RunnableIOEx() { @Override public void run() throws IOException { @@ -109,6 +121,12 @@ public class MorphShapeExporter { } }, handler).run(); ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("morphshape", currentIndex, count, t.getName()); + } + + currentIndex++; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java index da2678bf7..dcd8e1584 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MovieExporter.java @@ -1,21 +1,23 @@ /* * Copyright (C) 2010-2015 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. */ + * 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.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.SWF; @@ -45,7 +47,7 @@ import java.util.List; */ public class MovieExporter { - public List exportMovies(AbortRetryIgnoreHandler handler, String outdir, List tags, final MovieExportSettings settings) throws IOException { + public List exportMovies(AbortRetryIgnoreHandler handler, String outdir, List tags, final MovieExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -58,8 +60,21 @@ public class MovieExporter { } } } + + int count = 0; for (Tag t : tags) { if (t instanceof DefineVideoStreamTag) { + count++; + } + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof DefineVideoStreamTag) { + if (evl != null) { + evl.handleExportingEvent("movie", currentIndex, count, t.getName()); + } + final DefineVideoStreamTag videoStream = (DefineVideoStreamTag) t; final File file = new File(outdir + File.separator + Helper.makeFileName(videoStream.getCharacterExportFileName() + ".flv")); new RetryTask(new RunnableIOEx() { @@ -71,6 +86,11 @@ public class MovieExporter { } }, handler).run(); + if (evl != null) { + evl.handleExportedEvent("movie", currentIndex, count, t.getName()); + } + + currentIndex++; } } return ret; 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 bdde3e618..a8db8a2c0 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 @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.SWF; @@ -53,7 +54,7 @@ import java.util.Set; */ public class ShapeExporter { - public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final ShapeExportSettings settings) throws IOException { + public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final ShapeExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -67,8 +68,20 @@ public class ShapeExporter { } } + int count = 0; + for (Tag t : tags) { + if (t instanceof ShapeTag) { + count++; + } + } + + int currentIndex = 1; for (final Tag t : tags) { if (t instanceof ShapeTag) { + if (evl != null) { + evl.handleExportingEvent("shape", currentIndex, count, t.getName()); + } + int characterID = 0; if (t instanceof CharacterTag) { characterID = ((CharacterTag) t).getCharacterId(); @@ -141,6 +154,12 @@ public class ShapeExporter { } }, handler).run(); ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("shape", currentIndex, count, t.getName()); + } + + currentIndex++; } } if (settings.mode == ShapeExportMode.CANVAS) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java index 7de8f91ac..d1c2faef6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/SoundExporter.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.SWF; @@ -48,7 +49,7 @@ import java.util.List; */ public class SoundExporter { - public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings) throws IOException { + public List exportSounds(AbortRetryIgnoreHandler handler, String outdir, List tags, final SoundExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -61,14 +62,21 @@ public class SoundExporter { } } } - for (Tag t : tags) { - File newfile = null; - int id = 0; - if (t instanceof DefineSoundTag) { - id = ((DefineSoundTag) t).soundId; - } + int count = 0; + for (Tag t : tags) { if (t instanceof SoundTag) { + count++; + } + } + + int currentIndex = 1; + for (Tag t : tags) { + if (t instanceof SoundTag) { + if (evl != null) { + evl.handleExportingEvent("sound", currentIndex, count, t.getName()); + } + final SoundTag st = (SoundTag) t; String ext = "wav"; @@ -90,7 +98,6 @@ public class SoundExporter { } final File file = new File(outdir + File.separator + st.getCharacterExportFileName() + "." + ext); - newfile = file; new RetryTask(new RunnableIOEx() { @Override public void run() throws IOException { @@ -100,10 +107,14 @@ public class SoundExporter { } }, handler).run(); - ret.add(newfile); + ret.add(file); + if (evl != null) { + evl.handleExportedEvent("sound", currentIndex, count, t.getName()); + } + + currentIndex++; } - } return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java index a79860ffd..9034ec462 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/TextExporter.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.configuration.Configuration; @@ -48,7 +49,7 @@ public class TextExporter { public static final String TEXT_EXPORT_FILENAME_PLAIN = "textsplain.txt"; - public List exportTexts(AbortRetryIgnoreHandler handler, String outdir, List tags, final TextExportSettings settings) throws IOException { + public List exportTexts(AbortRetryIgnoreHandler handler, String outdir, List tags, final TextExportSettings settings, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (tags.isEmpty()) { return ret; @@ -62,9 +63,21 @@ public class TextExporter { } } + int count = 0; + for (Tag t : tags) { + if (t instanceof TextTag) { + count++; + } + } + + int currentIndex = 1; if (settings.mode == TextExportMode.SVG) { for (Tag t : tags) { if (t instanceof TextTag) { + if (evl != null) { + evl.handleExportingEvent("text", currentIndex, count, t.getName()); + } + final TextTag textTag = (TextTag) t; final File file = new File(outdir + File.separator + Helper.makeFileName(textTag.getCharacterExportFileName() + ".svg")); new RetryTask(new RunnableIOEx() { @@ -79,6 +92,12 @@ public class TextExporter { } }, handler).run(); ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("text", currentIndex, count, t.getName()); + } + + currentIndex++; } } return ret; @@ -119,6 +138,10 @@ public class TextExporter { } else { for (Tag t : tags) { if (t instanceof TextTag) { + if (evl != null) { + evl.handleExportingEvent("text", currentIndex, count, t.getName()); + } + final TextTag textTag = (TextTag) t; final File file = new File(outdir + File.separator + Helper.makeFileName(textTag.getCharacterExportFileName() + ".txt")); new RetryTask(new RunnableIOEx() { @@ -137,6 +160,12 @@ public class TextExporter { } }, handler).run(); ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("text", currentIndex, count, t.getName()); + } + + currentIndex++; } } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java index a2c33c031..2a4d4c0c8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/script/AS2ScriptExporter.java @@ -47,13 +47,13 @@ import java.util.logging.Logger; */ public class AS2ScriptExporter { - public List exportAS2ScriptsTimeout(final AbortRetryIgnoreHandler handler, final String outdir, final Map asms, final ScriptExportMode exportMode, final EventListener ev) throws IOException { + public List exportAS2ScriptsTimeout(final AbortRetryIgnoreHandler handler, final String outdir, final Map asms, final ScriptExportMode exportMode, final EventListener evl) throws IOException { try { List result = CancellableWorker.call(new Callable>() { @Override public List call() throws Exception { - return exportAS2Scripts(handler, outdir, asms, exportMode, ev); + return exportAS2Scripts(handler, outdir, asms, exportMode, evl); } }, Configuration.exportTimeout.get(), TimeUnit.SECONDS); return result; @@ -62,7 +62,7 @@ public class AS2ScriptExporter { return new ArrayList<>(); } - private List exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map asms, ScriptExportMode exportMode, EventListener ev) throws IOException { + private List exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map asms, ScriptExportMode exportMode, EventListener evl) throws IOException { List ret = new ArrayList<>(); if (!outdir.endsWith(File.separator)) { outdir += File.separator; @@ -90,7 +90,7 @@ public class AS2ScriptExporter { } existingNames.add(name); - File f = exportAS2Script(handler, currentOutDir, asm, exportMode, ev, cnt, asms.size(), name); + File f = exportAS2Script(handler, currentOutDir, asm, exportMode, evl, cnt, asms.size(), name); if (f != null) { ret.add(f); } @@ -99,7 +99,7 @@ public class AS2ScriptExporter { return ret; } - private File exportAS2Script(AbortRetryIgnoreHandler handler, String outdir, ASMSource asm, ScriptExportMode exportMode, EventListener ev, AtomicInteger index, int count, String name) throws IOException { + private File exportAS2Script(AbortRetryIgnoreHandler handler, String outdir, ASMSource asm, ScriptExportMode exportMode, EventListener evl, AtomicInteger index, int count, String name) throws IOException { boolean retry; do { retry = false; @@ -116,8 +116,8 @@ public class AS2ScriptExporter { } String f = outdir + name + ".as"; - if (ev != null) { - ev.handleEvent("exporting", "Exporting " + currentIndex + "/" + count + " " + f); + if (evl != null) { + evl.handleExportingEvent("script", currentIndex, count, f); } long startTime = System.currentTimeMillis(); @@ -141,9 +141,9 @@ public class AS2ScriptExporter { long stopTime = System.currentTimeMillis(); - if (ev != null) { + if (evl != null) { long time = stopTime - startTime; - ev.handleEvent("exported", "Exported " + currentIndex + "/" + count + " " + f + ", " + Helper.formatTimeSec(time)); + evl.handleExportedEvent("script", currentIndex, count, f + ", " + Helper.formatTimeSec(time)); } return file; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 048a71ea1..8ec97c84b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.timeline; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.FrameExporter; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.DoInitActionTag; @@ -426,7 +427,7 @@ public class Timeline { } public String toHtmlCanvas(double unitDivisor, List frames) { - return SWF.framesToHtmlCanvas(unitDivisor, this, frames, 0, null, 0, displayRect, new ColorTransform(), null); + return FrameExporter.framesToHtmlCanvas(unitDivisor, this, frames, 0, null, 0, displayRect, new ColorTransform(), null); } public void getSounds(int frame, int time, DepthState stateUnderCursor, int mouseButton, List sounds, List soundClasses) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index 872a06957..351e5263c 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -3064,7 +3064,7 @@ public class XFLConverter { } if (useAS3) { try { - swf.exportActionScript(handler, outDir.getAbsolutePath(), ScriptExportMode.AS, parallel); + swf.exportActionScript(handler, outDir.getAbsolutePath(), ScriptExportMode.AS, parallel, null); } catch (Exception ex) { Logger.getLogger(XFLConverter.class.getName()).log(Level.SEVERE, "Error during ActionScript3 export", ex); } diff --git a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java index 8a020e813..16c41e395 100644 --- a/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java +++ b/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java @@ -40,6 +40,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItem; import com.jpexs.decompiler.flash.exporters.BinaryDataExporter; import com.jpexs.decompiler.flash.exporters.FontExporter; +import com.jpexs.decompiler.flash.exporters.FrameExporter; import com.jpexs.decompiler.flash.exporters.ImageExporter; import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; import com.jpexs.decompiler.flash.exporters.MovieExporter; @@ -909,14 +910,28 @@ public class CommandLineArgumentParser { final Level level = traceLevel; exfile.addEventListener(new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + if (level.intValue() <= Level.FINE.intValue()) { + String text = "Exporting "; + if (type != null && type.length() > 0) { + text += type + " "; + } + System.out.println(text + index + "/" + count + " " + data); + } + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + String text = "Exported "; + if (type != null && type.length() > 0) { + text += type + " "; + } + System.out.println(text + index + "/" + count + " " + data); + } + @Override public void handleEvent(String event, Object data) { - if (level.intValue() <= Level.FINE.intValue() && event.equals("exporting")) { - System.out.println((String) data); - } - if (event.equals("exported")) { - System.out.println((String) data); - } } }); @@ -935,40 +950,41 @@ public class CommandLineArgumentParser { commandLineMode = true; boolean exportAll = exportFormats.contains("all"); boolean multipleExportTypes = exportAll || exportFormats.size() > 1; + EventListener evl = exfile.getExportEventListener(); if (exportAll || exportFormats.contains("image")) { System.out.println("Exporting images..."); - new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + "images" : ""), extags, new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class))); + new ImageExporter().exportImages(handler, outDir + (multipleExportTypes ? File.separator + "images" : ""), extags, new ImageExportSettings(enumFromStr(formats.get("image"), ImageExportMode.class)), evl); } if (exportAll || exportFormats.contains("shape")) { System.out.println("Exporting shapes..."); - new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + "shapes" : ""), extags, new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom)); + new ShapeExporter().exportShapes(handler, outDir + (multipleExportTypes ? File.separator + "shapes" : ""), extags, new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class), zoom), evl); } if (exportAll || exportFormats.contains("morphshape")) { System.out.println("Exporting morphshapes..."); - new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + "morphshapes" : ""), extags, new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom)); + new MorphShapeExporter().exportMorphShapes(handler, outDir + (multipleExportTypes ? File.separator + "morphshapes" : ""), extags, new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class), zoom), evl); } if (exportAll || exportFormats.contains("movie")) { System.out.println("Exporting movies..."); - new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + "movies" : ""), extags, new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class))); + new MovieExporter().exportMovies(handler, outDir + (multipleExportTypes ? File.separator + "movies" : ""), extags, new MovieExportSettings(enumFromStr(formats.get("movie"), MovieExportMode.class)), evl); } if (exportAll || exportFormats.contains("font")) { System.out.println("Exporting fonts..."); - new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + "fonts" : ""), extags, new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class))); + new FontExporter().exportFonts(handler, outDir + (multipleExportTypes ? File.separator + "fonts" : ""), extags, new FontExportSettings(enumFromStr(formats.get("font"), FontExportMode.class)), evl); } if (exportAll || exportFormats.contains("sound")) { System.out.println("Exporting sounds..."); - new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + "sounds" : ""), extags, new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class))); + new SoundExporter().exportSounds(handler, outDir + (multipleExportTypes ? File.separator + "sounds" : ""), extags, new SoundExportSettings(enumFromStr(formats.get("sound"), SoundExportMode.class)), evl); } if (exportAll || exportFormats.contains("binarydata")) { System.out.println("Exporting binaryData..."); - new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + "binaryData" : ""), extags, new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class))); + new BinaryDataExporter().exportBinaryData(handler, outDir + (multipleExportTypes ? File.separator + "binaryData" : ""), extags, new BinaryDataExportSettings(enumFromStr(formats.get("binarydata"), BinaryDataExportMode.class)), evl); } if (exportAll || exportFormats.contains("text")) { @@ -977,7 +993,7 @@ public class CommandLineArgumentParser { if (singleTextFile == null) { singleTextFile = Configuration.textExportSingleFile.get(); } - new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + "texts" : ""), extags, new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom)); + new TextExporter().exportTexts(handler, outDir + (multipleExportTypes ? File.separator + "texts" : ""), extags, new TextExportSettings(enumFromStr(formats.get("text"), TextExportMode.class), singleTextFile, zoom), evl); } if (exportAll || exportFormats.contains("frame")) { @@ -988,7 +1004,7 @@ public class CommandLineArgumentParser { frames.add(i); } } - exfile.exportFrames(handler, outDir + (multipleExportTypes ? File.separator + "frames" : ""), 0, frames, new FramesExportSettings(enumFromStr(formats.get("frame"), FramesExportMode.class), zoom)); + new FrameExporter().exportFrames(handler, outDir + (multipleExportTypes ? File.separator + "frames" : ""), exfile, 0, frames, new FramesExportSettings(enumFromStr(formats.get("frame"), FramesExportMode.class), zoom), evl); } if (exportAll || exportFormats.contains("script")) { @@ -999,10 +1015,10 @@ public class CommandLineArgumentParser { } if (!as3classes.isEmpty()) { for (String as3class : as3classes) { - exportOK = exportOK && exfile.exportAS3Class(as3class, outDir, enumFromStr(formats.get("script"), ScriptExportMode.class), parallel); + exportOK = exportOK && exfile.exportAS3Class(as3class, outDir, enumFromStr(formats.get("script"), ScriptExportMode.class), parallel, evl); } } else { - exportOK = exportOK && exfile.exportActionScript(handler, outDir, enumFromStr(formats.get("script"), ScriptExportMode.class), parallel) != null; + exportOK = exportOK && exfile.exportActionScript(handler, outDir, enumFromStr(formats.get("script"), ScriptExportMode.class), parallel, evl) != null; } } diff --git a/src/com/jpexs/decompiler/flash/gui/Main.java b/src/com/jpexs/decompiler/flash/gui/Main.java index c9d2cac31..5765de7ea 100644 --- a/src/com/jpexs/decompiler/flash/gui/Main.java +++ b/src/com/jpexs/decompiler/flash/gui/Main.java @@ -358,10 +358,30 @@ public class Main { swf.swfList = result; swf.addEventListener(new EventListener() { + @Override + public void handleExportingEvent(String type, int index, int count, Object data) { + // todo honfika: localize + String text = "Exporting "; + if (type != null && type.length() > 0) { + text += type + " "; + } + startWork(text + index + "/" + count + " " + data); + } + + @Override + public void handleExportedEvent(String type, int index, int count, Object data) { + // todo honfika: localize + String text = "Exported "; + if (type != null && type.length() > 0) { + text += type + " "; + } + startWork(text + index + "/" + count + " " + data); + } + @Override public void handleEvent(String event, Object data) { - if (event.equals("exporting")) { - startWork((String) data); + if (event.equals("exporting") || event.equals("exported")) { + throw new Error("Event is not supported by this handler."); } if (event.equals("getVariables")) { startWork(AppStrings.translate("work.gettingvariables") + "..." + (String) data); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index f9ea387ad..47b93d6c3 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFBundle; import com.jpexs.decompiler.flash.abc.ABC; @@ -31,6 +32,7 @@ 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.FontExporter; +import com.jpexs.decompiler.flash.exporters.FrameExporter; import com.jpexs.decompiler.flash.exporters.ImageExporter; import com.jpexs.decompiler.flash.exporters.MorphShapeExporter; import com.jpexs.decompiler.flash.exporters.MovieExporter; @@ -1037,27 +1039,30 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } + EventListener evl = swf.getExportEventListener(); + final ScriptExportMode scriptMode = export.getValue(ScriptExportMode.class); ret.addAll(new ImageExporter().exportImages(handler, selFile + File.separator + "images", images, - new ImageExportSettings(export.getValue(ImageExportMode.class)))); + new ImageExportSettings(export.getValue(ImageExportMode.class)), evl)); ret.addAll(new ShapeExporter().exportShapes(handler, selFile + File.separator + "shapes", shapes, - new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()))); + new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl)); ret.addAll(new MorphShapeExporter().exportMorphShapes(handler, selFile + File.separator + "morphshapes", morphshapes, - new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()))); + new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl)); ret.addAll(new TextExporter().exportTexts(handler, selFile + File.separator + "texts", texts, - new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()))); + new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl)); ret.addAll(new MovieExporter().exportMovies(handler, selFile + File.separator + "movies", movies, - new MovieExportSettings(export.getValue(MovieExportMode.class)))); + new MovieExportSettings(export.getValue(MovieExportMode.class)), evl)); ret.addAll(new SoundExporter().exportSounds(handler, selFile + File.separator + "sounds", sounds, - new SoundExportSettings(export.getValue(SoundExportMode.class)))); + new SoundExportSettings(export.getValue(SoundExportMode.class)), evl)); ret.addAll(new BinaryDataExporter().exportBinaryData(handler, selFile + File.separator + "binaryData", binaryData, - new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)))); + new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl)); ret.addAll(new FontExporter().exportFonts(handler, selFile + File.separator + "fonts", fonts, - new FontExportSettings(export.getValue(FontExportMode.class)))); + new FontExportSettings(export.getValue(FontExportMode.class)), evl)); + FrameExporter frameExporter = new FrameExporter(); + FramesExportSettings fes = new FramesExportSettings(export.getValue(FramesExportMode.class), export.getZoom()); for (Entry> entry : frames.entrySet()) { - ret.addAll(swf.exportFrames(handler, selFile + File.separator + "frames", entry.getKey(), entry.getValue(), - new FramesExportSettings(export.getValue(FramesExportMode.class), export.getZoom()))); + ret.addAll(frameExporter.exportFrames(handler, selFile + File.separator + "frames", swf, entry.getKey(), entry.getValue(), fes, evl)); } if (swf.isAS3()) { @@ -1068,40 +1073,42 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec } } else { Map asmsToExport = swf.getASMs(true, as12scripts, false); - ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, selFile + File.separator + "scripts", asmsToExport, scriptMode, swf.getExportEventListener())); + ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, selFile + File.separator + "scripts", asmsToExport, scriptMode, evl)); } } return ret; } public void exportAll(SWF swf, AbortRetryIgnoreHandler handler, String selFile, ExportDialog export) throws IOException { + EventListener evl = swf.getExportEventListener(); new ImageExporter().exportImages(handler, selFile + File.separator + "images", swf.tags, - new ImageExportSettings(export.getValue(ImageExportMode.class))); + new ImageExportSettings(export.getValue(ImageExportMode.class)), evl); new ShapeExporter().exportShapes(handler, selFile + File.separator + "shapes", swf.tags, - new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom())); + new ShapeExportSettings(export.getValue(ShapeExportMode.class), export.getZoom()), evl); new MorphShapeExporter().exportMorphShapes(handler, selFile + File.separator + "morphshapes", swf.tags, - new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom())); + new MorphShapeExportSettings(export.getValue(MorphShapeExportMode.class), export.getZoom()), evl); new TextExporter().exportTexts(handler, selFile + File.separator + "texts", swf.tags, - new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom())); + new TextExportSettings(export.getValue(TextExportMode.class), Configuration.textExportSingleFile.get(), export.getZoom()), evl); new MovieExporter().exportMovies(handler, selFile + File.separator + "movies", swf.tags, - new MovieExportSettings(export.getValue(MovieExportMode.class))); + new MovieExportSettings(export.getValue(MovieExportMode.class)), evl); new SoundExporter().exportSounds(handler, selFile + File.separator + "sounds", swf.tags, - new SoundExportSettings(export.getValue(SoundExportMode.class))); + new SoundExportSettings(export.getValue(SoundExportMode.class)), evl); new BinaryDataExporter().exportBinaryData(handler, selFile + File.separator + "binaryData", swf.tags, - new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class))); + new BinaryDataExportSettings(export.getValue(BinaryDataExportMode.class)), evl); new FontExporter().exportFonts(handler, selFile + File.separator + "fonts", swf.tags, - new FontExportSettings(export.getValue(FontExportMode.class))); - swf.exportFrames(handler, selFile + File.separator + "frames", 0, null, - new FramesExportSettings(export.getValue(FramesExportMode.class), export.getZoom())); + new FontExportSettings(export.getValue(FontExportMode.class)), evl); + + FrameExporter frameExporter = new FrameExporter(); + FramesExportSettings fes = new FramesExportSettings(export.getValue(FramesExportMode.class), export.getZoom()); + frameExporter.exportFrames(handler, selFile + File.separator + "frames", swf, 0, null, fes, evl); for (CharacterTag c : swf.getCharacters().values()) { if (c instanceof DefineSpriteTag) { - swf.exportFrames(handler, selFile + File.separator + "frames", c.getCharacterId(), null, - new FramesExportSettings(export.getValue(FramesExportMode.class), export.getZoom())); + frameExporter.exportFrames(handler, selFile + File.separator + "frames", swf, c.getCharacterId(), null, fes, evl); } } ScriptExportMode exportMode = export.getValue(ScriptExportMode.class); - swf.exportActionScript(handler, selFile, exportMode, Configuration.parallelSpeedUp.get()); + swf.exportActionScript(handler, selFile, exportMode, Configuration.parallelSpeedUp.get(), evl); } public List getSwfs() {