Added #2119 Option to export assets with names like their assigned classes via SymbolClass, without character id

This commit is contained in:
Jindra Petřík
2023-11-17 19:05:38 +01:00
parent e2b8f54981
commit 7fd930489e
15 changed files with 533 additions and 292 deletions

View File

@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.abc.types;
import com.jpexs.decompiler.flash.abc.ABC;
import com.jpexs.decompiler.flash.abc.avm2.AVM2ConstantPool;
import com.jpexs.decompiler.flash.abc.types.traits.Traits;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.helpers.GraphTextWriter;
import com.jpexs.decompiler.flash.helpers.hilight.HighlightSpecialType;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
@@ -98,12 +99,18 @@ public class InstanceInfo {
String className = getName(abc.constants).getNameWithNamespace(abc.constants, false).toRawString();
CharacterTag ct = abc.getSwf().getCharacterByClass(className);
if (ct != null) {
String fileName = ct.getCharacterExportFileName();
if (Configuration.as3ExportNamesUseClassNamesOnly.get()) {
fileName = getName(abc.constants).getNameWithNamespace(abc.constants, false).toRawString();
}
fileName = Helper.makeFileName(fileName);
if (ct instanceof DefineBinaryDataTag) {
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".bin\", mimeType=\"application/octet-stream\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + fileName + ".bin\", mimeType=\"application/octet-stream\")]").newLine();
}
if (ct instanceof ImageTag) {
ImageTag it = (ImageTag) ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ((ImageTag) ct).getImageFormat().getExtension() + "\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + fileName + ((ImageTag) ct).getImageFormat().getExtension() + "\")]").newLine();
}
if (ct instanceof DefineSpriteTag) {
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + "assets.swf\", symbol=\"" + Helper.escapeActionScriptString(className) + "\")]").newLine();
@@ -111,7 +118,7 @@ public class InstanceInfo {
if (ct instanceof DefineSoundTag) {
//should be mp3, otherwise it won't work. Should we convert this?
DefineSoundTag st = (DefineSoundTag) ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + "." + (st.getSoundFormat().formatId == SoundFormat.FORMAT_MP3 ? "mp3" : "wav") + "\")]").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + fileName + "." + (st.getSoundFormat().formatId == SoundFormat.FORMAT_MP3 ? "mp3" : "wav") + "\")]").newLine();
}
if (ct instanceof FontTag) {
FontTag ft = (FontTag) ct;
@@ -125,7 +132,7 @@ public class InstanceInfo {
}
}
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".ttf\",").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + fileName + ".ttf\",").newLine();
writer.appendNoHilight("fontName=\"" + Helper.escapeActionScriptString(ft.getFontNameIntag()) + "\",").newLine();
writer.appendNoHilight("fontFamily=\"" + Helper.escapeActionScriptString(ft.getFontName()) + "\",").newLine();
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
@@ -174,7 +181,7 @@ public class InstanceInfo {
if (ct instanceof DefineFont4Tag) {
DefineFont4Tag ft4 = (DefineFont4Tag) ct;
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + Helper.makeFileName(ct.getCharacterExportFileName()) + ".cff\",").newLine();
writer.appendNoHilight("[Embed(source=\"" + ASSETS_DIR + fileName + ".cff\",").newLine();
writer.appendNoHilight("fontName=\"" + Helper.escapeActionScriptString(ft4.fontName) + "\",").newLine();
writer.appendNoHilight("mimeType=\"application/x-font\",").newLine();
writer.appendNoHilight("fontWeight=\"" + (ft4.fontFlagsBold ? "bold" : "normal") + "\",").newLine();

View File

@@ -982,6 +982,10 @@ public final class Configuration {
@ConfigurationDefaultInt(1000)
@ConfigurationCategory("limit")
public static ConfigurationItem<Integer> boxBlurPixelsLimit = null;
@ConfigurationDefaultBoolean(false)
@ConfigurationCategory("export")
public static ConfigurationItem<Boolean> as3ExportNamesUseClassNamesOnly = null;
private enum OSId {
WINDOWS, OSX, UNIX

View File

@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings;
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
import com.jpexs.decompiler.flash.tags.Tag;
@@ -30,8 +31,11 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
*
@@ -78,8 +82,20 @@ public class BinaryDataExporter {
fos.write(bdt.binaryData.getRangeData());
}
}, handler).run();
ret.add(file);
Set<String> classNames = bdt.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;

View File

@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.Font4ExportMode;
import com.jpexs.decompiler.flash.exporters.settings.Font4ExportSettings;
import com.jpexs.decompiler.flash.tags.DefineFont4Tag;
@@ -32,8 +33,11 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -84,7 +88,19 @@ public class Font4Exporter {
exportFont(st, settings.mode, file);
}, handler).run();
ret.add(file);
Set<String> classNames = st.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;

