#798 ffdec doesn't show what it's exporting

This commit is contained in:
honfika@gmail.com
2015-02-11 22:25:53 +01:00
parent f2922421cb
commit 914bb09355
17 changed files with 956 additions and 648 deletions

View File

@@ -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);
}

View File

@@ -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<ABCContainerTag> 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<File> exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ScriptExportMode exportMode, final boolean parallel) {
private List<File> exportActionScript3(final AbortRetryIgnoreHandler handler, final String outdir, final ScriptExportMode exportMode, final boolean parallel, final EventListener evl) {
final AtomicInteger cnt = new AtomicInteger(1);
final List<File> ret = new ArrayList<>();
@@ -1200,7 +1181,7 @@ public final class SWF implements SWFContainerItem, Timelined {
@Override
public Void call() throws Exception {
for (MyEntry<ClassPath, ScriptPack> 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<Future<File>> futureResults = new ArrayList<>();
for (MyEntry<ClassPath, ScriptPack> item : packs) {
Future<File> future = executor.submit(new ExportPackTask(handler, cnt, packs.size(), item.getKey(), item.getValue(), outdir, exportMode, parallel));
Future<File> 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<File> exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportMode exportMode, boolean parallel) throws IOException {
public List<File> exportActionScript(AbortRetryIgnoreHandler handler, String outdir, ScriptExportMode exportMode, boolean parallel, EventListener evl) throws IOException {
List<File> 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<BufferedImage> images, int frameRate, File file) throws IOException {
public static void makeAVI(Iterator<BufferedImage> 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<BufferedImage> images, int frameRate, File file) throws IOException {
public static void makeGIF(Iterator<BufferedImage> 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<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, int containerId, List<Integer> frames, final FramesExportSettings settings) throws IOException {
final List<File> 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<Integer> 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<Integer> 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<BufferedImage> frameImages = new Iterator<BufferedImage>() {
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<GraphTargetItem> output, ActionGraphSource code, int ip, List<MyEntry<DirectValueActionItem, ConstantPool>> variables, List<GraphSourceItem> functions, HashMap<DirectValueActionItem, ConstantPool> strings, List<Integer> visited, HashMap<DirectValueActionItem, String> 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<Integer> 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<Integer> 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;

View File

@@ -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<File> exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, BinaryDataExportSettings settings) throws IOException {
public List<File> exportBinaryData(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, BinaryDataExportSettings settings, EventListener evl) throws IOException {
List<File> 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;
}
}

View File

@@ -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<File> exportFonts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final FontExportSettings settings) throws IOException {
public List<File> exportFonts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final FontExportSettings settings, EventListener evl) throws IOException {
List<File> 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);

View File

@@ -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<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List<Integer> frames, final FramesExportSettings settings, final EventListener evl) throws IOException {
final List<File> 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<Integer> 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<Integer> 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<BufferedImage> frameImages = new Iterator<BufferedImage>() {
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<Integer> 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<Integer> 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();
}
}

View File

@@ -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<File> exportImages(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final ImageExportSettings settings) throws IOException {
public List<File> exportImages(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, ImageExportSettings settings, EventListener evl) throws IOException {
List<File> 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;
}
}

View File

@@ -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<File> exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final MorphShapeExportSettings settings) throws IOException {
public List<File> exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException {
List<File> 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++;
}
}

View File

@@ -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<File> exportMovies(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final MovieExportSettings settings, EventListener evl) throws IOException {
List<File> 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;

View File

@@ -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<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final ShapeExportSettings settings) throws IOException {
public List<File> exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List<Tag> tags, final ShapeExportSettings settings, EventListener evl) throws IOException {
List<File> 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) {

View File

@@ -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<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final SoundExportSettings settings) throws IOException {
public List<File> exportSounds(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final SoundExportSettings settings, EventListener evl) throws IOException {
List<File> 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;
}

View File

@@ -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<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final TextExportSettings settings) throws IOException {
public List<File> exportTexts(AbortRetryIgnoreHandler handler, String outdir, List<Tag> tags, final TextExportSettings settings, EventListener evl) throws IOException {
List<File> 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++;
}
}
}

View File

@@ -47,13 +47,13 @@ import java.util.logging.Logger;
*/
public class AS2ScriptExporter {
public List<File> exportAS2ScriptsTimeout(final AbortRetryIgnoreHandler handler, final String outdir, final Map<String, ASMSource> asms, final ScriptExportMode exportMode, final EventListener ev) throws IOException {
public List<File> exportAS2ScriptsTimeout(final AbortRetryIgnoreHandler handler, final String outdir, final Map<String, ASMSource> asms, final ScriptExportMode exportMode, final EventListener evl) throws IOException {
try {
List<File> result = CancellableWorker.call(new Callable<List<File>>() {
@Override
public List<File> 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<File> exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map<String, ASMSource> asms, ScriptExportMode exportMode, EventListener ev) throws IOException {
private List<File> exportAS2Scripts(AbortRetryIgnoreHandler handler, String outdir, Map<String, ASMSource> asms, ScriptExportMode exportMode, EventListener evl) throws IOException {
List<File> 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;

View File

@@ -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<Integer> 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<Integer> sounds, List<String> soundClasses) {

View File

@@ -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);
}