View File

@@ -46,6 +46,8 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
@@ -100,9 +102,21 @@ public class FontExporter {
new RetryTask(() -> {
exportFont(st, settings.mode, file);
}, handler).run();
ret.add(file);
Set<String> classNames = st.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;
}

View File

@@ -166,6 +166,75 @@ public class FrameExporter {
FrameExportSettings fes = new FrameExportSettings(fem, settings.zoom);
return exportFrames(handler, outdir, swf, containerId, frames, fes, evl);
}
private class MyFrameIterator implements Iterator<BufferedImage> {
private int pos = 0;
private final Timeline tim;
private final List<Integer> fframes;
private final EventListener evl;
private final boolean usesTransparency;
private final Color backgroundColor;
private final FrameExportSettings settings;
public MyFrameIterator(
Timeline tim,
List<Integer> fframes,
final EventListener evl,
boolean usesTransparency,
Color backgroundColor,
FrameExportSettings settings
) {
this.tim = tim;
this.fframes = fframes;
this.evl = evl;
this.usesTransparency = usesTransparency;
this.backgroundColor = backgroundColor;
this.settings = settings;
}
public void reset() {
pos = 0;
}
@Override
public boolean hasNext() {
if (Thread.currentThread().isInterrupted()) {
return false;
}
return fframes.size() > pos;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public BufferedImage next() {
if (!hasNext()) {
return null;
}
Tag parentTag = tim.getParentTag();
String tagName = parentTag == null ? "" : parentTag.getName();
if (evl != null) {
evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName);
}
int fframe = fframes.get(pos++);
BufferedImage result = SWF.frameToImageGet(tim, fframe, 0, null, 0, tim.displayRect, new Matrix(), null, usesTransparency ? null : backgroundColor, settings.zoom, true).getBufferedImage();
if (Thread.currentThread().isInterrupted()) {
return null;
}
if (evl != null) {
evl.handleExportedEvent("frame", pos, fframes.size(), tagName);
}
return result;
}
}
public List<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List<Integer> frames, final FrameExportSettings settings, final EventListener evl) throws IOException, InterruptedException {
final List<File> ret = new ArrayList<>();
@@ -177,12 +246,21 @@ public class FrameExporter {
return ret;
}
Timeline tim0;
String path = "";
List<String> paths = new ArrayList<>();
if (containerId == 0) {
tim0 = swf.getTimeline();
paths.add("");
} else {
tim0 = ((Timelined) swf.getCharacter(containerId)).getTimeline();
path = File.separator + Helper.makeFileName(swf.getCharacter(containerId).getExportFileName());
Set<String> classNames = swf.getCharacter(containerId).getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
paths.add(File.separator + Helper.makeFileName(className));
}
} else {
paths.add(File.separator + Helper.makeFileName(swf.getCharacter(containerId).getExportFileName()));
}
}
final Timeline tim = tim0;
@@ -195,8 +273,14 @@ public class FrameExporter {
}
}
final File foutdir = new File(outdir + path);
Path.createDirectorySafe(foutdir);
final List<File> foutdirs = new ArrayList<>();
for (String path : paths) {
File foutdir = new File(outdir + path);
foutdirs.add(foutdir);
Path.createDirectorySafe(foutdir);
}
final List<Integer> fframes = frames;
@@ -215,25 +299,27 @@ public class FrameExporter {
final int fi = i;
final Color fbackgroundColor = null;
new RetryTask(() -> {
int frame = fframes.get(fi);
File f = new File(foutdir + File.separator + (frame + 1) + ".svg");
try (OutputStream fos = new BufferedOutputStream(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, settings.zoom, "frame");
if (fbackgroundColor != null) {
exporter.setBackGroundColor(fbackgroundColor);
}
for (File foutdir : foutdirs) {
new RetryTask(() -> {
int frame = fframes.get(fi);
File f = new File(foutdir + File.separator + (frame + 1) + ".svg");
try (OutputStream fos = new BufferedOutputStream(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, settings.zoom, "frame");
if (fbackgroundColor != null) {
exporter.setBackGroundColor(fbackgroundColor);
}
tim.toSVG(frame, 0, null, 0, exporter, null, 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
ret.add(f);
}, handler).run();
tim.toSVG(frame, 0, null, 0, exporter, null, 0);
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
ret.add(f);
}, handler).run();
}
if (Thread.currentThread().isInterrupted()) {
break;
@@ -257,104 +343,106 @@ public class FrameExporter {
final Timeline ftim = tim;
final Color fbackgroundColor = null;
final SWF fswf = swf;
new RetryTask(() -> {
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);
for (File foutdir : foutdirs) {
new RetryTask(() -> {
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 (final OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) {
fos.write(Utf8Helper.getBytes("\r\n"));
fos.write(Utf8Helper.getBytes("var scalingGrids = {};\r\nvar boundRects = {};\r\n"));
Set<Integer> library = new HashSet<>();
ftim.getNeededCharacters(fframes, library);
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 (final OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) {
fos.write(Utf8Helper.getBytes("\r\n"));
fos.write(Utf8Helper.getBytes("var scalingGrids = {};\r\nvar boundRects = {};\r\n"));
Set<Integer> library = new HashSet<>();
ftim.getNeededCharacters(fframes, library);
SWF.libraryToHtmlCanvas(fswf, library, fos);
SWF.libraryToHtmlCanvas(fswf, library, fos);
String currentName = ftim.id == 0 ? "main" : SWF.getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id;
String currentName = ftim.id == 0 ? "main" : SWF.getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id;
StringBuilder sb = new StringBuilder();
sb.append("function ").append(currentName).append("(ctx,ctrans,frame,ratio,time){\r\n");
sb.append("\tctx.save();\r\n");
sb.append("\tctx.transform(1,0,0,1,").append(-ftim.displayRect.Xmin * settings.zoom / SWF.unitDivisor).append(",").append(-ftim.displayRect.Ymin * settings.zoom / SWF.unitDivisor).append(");\r\n");
framesToHtmlCanvas(sb, SWF.unitDivisor / settings.zoom, ftim, fframes, 0, null, 0, ftim.displayRect, null, fbackgroundColor);
sb.append("\tctx.restore();\r\n");
sb.append("}\r\n\r\n");
StringBuilder sb = new StringBuilder();
sb.append("function ").append(currentName).append("(ctx,ctrans,frame,ratio,time){\r\n");
sb.append("\tctx.save();\r\n");
sb.append("\tctx.transform(1,0,0,1,").append(-ftim.displayRect.Xmin * settings.zoom / SWF.unitDivisor).append(",").append(-ftim.displayRect.Ymin * settings.zoom / SWF.unitDivisor).append(");\r\n");
framesToHtmlCanvas(sb, SWF.unitDivisor / settings.zoom, ftim, fframes, 0, null, 0, ftim.displayRect, null, fbackgroundColor);
sb.append("\tctx.restore();\r\n");
sb.append("}\r\n\r\n");
sb.append("var frame = -1;\r\n");
sb.append("var time = 0;\r\n");
sb.append("var frames = [];\r\n");
for (int i : fframes) {
sb.append("frames.push(").append(i).append(");\r\n");
}
sb.append("\r\n");
RGB backgroundColor1 = new RGB(255, 255, 255);
if (setBgColorTag != null) {
backgroundColor1 = setBgColorTag.backgroundColor;
sb.append("var frame = -1;\r\n");
sb.append("var time = 0;\r\n");
sb.append("var frames = [];\r\n");
for (int i : fframes) {
sb.append("frames.push(").append(i).append(");\r\n");
}
sb.append("\r\n");
RGB backgroundColor1 = new RGB(255, 255, 255);
if (setBgColorTag != null) {
backgroundColor1 = setBgColorTag.backgroundColor;
}
sb.append("var backgroundColor = \"").append(backgroundColor1.toHexRGB()).append("\";\r\n");
sb.append("var originalWidth = ").append(width).append(";\r\n");
sb.append("var originalHeight= ").append(height).append(";\r\n");
sb.append("function nextFrame(ctx,ctrans){\r\n");
sb.append("\tvar oldframe = frame;\r\n");
sb.append("\tframe = (frame+1)%frames.length;\r\n");
sb.append("\tif(frame==oldframe){time++;}else{time=0;};\r\n");
sb.append("\tdrawFrame();\r\n");
sb.append("}\r\n\r\n");
sb.append("function drawFrame(){\r\n");
sb.append("\tctx.fillStyle = backgroundColor;\r\n");
sb.append("\tctx.fillRect(0,0,canvas.width,canvas.height);\r\n");
sb.append("\tctx.save();\r\n");
sb.append("\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n");
sb.append("\t").append(currentName).append("(ctx,ctrans,frames[frame],0,time);\r\n");
sb.append("\tctx.restore();\r\n");
sb.append("}\r\n\r\n");
if (ftim.swf.frameRate > 0) {
sb.append("window.setInterval(function(){nextFrame(ctx,ctrans);},").append((int) (1000.0 / ftim.swf.frameRate)).append(");\r\n");
}
sb.append("nextFrame(ctx,ctrans);\r\n");
fos.write(Utf8Helper.getBytes(sb.toString()));
}
sb.append("var backgroundColor = \"").append(backgroundColor1.toHexRGB()).append("\";\r\n");
sb.append("var originalWidth = ").append(width).append(";\r\n");
sb.append("var originalHeight= ").append(height).append(";\r\n");
sb.append("function nextFrame(ctx,ctrans){\r\n");
sb.append("\tvar oldframe = frame;\r\n");
sb.append("\tframe = (frame+1)%frames.length;\r\n");
sb.append("\tif(frame==oldframe){time++;}else{time=0;};\r\n");
sb.append("\tdrawFrame();\r\n");
sb.append("}\r\n\r\n");
sb.append("function drawFrame(){\r\n");
sb.append("\tctx.fillStyle = backgroundColor;\r\n");
sb.append("\tctx.fillRect(0,0,canvas.width,canvas.height);\r\n");
sb.append("\tctx.save();\r\n");
sb.append("\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n");
sb.append("\t").append(currentName).append("(ctx,ctrans,frames[frame],0,time);\r\n");
sb.append("\tctx.restore();\r\n");
sb.append("}\r\n\r\n");
if (ftim.swf.frameRate > 0) {
sb.append("window.setInterval(function(){nextFrame(ctx,ctrans);},").append((int) (1000.0 / ftim.swf.frameRate)).append(");\r\n");
}
sb.append("nextFrame(ctx,ctrans);\r\n");
fos.write(Utf8Helper.getBytes(sb.toString()));
}
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");
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);
}
} else {
f.renameTo(fmin);
}
File fh = new File(foutdir + File.separator + "frames.html");
try (OutputStream fos = new BufferedOutputStream(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);
File fh = new File(foutdir + File.separator + "frames.html");
try (OutputStream fos = new BufferedOutputStream(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()));
}
if (packed) {
fos.write(Utf8Helper.getBytes(";"));
}
fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsSuffix()));
fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlSuffix()));
}
fmin.delete();
fmin.delete();
ret.add(f);
}, handler).run();
ret.add(f);
}, handler).run();
}
if (evl != null) {
Tag parentTag = tim.getParentTag();
@@ -366,28 +454,13 @@ public class FrameExporter {
if (settings.mode == FrameExportMode.SWF) {
Color fBackgroundColor = backgroundColor;
if (exportAll) {
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.swf");
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) {
try {
new PreviewExporter().exportSwf(fos, swf.getCharacter(containerId), fBackgroundColor, 0, false);
} catch (ActionParseException ex) {
Logger.getLogger(MorphShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
ret.add(f);
}, handler).run();
} else {
for (Integer frame : fframes) {
for (File foutdir : foutdirs) {
new RetryTask(() -> {
File f = new File(foutdir + File.separator + (frame + 1) + ".swf");
Frame fn = (Frame) tim.getFrame(frame);
File f = new File(foutdir + File.separator + "frames.swf");
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) {
try {
new PreviewExporter().exportSwf(fos, fn, fBackgroundColor, 0, false);
new PreviewExporter().exportSwf(fos, swf.getCharacter(containerId), fBackgroundColor, 0, false);
} catch (ActionParseException ex) {
Logger.getLogger(MorphShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
}
@@ -396,184 +469,175 @@ public class FrameExporter {
ret.add(f);
}, handler).run();
}
} else {
for (Integer frame : fframes) {
for (File foutdir : foutdirs) {
new RetryTask(() -> {
File f = new File(foutdir + File.separator + (frame + 1) + ".swf");
Frame fn = (Frame) tim.getFrame(frame);
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) {
try {
new PreviewExporter().exportSwf(fos, fn, fBackgroundColor, 0, false);
} catch (ActionParseException ex) {
Logger.getLogger(MorphShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
}
}
ret.add(f);
}, handler).run();
}
}
}
}
final Color fbackgroundColor = backgroundColor;
final boolean fusesTransparency = settings.mode == FrameExportMode.PNG || settings.mode == FrameExportMode.GIF;
final Iterator<BufferedImage> frameImages = new Iterator<BufferedImage>() {
private int pos = 0;
@Override
public boolean hasNext() {
if (Thread.currentThread().isInterrupted()) {
return false;
}
return fframes.size() > pos;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public BufferedImage next() {
if (!hasNext()) {
return null;
}
Tag parentTag = tim.getParentTag();
String tagName = parentTag == null ? "" : parentTag.getName();
if (evl != null) {
evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName);
}
int fframe = fframes.get(pos++);
BufferedImage result = SWF.frameToImageGet(tim, fframe, 0, null, 0, tim.displayRect, new Matrix(), null, fusesTransparency ? null : fbackgroundColor, settings.zoom, true).getBufferedImage();
if (Thread.currentThread().isInterrupted()) {
return null;
}
if (evl != null) {
evl.handleExportedEvent("frame", pos, fframes.size(), tagName);
}
return result;
}
};
final boolean usesTransparency = settings.mode == FrameExportMode.PNG || settings.mode == FrameExportMode.GIF;
final MyFrameIterator frameImages = new MyFrameIterator(tim, fframes, evl, usesTransparency, backgroundColor, settings);
switch (settings.mode) {
case GIF:
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.gif");
makeGIF(frameImages, swf.frameRate, f, evl);
ret.add(f);
}, handler).run();
break;
case BMP:
for (int i = 0; frameImages.hasNext(); i++) {
final int fi = i;
for (File foutdir : foutdirs) {
frameImages.reset();
new RetryTask(() -> {
File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".bmp");
BufferedImage img = frameImages.next();
if (img != null) {
BMPFile.saveBitmap(img, f);
}
File f = new File(foutdir + File.separator + "frames.gif");
makeGIF(frameImages, swf.frameRate, f, evl);
ret.add(f);
}, handler).run();
}
break;
case BMP:
for (File foutdir : foutdirs) {
frameImages.reset();
for (int i = 0; frameImages.hasNext(); i++) {
final int fi = i;
new RetryTask(() -> {
File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".bmp");
BufferedImage img = frameImages.next();
if (img != null) {
BMPFile.saveBitmap(img, f);
}
ret.add(f);
}, handler).run();
}
}
break;
case PNG:
for (int i = 0; frameImages.hasNext(); i++) {
final int fi = i;
new RetryTask(() -> {
File file = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png");
BufferedImage img = frameImages.next();
if (img != null) {
ImageHelper.write(img, ImageFormat.PNG, file);
ret.add(file);
}
}, handler).run();
for (File foutdir : foutdirs) {
frameImages.reset();
for (int i = 0; frameImages.hasNext(); i++) {
final int fi = i;
new RetryTask(() -> {
File file = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png");
BufferedImage img = frameImages.next();
if (img != null) {
ImageHelper.write(img, ImageFormat.PNG, file);
ret.add(file);
}
}, handler).run();
}
}
//ShapeExporterBase.clearCache();
break;
case PDF:
if (frameImages.hasNext()) {
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.pdf");
PDFJob job = new PDFJob(new BufferedOutputStream(new FileOutputStream(f)));
PageFormat pf = new PageFormat();
pf.setOrientation(PageFormat.PORTRAIT);
Paper p = new Paper();
/*BufferedImage img = frameImages.next();
p.setSize(img.getWidth() + 10, img.getHeight() + 10);*/
for (File foutdir : foutdirs) {
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.pdf");
PDFJob job = new PDFJob(new BufferedOutputStream(new FileOutputStream(f)));
PageFormat pf = new PageFormat();
pf.setOrientation(PageFormat.PORTRAIT);
Paper p = new Paper();
/*BufferedImage img = frameImages.next();
p.setSize(img.getWidth() + 10, img.getHeight() + 10);*/
int pos = 0;
RECT rect = tim.displayRect;
int pos = 0;
RECT rect = tim.displayRect;
double w = (rect.getWidth() * settings.zoom / SWF.unitDivisor);
double h = (rect.getHeight() * settings.zoom / SWF.unitDivisor);
p.setSize(w, h);
pf.setPaper(p);
double zoom = settings.zoom;
Matrix m = new Matrix();
m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom);
m.scale(zoom);
Matrix transformation = m;
Map<Integer, Font> existingFonts = new HashMap<>();
double w = (rect.getWidth() * settings.zoom / SWF.unitDivisor);
double h = (rect.getHeight() * settings.zoom / SWF.unitDivisor);
p.setSize(w, h);
pf.setPaper(p);
double zoom = settings.zoom;
Matrix m = new Matrix();
m.translate(-rect.Xmin * zoom, -rect.Ymin * zoom);
m.scale(zoom);
Matrix transformation = m;
Map<Integer, Font> existingFonts = new HashMap<>();
while (pos < fframes.size()) {
while (pos < fframes.size()) {
if (evl != null) {
Tag parentTag = tim.getParentTag();
String tagName = parentTag == null ? "" : parentTag.getName();
evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName);
}
int fframe = fframes.get(pos);
final Graphics2D g = (Graphics2D) job.getGraphics(pf);
//g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null);
if (evl != null) {
Tag parentTag = tim.getParentTag();
String tagName = parentTag == null ? "" : parentTag.getName();
evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName);
}
int fframe = fframes.get(pos);
final Graphics2D g = (Graphics2D) job.getGraphics(pf);
//g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null);
SerializableImage image = new SerializableImage((int) w + 1, (int) h + 1, SerializableImage.TYPE_INT_ARGB_PRE) {
SerializableImage image = new SerializableImage((int) w + 1, (int) h + 1, SerializableImage.TYPE_INT_ARGB_PRE) {
private Graphics2D compositeGraphics;
private Graphics2D compositeGraphics;
@Override
public Graphics getGraphics() {
if (compositeGraphics != null) {
@Override
public Graphics getGraphics() {
if (compositeGraphics != null) {
return compositeGraphics;
}
final Graphics2D parentGraphics = (Graphics2D) super.getGraphics();
compositeGraphics = new DualPdfGraphics2D(parentGraphics, (PDFGraphics) g, existingFonts);
return compositeGraphics;
}
final Graphics2D parentGraphics = (Graphics2D) super.getGraphics();
compositeGraphics = new DualPdfGraphics2D(parentGraphics, (PDFGraphics) g, existingFonts);
return compositeGraphics;
@Override
public void fillTransparent() {
}
};
//if (backGroundColor == null) {
// image.fillTransparent();
int imgWidth = (int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1;
int imgHeight = (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1;
if (!usesTransparency && fbackgroundColor != null) {
g.setComposite(AlphaComposite.Src);
g.setColor(fbackgroundColor);
g.fill(new Rectangle(imgWidth, imgHeight));
}
@Override
public void fillTransparent() {
RenderContext renderContext = new RenderContext();
renderContext.cursorPosition = new Point(-1, -1);
renderContext.mouseButton = 0;
renderContext.stateUnderCursor = new ArrayList<>();
try {
tim.toImage(fframe, fframe, renderContext, image, image, false, m, new Matrix(), m, null, zoom, true, new ExportRectangle(rect), m, true, Timeline.DRAW_MODE_ALL, 0, true);
} catch (Exception ex) {
ex.printStackTrace();
}
g.dispose();
};
//if (backGroundColor == null) {
// image.fillTransparent();
int imgWidth = (int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1;
int imgHeight = (int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1;
if (!fusesTransparency && fbackgroundColor != null) {
g.setComposite(AlphaComposite.Src);
g.setColor(fbackgroundColor);
g.fill(new Rectangle(imgWidth, imgHeight));
if (Thread.currentThread().isInterrupted()) {
return;
}
pos++;
}
RenderContext renderContext = new RenderContext();
renderContext.cursorPosition = new Point(-1, -1);
renderContext.mouseButton = 0;
renderContext.stateUnderCursor = new ArrayList<>();
try {
tim.toImage(fframe, fframe, renderContext, image, image, false, m, new Matrix(), m, null, zoom, true, new ExportRectangle(rect), m, true, Timeline.DRAW_MODE_ALL, 0, true);
} catch (Exception ex) {
ex.printStackTrace();
}
g.dispose();
if (Thread.currentThread().isInterrupted()) {
return;
}
pos++;
}
job.end();
ret.add(f);
}, handler).run();
job.end();
ret.add(f);
}, handler).run();
}
}
break;
case AVI:
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.avi");
makeAVI(frameImages, swf.frameRate, f, evl);
ret.add(f);
}, handler).run();
for (File foutdir : foutdirs) {
frameImages.reset();
new RetryTask(() -> {
File f = new File(foutdir + File.separator + "frames.avi");
makeAVI(frameImages, swf.frameRate, f, evl);
ret.add(f);
}, handler).run();
}
break;
}

View File

@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings;
import com.jpexs.decompiler.flash.helpers.BMPFile;
@@ -38,8 +39,12 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.imageio.ImageIO;
/**
@@ -118,7 +123,6 @@ public class ImageExporter {
}
}, handler).run();
final File alphaBinFile = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + ".alpha.bin"));
final File alphaPngFile = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + ".alpha.png"));
if ((imageTag instanceof HasSeparateAlphaChannel)
@@ -145,7 +149,26 @@ public class ImageExporter {
}, handler).run();
}
}
ret.add(file);
Set<String> classNames = imageTag.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + "." + ImageHelper.getImageFormatString(fileFormat)));
File classAlphaPngFile = new File(outdir + File.separator + Helper.makeFileName(className + ".alpha.png"));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
if (alphaPngFile.exists()) {
Files.copy(alphaPngFile.toPath(), classAlphaPngFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
ret.add(classFile);
}
file.delete();
if (alphaPngFile.exists()) {
alphaPngFile.delete();
}
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;

View File

@@ -22,11 +22,11 @@ import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
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.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
import com.jpexs.decompiler.flash.helpers.BMPFile;
@@ -53,6 +53,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -106,8 +108,9 @@ public class MorphShapeExporter {
final File file = new File(outdir + File.separator + characterID + settings.getFileExtension());
final File fileStart = new File(outdir + File.separator + characterID + ".start" + settings.getFileExtension());
final File fileEnd = new File(outdir + File.separator + characterID + ".end" + settings.getFileExtension());
MorphShapeTag mst = (MorphShapeTag) t;
new RetryTask(() -> {
MorphShapeTag mst = (MorphShapeTag) t;
switch (settings.mode) {
case SVG_START_END:
try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fileStart))) {
@@ -218,8 +221,42 @@ public class MorphShapeExporter {
break;
}
}, handler).run();
ret.add(file);
Set<String> classNames = mst.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + settings.getFileExtension()));
File classFileStart = new File(outdir + File.separator + Helper.makeFileName(className + ".start" + settings.getFileExtension()));
File classFileEnd = new File(outdir + File.separator + Helper.makeFileName(className + ".end" + settings.getFileExtension()));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
if (fileStart.exists()) {
new RetryTask(() -> {
Files.copy(fileStart.toPath(), classFileStart.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
}
if (fileEnd.exists()) {
new RetryTask(() -> {
Files.copy(fileEnd.toPath(), classFileEnd.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
}
}
file.delete();
if (fileStart.exists()) {
fileStart.delete();
}
if (fileEnd.exists()) {
fileEnd.delete();
}
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;
}

View File

@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings;
import com.jpexs.decompiler.flash.flv.FLVOutputStream;
@@ -40,11 +41,14 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
*
@@ -90,6 +94,20 @@ public class MovieExporter {
}
}, handler).run();
Set<String> classNames = videoStream.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ".flv"));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;
}

View File

@@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.action.parser.ActionParseException;
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;
@@ -50,6 +51,8 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@@ -161,7 +164,20 @@ public class ShapeExporter {
break;
}
}, handler).run();
ret.add(file);
Set<String> classNames = st.getClassNames();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + settings.getFileExtension()));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;

View File

@@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.EventListener;
import com.jpexs.decompiler.flash.ReadOnlyTagList;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.exporters.modes.SoundExportMode;
import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
import com.jpexs.decompiler.flash.flv.AUDIODATA;
@@ -28,6 +29,7 @@ import com.jpexs.decompiler.flash.flv.FLVTAG;
import com.jpexs.decompiler.flash.tags.DefineSoundTag;
import com.jpexs.decompiler.flash.tags.SoundStreamBlockTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.tags.gfx.DefineExternalSound;
@@ -43,9 +45,13 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
*
@@ -86,32 +92,44 @@ public class SoundExporter {
final SoundTag st = (SoundTag) t;
String ext = "wav";
String ext = ".wav";
SoundFormat fmt = st.getSoundFormat();
switch (fmt.getNativeExportFormat()) {
case MP3:
if (settings.mode.hasMP3()) {
ext = "mp3";
ext = ".mp3";
}
break;
case FLV:
if (settings.mode.hasFlv()) {
ext = "flv";
ext = ".flv";
}
break;
}
if (settings.mode == SoundExportMode.FLV) {
ext = "flv";
ext = ".flv";
}
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + "." + ext);
final File file = new File(outdir + File.separator + Helper.makeFileName(st.getCharacterExportFileName()) + ext);
new RetryTask(() -> {
try (OutputStream os = new BufferedOutputStream(new FileOutputStream(file))) {
exportSound(os, st, settings.mode);
}
}, handler).run();
ret.add(file);
Set<String> classNames = (st instanceof CharacterTag) ? ((CharacterTag)st).getClassNames() : new HashSet<>();
if (Configuration.as3ExportNamesUseClassNamesOnly.get() && !classNames.isEmpty()) {
for (String className : classNames) {
File classFile = new File(outdir + File.separator + Helper.makeFileName(className + ext));
new RetryTask(() -> {
Files.copy(file.toPath(), classFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
},handler).run();
ret.add(classFile);
}
file.delete();
} else {
ret.add(file);
}
if (Thread.currentThread().isInterrupted()) {
break;

View File

@@ -48,7 +48,7 @@ public class ShapeExportSettings {
case SWF:
return ".swf";
default:
throw new Error("Unsupported morphshape export mode: " + mode);
throw new Error("Unsupported shape export mode: " + mode);
}
}
}