diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java index c049d7f1e..22d21160d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java @@ -1,137 +1,137 @@ -/* - * 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.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.RetryTask; -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; -import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; -import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag; -import com.jpexs.decompiler.flash.tags.Tag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class MorphShapeExporter { - - //TODO: implement morphshape export. How to handle 65536 frames? - public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException { - List ret = new ArrayList<>(); - if (tags.isEmpty()) { - return ret; - } - - File foutdir = new File(outdir); - Path.createDirectorySafe(foutdir); - - int count = 0; - for (Tag t : tags) { - if (t instanceof MorphShapeTag) { - count++; - } - } - - if (count == 0) { - return ret; - } - - 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(); - } - String ext = settings.mode == MorphShapeExportMode.CANVAS ? "html" : "svg"; - - final File file = new File(outdir + File.separator + characterID + "." + ext); - new RetryTask(() -> { - MorphShapeTag mst = (MorphShapeTag) t; - switch (settings.mode) { - case SVG: - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { - ExportRectangle rect = new ExportRectangle(mst.getRect()); - rect.xMax *= settings.zoom; - rect.yMax *= settings.zoom; - rect.xMin *= settings.zoom; - rect.yMin *= settings.zoom; - SVGExporter exporter = new SVGExporter(rect); - mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, settings.zoom); - fos.write(Utf8Helper.getBytes(exporter.getSVG())); - } - break; - case CANVAS: - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { - int deltaX = -Math.min(mst.getStartBounds().Xmin, mst.getEndBounds().Xmin); - int deltaY = -Math.min(mst.getStartBounds().Ymin, mst.getEndBounds().Ymin); - CanvasMorphShapeExporter cse = new CanvasMorphShapeExporter(((Tag) mst).getSwf(), mst.getShapeAtRatio(0), mst.getShapeAtRatio(DefineMorphShapeTag.MAX_RATIO), new CXFORMWITHALPHA(), SWF.unitDivisor, deltaX, deltaY); - cse.export(); - Set needed = new HashSet<>(); - CharacterTag ct = ((CharacterTag) mst); - needed.add(ct.getCharacterId()); - ct.getNeededCharactersDeep(needed); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWF.writeLibrary(ct.getSwf(), needed, baos); - fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), "UTF-8")))); - } - break; - } - }, handler).run(); - ret.add(file); - - if (evl != null) { - evl.handleExportedEvent("morphshape", currentIndex, count, t.getName()); - } - - currentIndex++; - } - } - - if (settings.mode == MorphShapeExportMode.CANVAS) { - 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); - } - return ret; - } -} +/* + * 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.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode; +import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings; +import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag; +import com.jpexs.decompiler.flash.tags.Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class MorphShapeExporter { + + //TODO: implement morphshape export. How to handle 65536 frames? + public List exportMorphShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final MorphShapeExportSettings settings, EventListener evl) throws IOException { + List ret = new ArrayList<>(); + if (tags.isEmpty()) { + return ret; + } + + File foutdir = new File(outdir); + Path.createDirectorySafe(foutdir); + + int count = 0; + for (Tag t : tags) { + if (t instanceof MorphShapeTag) { + count++; + } + } + + if (count == 0) { + return ret; + } + + 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(); + } + String ext = settings.mode == MorphShapeExportMode.CANVAS ? "html" : "svg"; + + final File file = new File(outdir + File.separator + characterID + "." + ext); + new RetryTask(() -> { + MorphShapeTag mst = (MorphShapeTag) t; + switch (settings.mode) { + case SVG: + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + ExportRectangle rect = new ExportRectangle(mst.getRect()); + rect.xMax *= settings.zoom; + rect.yMax *= settings.zoom; + rect.xMin *= settings.zoom; + rect.yMin *= settings.zoom; + SVGExporter exporter = new SVGExporter(rect); + mst.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, settings.zoom); + fos.write(Utf8Helper.getBytes(exporter.getSVG())); + } + break; + case CANVAS: + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + int deltaX = -Math.min(mst.getStartBounds().Xmin, mst.getEndBounds().Xmin); + int deltaY = -Math.min(mst.getStartBounds().Ymin, mst.getEndBounds().Ymin); + CanvasMorphShapeExporter cse = new CanvasMorphShapeExporter(((Tag) mst).getSwf(), mst.getShapeAtRatio(0), mst.getShapeAtRatio(DefineMorphShapeTag.MAX_RATIO), new CXFORMWITHALPHA(), SWF.unitDivisor, deltaX, deltaY); + cse.export(); + Set needed = new HashSet<>(); + CharacterTag ct = ((CharacterTag) mst); + needed.add(ct.getCharacterId()); + ct.getNeededCharactersDeep(needed); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWF.writeLibrary(ct.getSwf(), needed, baos); + fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), "UTF-8"), SWF.getTypePrefix(mst) + mst.getCharacterId(), mst.getRect()))); + } + break; + } + }, handler).run(); + ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("morphshape", currentIndex, count, t.getName()); + } + + currentIndex++; + } + } + + if (settings.mode == MorphShapeExportMode.CANVAS) { + 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); + } + return ret; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 353b17260..58ac832b0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -1,167 +1,167 @@ -/* - * 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.jpexs.decompiler.flash.AbortRetryIgnoreHandler; -import com.jpexs.decompiler.flash.EventListener; -import com.jpexs.decompiler.flash.RetryTask; -import com.jpexs.decompiler.flash.SWF; -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.ShapeExportMode; -import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; -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.Tag; -import com.jpexs.decompiler.flash.tags.base.CharacterTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.tags.base.ShapeTag; -import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.helpers.Helper; -import com.jpexs.helpers.Path; -import com.jpexs.helpers.SerializableImage; -import com.jpexs.helpers.utf8.Utf8Helper; -import java.io.BufferedOutputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * - * @author JPEXS - */ -public class ShapeExporter { - - public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final ShapeExportSettings settings, EventListener evl) throws IOException { - List ret = new ArrayList<>(); - if (tags.isEmpty()) { - return ret; - } - - File foutdir = new File(outdir); - Path.createDirectorySafe(foutdir); - - int count = 0; - for (Tag t : tags) { - if (t instanceof ShapeTag) { - count++; - } - } - - if (count == 0) { - return ret; - } - - 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(); - } - String ext = "svg"; - if (settings.mode == ShapeExportMode.PNG) { - ext = "png"; - } - if (settings.mode == ShapeExportMode.BMP) { - ext = "bmp"; - } - if (settings.mode == ShapeExportMode.CANVAS) { - ext = "html"; - } - - final File file = new File(outdir + File.separator + characterID + "." + ext); - new RetryTask(() -> { - ShapeTag st = (ShapeTag) t; - switch (settings.mode) { - case SVG: - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { - ExportRectangle rect = new ExportRectangle(st.getRect()); - rect.xMax *= settings.zoom; - rect.yMax *= settings.zoom; - rect.xMin *= settings.zoom; - rect.yMin *= settings.zoom; - SVGExporter exporter = new SVGExporter(rect); - st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, settings.zoom); - fos.write(Utf8Helper.getBytes(exporter.getSVG())); - } - break; - case PNG: - case BMP: - RECT rect = st.getRect(); - int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1; - int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1; - SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); - img.fillTransparent(); - Matrix m = new Matrix(); - m.translate(-rect.Xmin, -rect.Ymin); - m.scale(settings.zoom); - st.toImage(0, 0, 0, new RenderContext(), img, m, new CXFORMWITHALPHA()); - if (settings.mode == ShapeExportMode.PNG) { - ImageHelper.write(img.getBufferedImage(), "PNG", file); - } else { - BMPFile.saveBitmap(img.getBufferedImage(), file); - } - break; - case CANVAS: - try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { - SHAPE shp = st.getShapes(); - int deltaX = -shp.getBounds().Xmin; - int deltaY = -shp.getBounds().Ymin; - CanvasShapeExporter cse = new CanvasShapeExporter(null, SWF.unitDivisor / settings.zoom, ((Tag) st).getSwf(), shp, new CXFORMWITHALPHA(), deltaX, deltaY); - cse.export(); - Set needed = new HashSet<>(); - needed.add(st.getCharacterId()); - st.getNeededCharactersDeep(needed); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SWF.writeLibrary(st.getSwf(), needed, baos); - fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), "UTF-8")))); - } - break; - } - }, handler).run(); - ret.add(file); - - if (evl != null) { - evl.handleExportedEvent("shape", currentIndex, count, t.getName()); - } - - currentIndex++; - } - } - if (settings.mode == ShapeExportMode.CANVAS) { - 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); - } - return ret; - } -} +/* + * 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.jpexs.decompiler.flash.AbortRetryIgnoreHandler; +import com.jpexs.decompiler.flash.EventListener; +import com.jpexs.decompiler.flash.RetryTask; +import com.jpexs.decompiler.flash.SWF; +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.ShapeExportMode; +import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; +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.Tag; +import com.jpexs.decompiler.flash.tags.base.CharacterTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.tags.base.ShapeTag; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.Path; +import com.jpexs.helpers.SerializableImage; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * + * @author JPEXS + */ +public class ShapeExporter { + + public List exportShapes(AbortRetryIgnoreHandler handler, final String outdir, List tags, final ShapeExportSettings settings, EventListener evl) throws IOException { + List ret = new ArrayList<>(); + if (tags.isEmpty()) { + return ret; + } + + File foutdir = new File(outdir); + Path.createDirectorySafe(foutdir); + + int count = 0; + for (Tag t : tags) { + if (t instanceof ShapeTag) { + count++; + } + } + + if (count == 0) { + return ret; + } + + 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(); + } + String ext = "svg"; + if (settings.mode == ShapeExportMode.PNG) { + ext = "png"; + } + if (settings.mode == ShapeExportMode.BMP) { + ext = "bmp"; + } + if (settings.mode == ShapeExportMode.CANVAS) { + ext = "html"; + } + + final File file = new File(outdir + File.separator + characterID + "." + ext); + new RetryTask(() -> { + ShapeTag st = (ShapeTag) t; + switch (settings.mode) { + case SVG: + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + ExportRectangle rect = new ExportRectangle(st.getRect()); + rect.xMax *= settings.zoom; + rect.yMax *= settings.zoom; + rect.xMin *= settings.zoom; + rect.yMin *= settings.zoom; + SVGExporter exporter = new SVGExporter(rect); + st.toSVG(exporter, -2, new CXFORMWITHALPHA(), 0, settings.zoom); + fos.write(Utf8Helper.getBytes(exporter.getSVG())); + } + break; + case PNG: + case BMP: + RECT rect = st.getRect(); + int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1; + int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1; + SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB); + img.fillTransparent(); + Matrix m = new Matrix(); + m.translate(-rect.Xmin, -rect.Ymin); + m.scale(settings.zoom); + st.toImage(0, 0, 0, new RenderContext(), img, m, new CXFORMWITHALPHA()); + if (settings.mode == ShapeExportMode.PNG) { + ImageHelper.write(img.getBufferedImage(), "PNG", file); + } else { + BMPFile.saveBitmap(img.getBufferedImage(), file); + } + break; + case CANVAS: + try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(file))) { + SHAPE shp = st.getShapes(); + int deltaX = -shp.getBounds().Xmin; + int deltaY = -shp.getBounds().Ymin; + CanvasShapeExporter cse = new CanvasShapeExporter(null, SWF.unitDivisor / settings.zoom, ((Tag) st).getSwf(), shp, new CXFORMWITHALPHA(), deltaX, deltaY); + cse.export(); + Set needed = new HashSet<>(); + needed.add(st.getCharacterId()); + st.getNeededCharactersDeep(needed); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + SWF.writeLibrary(st.getSwf(), needed, baos); + fos.write(Utf8Helper.getBytes(cse.getHtml(new String(baos.toByteArray(), "UTF-8"), SWF.getTypePrefix(st) + st.getCharacterId(), st.getRect()))); + } + break; + } + }, handler).run(); + ret.add(file); + + if (evl != null) { + evl.handleExportedEvent("shape", currentIndex, count, t.getName()); + } + + currentIndex++; + } + } + if (settings.mode == ShapeExportMode.CANVAS) { + 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); + } + return ret; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java index c46d0c2af..8b1a48105 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java @@ -28,6 +28,7 @@ import com.jpexs.decompiler.flash.types.FILLSTYLE; import com.jpexs.decompiler.flash.types.GRADIENT; import com.jpexs.decompiler.flash.types.GRADRECORD; import com.jpexs.decompiler.flash.types.LINESTYLE2; +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.SHAPE; @@ -94,16 +95,23 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { this.swf = swf; } - public String getHtml(String needed) { - int width = (int) (Math.max(shape.getBounds().getWidth(), shapeEnd.getBounds().getWidth()) / unitDivisor); - int height = (int) (Math.max(shape.getBounds().getHeight(), shapeEnd.getBounds().getHeight()) / unitDivisor); - - return CanvasShapeExporter.getHtmlPrefix(width, height) + getJsPrefix() + needed + CanvasShapeExporter.getDrawJs(width, height, shapeData.toString()) + getJsSuffix(width, height) + CanvasShapeExporter.getHtmlSuffix(); + private String getDrawJs(int width, int height, String id, RECT rect) { + return "var originalWidth=" + width + ";\r\nvar originalHeight=" + height + ";\r\n function drawFrame(ctx,ratio){\r\n" + + "\tctx.save();\r\n\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n" + + "\tplace(\"" + id + "\",canvas,ctx,[" + (1 / unitDivisor) + ",0.0,0.0," + (1 / unitDivisor) + "," + + (-rect.Xmin / unitDivisor) + "," + (-rect.Ymin / unitDivisor) + "],ctrans,1,0,ratio,0);\r\n" + + "\tctx.restore();\r\n}\r\n"; } - public static String getJsSuffix(int width, int height) { + public String getHtml(String needed, String id, RECT rect) { + int width = (int) (rect.getWidth() / unitDivisor); + int height = (int) (rect.getHeight() / unitDivisor); + + return CanvasShapeExporter.getHtmlPrefix(width, height) + getJsPrefix() + needed + getDrawJs(width, height, id, rect) + getJsSuffix(width, height) + CanvasShapeExporter.getHtmlSuffix(); + } + + private static String getJsSuffix(int width, int height) { StringBuilder ret = new StringBuilder(); - ret.append("}\r\n"); int step = Math.round(65535 / 100); int rate = 10; ret.append("var step = ").append(step).append(";\r\n"); @@ -111,16 +119,15 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { ret.append("function nextFrame(ctx){\r\n"); ret.append("\tctx.clearRect(0,0,").append(width).append(",").append(height).append(");\r\n"); ret.append("\tratio = (ratio+step)%65535;\r\n"); - ret.append("\tmorphshape(ctx,ratio);\r\n"); + ret.append("\tdrawFrame(ctx,ratio);\r\n"); ret.append("}\r\n"); ret.append("window.setInterval(function(){nextFrame(ctx)},").append(rate).append(");\r\n"); ret.append(CanvasShapeExporter.getJsSuffix()); return ret.toString(); } - public static String getJsPrefix() { + private static String getJsPrefix() { String ret = CanvasShapeExporter.getJsPrefix(); - ret += "function morphshape(ctx,ratio){\r\n"; return ret; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java index ffb8b9af7..86254c8d7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java @@ -130,17 +130,19 @@ public class CanvasShapeExporter extends ShapeExporterBase { + ""; } - public static String getDrawJs(int width, int height, String data) { + private String getDrawJs(int width, int height, String id, RECT rect) { return "var originalWidth=" + width + ";\r\nvar originalHeight=" + height + ";\r\n function drawFrame(){\r\n" - + "\tctx.save();\r\n\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n" + data + "\tctx.restore();\r\n}\r\n\tdrawFrame();\r\n"; + + "\tctx.save();\r\n\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n" + + "\tplace(\"" + id + "\",canvas,ctx,[" + (1 / unitDivisor) + ",0.0,0.0," + (1 / unitDivisor) + "," + + (-rect.Xmin / unitDivisor) + "," + (-rect.Ymin / unitDivisor) + "],ctrans,1,0,0,0);\r\n" + + "\tctx.restore();\r\n}\r\n\tdrawFrame();\r\n"; } - public String getHtml(String needed) { - RECT r = shape.getBounds(); - int width = (int) (r.getWidth() / unitDivisor); - int height = (int) (r.getHeight() / unitDivisor); + public String getHtml(String needed, String id, RECT rect) { + int width = (int) (rect.getWidth() / unitDivisor); + int height = (int) (rect.getHeight() / unitDivisor); - return getHtmlPrefix(width, height) + getJsPrefix() + needed + getDrawJs(width, height, shapeData.toString()) + getJsSuffix() + getHtmlSuffix(); + return getHtmlPrefix(width, height) + getJsPrefix() + needed + getDrawJs(width, height, id, rect) + getJsSuffix() + getHtmlSuffix(); } public String getShapeData() { @@ -208,7 +210,7 @@ public class CanvasShapeExporter extends ShapeExporterBase { start.y += deltaY; end.x += deltaX; end.y += deltaY; - fillData.append("\tvar grd=ctx.createLinearGradient(").append(Double.toString(start.x / unitDivisor)).append(",").append(Double.toString(start.y / unitDivisor)).append(",").append(Double.toString(end.x / unitDivisor)).append(",").append(Double.toString(end.y / unitDivisor)).append(");\r\n"); + fillData.append("\tvar grd=ctx.createLinearGradient(").append(start.x / unitDivisor).append(",").append(start.y / unitDivisor).append(",").append(end.x / unitDivisor).append(",").append(end.y / unitDivisor).append(");\r\n"); } else { fillMatrix = matrix; fillData.append("\tvar grd=ctx.createRadialGradient(").append(focalPointRatio * 16384).append(",0,0,0,0,").append(16384 + 32768 * repeatCnt).append(");\r\n"); @@ -225,7 +227,7 @@ public class CanvasShapeExporter extends ShapeExporterBase { revert = !revert; } for (GRADRECORD r : gradientRecords) { - fillData.append("\tgrd.addColorStop(").append(Double.toString(pos + (oneHeight * (revert ? 255 - r.ratio : r.ratio) / 255.0))).append(",").append(color(r.color)).append(");\r\n"); + fillData.append("\tgrd.addColorStop(").append(pos + (oneHeight * (revert ? 255 - r.ratio : r.ratio) / 255.0)).append(",").append(color(r.color)).append(");\r\n"); lastRadColor = color(r.color); } pos += oneHeight; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java index 2cea3209d..f25b8b471 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java @@ -1,432 +1,431 @@ -/* - * 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.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE; -import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2; -import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.Reserved; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Shape; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * - * - * @author JPEXS - */ -public class DefineMorphShape2Tag extends MorphShapeTag { - - @SWFType(BasicType.UI16) - public int characterId; - - public RECT startBounds; - - public RECT endBounds; - - public RECT startEdgeBounds; - - public RECT endEdgeBounds; - - @Reserved - @SWFType(value = BasicType.UB, count = 6) - public int reserved; - - public boolean usesNonScalingStrokes; - - public boolean usesScalingStrokes; - - public MORPHFILLSTYLEARRAY morphFillStyles; - - public MORPHLINESTYLEARRAY morphLineStyles; - - public SHAPE startEdges; - - public SHAPE endEdges; - - public static final int ID = 84; - - public static final int MAX_RATIO = 65535; - - @Override - public void getNeededCharacters(Set needed) { - morphFillStyles.getNeededCharacters(needed); - startEdges.getNeededCharacters(needed); - endEdges.getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); - modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); - modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - modified |= morphFillStyles.removeCharacter(characterId); - modified |= startEdges.removeCharacter(characterId); - modified |= endEdges.removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public RECT getRect(Set added) { - RECT rect = new RECT(); - rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); - rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); - rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); - rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); - return rect; - } - - @Override - public int getCharacterId() { - return characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeRECT(startBounds); - sos.writeRECT(endBounds); - sos.writeRECT(startEdgeBounds); - sos.writeRECT(endEdgeBounds); - sos.writeUB(6, reserved); - sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); - sos.writeUB(1, usesScalingStrokes ? 1 : 0); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 2); - sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 2); - sos2.writeSHAPE(startEdges, 2); - byte[] ba2 = baos2.toByteArray(); - sos.writeUI32(ba2.length); - sos.write(ba2); - sos.writeSHAPE(endEdges, 2); - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineMorphShape2Tag(SWF swf) { - super(swf, ID, "DefineMorphShape2", null); - characterId = swf.getNextCharacterId(); - startBounds = new RECT(); - endBounds = new RECT(); - startEdgeBounds = new RECT(); - endEdgeBounds = new RECT(); - startEdges = SHAPE.createEmpty(2); - endEdges = SHAPE.createEmpty(2); - morphFillStyles = new MORPHFILLSTYLEARRAY(); - morphFillStyles.fillStyles = new MORPHFILLSTYLE[0]; - morphLineStyles = new MORPHLINESTYLEARRAY(); - morphLineStyles.lineStyles2 = new MORPHLINESTYLE2[0]; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineMorphShape2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineMorphShape2", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - startBounds = sis.readRECT("startBounds"); - endBounds = sis.readRECT("endBounds"); - startEdgeBounds = sis.readRECT("startEdgeBounds"); - endEdgeBounds = sis.readRECT("endEdgeBounds"); - reserved = (int) sis.readUB(6, "reserved"); - usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; - usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; - long offset = sis.readUI32("offset"); - morphFillStyles = sis.readMORPHFILLSTYLEARRAY("morphFillStyles"); - morphLineStyles = sis.readMORPHLINESTYLEARRAY(2, "morphLineStyles"); - startEdges = sis.readSHAPE(2, true, "startEdges"); - endEdges = sis.readSHAPE(2, true, "endEdges"); - } - - @Override - public RECT getStartBounds() { - return startBounds; - } - - @Override - public RECT getEndBounds() { - return endBounds; - } - - @Override - public MORPHFILLSTYLEARRAY getFillStyles() { - return morphFillStyles; - } - - @Override - public MORPHLINESTYLEARRAY getLineStyles() { - return morphLineStyles; - } - - @Override - public SHAPE getStartEdges() { - return startEdges; - } - - @Override - public SHAPE getEndEdges() { - return endEdges; - } - - @Override - public int getShapeNum() { - return 2; - } - - @Override - public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { - List finalRecords = new ArrayList<>(); - FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); - LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); - - int startPosX = 0, startPosY = 0; - int endPosX = 0, endPosY = 0; - int posX = 0, posY = 0; - - for (int startIndex = 0, endIndex = 0; - startIndex < startEdges.shapeRecords.size() - && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { - - SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); - SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); - if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { - StyleChangeRecord scr1; - if (edge1 instanceof StyleChangeRecord) { - scr1 = (StyleChangeRecord) edge1; - if (scr1.stateMoveTo) { - startPosX = scr1.moveDeltaX; - startPosY = scr1.moveDeltaY; - } - } else { - scr1 = new StyleChangeRecord(); - startIndex--; - } - StyleChangeRecord scr2; - if (edge2 instanceof StyleChangeRecord) { - scr2 = (StyleChangeRecord) edge2; - if (scr2.stateMoveTo) { - endPosX = scr2.moveDeltaX; - endPosY = scr2.moveDeltaY; - } - } else { - scr2 = new StyleChangeRecord(); - endIndex--; - } - StyleChangeRecord scr = scr1.clone(); - if (scr1.stateMoveTo || scr2.stateMoveTo) { - scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / 65535; - scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / 65535; - scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; - } - finalRecords.add(scr); - continue; - } - - if (edge1 instanceof EndShapeRecord) { - finalRecords.add(edge1); - break; - } - if (edge2 instanceof EndShapeRecord) { - finalRecords.add(edge2); - break; - } - - if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer1 = null; - if (edge1 instanceof CurvedEdgeRecord) { - cer1 = (CurvedEdgeRecord) edge1; - } else if (edge1 instanceof StraightEdgeRecord) { - cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); - } - CurvedEdgeRecord cer2 = null; - if (edge2 instanceof CurvedEdgeRecord) { - cer2 = (CurvedEdgeRecord) edge2; - } else if (edge2 instanceof StraightEdgeRecord) { - cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); - } - if ((cer2 == null) || (cer1 == null)) { - continue; - } - CurvedEdgeRecord cer = new CurvedEdgeRecord(); - cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / 65535; - cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / 65535; - cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / 65535; - cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / 65535; - startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; - startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; - endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; - endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; - posX += cer.controlDeltaX + cer.anchorDeltaX; - posY += cer.controlDeltaY + cer.anchorDeltaY; - finalRecords.add(cer); - } else { - StraightEdgeRecord ser1 = null; - if (edge1 instanceof StraightEdgeRecord) { - ser1 = (StraightEdgeRecord) edge1; - } - StraightEdgeRecord ser2 = null; - if (edge2 instanceof StraightEdgeRecord) { - ser2 = (StraightEdgeRecord) edge2; - } - if ((ser2 == null) || (ser1 == null)) { - continue; - } - StraightEdgeRecord ser = new StraightEdgeRecord(); - ser.generalLineFlag = true; - ser.vertLineFlag = false; - ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / 65535; - ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / 65535; - startPosX += ser1.deltaX; - startPosY += ser1.deltaY; - endPosX += ser2.deltaX; - endPosY += ser2.deltaY; - posX += ser.deltaX; - posY += ser.deltaX; - finalRecords.add(ser); - } - } - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = fillStyles; - shape.lineStyles = lineStyles; - shape.shapeRecords = finalRecords; - return shape; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); - // shapeNum: 4 - // todo: Currently the generated image is not cached, because the cache - // key contains the hashCode of the finalRecord object, and it is always - // recreated - BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - if (ratio == -2) { - SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); - SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); - SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } else { - SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } - } - - @Override - public int getNumFrames() { - return 65536; - } - - @Override - public boolean isSingleFrame() { - // Morpshape is a single frame specified with the ratio - return true; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); - cmse.export(); - - return cmse.getShapeData(); - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } -} +/* + * 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.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLE2; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.Reserved; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Shape; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * + * + * @author JPEXS + */ +public class DefineMorphShape2Tag extends MorphShapeTag { + + @SWFType(BasicType.UI16) + public int characterId; + + public RECT startBounds; + + public RECT endBounds; + + public RECT startEdgeBounds; + + public RECT endEdgeBounds; + + @Reserved + @SWFType(value = BasicType.UB, count = 6) + public int reserved; + + public boolean usesNonScalingStrokes; + + public boolean usesScalingStrokes; + + public MORPHFILLSTYLEARRAY morphFillStyles; + + public MORPHLINESTYLEARRAY morphLineStyles; + + public SHAPE startEdges; + + public SHAPE endEdges; + + public static final int ID = 84; + + public static final int MAX_RATIO = 65535; + + @Override + public void getNeededCharacters(Set needed) { + morphFillStyles.getNeededCharacters(needed); + startEdges.getNeededCharacters(needed); + endEdges.getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); + modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + modified |= morphFillStyles.removeCharacter(characterId); + modified |= startEdges.removeCharacter(characterId); + modified |= endEdges.removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public RECT getRect(Set added) { + RECT rect = new RECT(); + rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); + rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); + rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); + rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); + return rect; + } + + @Override + public int getCharacterId() { + return characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeRECT(startBounds); + sos.writeRECT(endBounds); + sos.writeRECT(startEdgeBounds); + sos.writeRECT(endEdgeBounds); + sos.writeUB(6, reserved); + sos.writeUB(1, usesNonScalingStrokes ? 1 : 0); + sos.writeUB(1, usesScalingStrokes ? 1 : 0); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 2); + sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 2); + sos2.writeSHAPE(startEdges, 2); + byte[] ba2 = baos2.toByteArray(); + sos.writeUI32(ba2.length); + sos.write(ba2); + sos.writeSHAPE(endEdges, 2); + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineMorphShape2Tag(SWF swf) { + super(swf, ID, "DefineMorphShape2", null); + characterId = swf.getNextCharacterId(); + startBounds = new RECT(); + endBounds = new RECT(); + startEdgeBounds = new RECT(); + endEdgeBounds = new RECT(); + startEdges = SHAPE.createEmpty(2); + endEdges = SHAPE.createEmpty(2); + morphFillStyles = new MORPHFILLSTYLEARRAY(); + morphFillStyles.fillStyles = new MORPHFILLSTYLE[0]; + morphLineStyles = new MORPHLINESTYLEARRAY(); + morphLineStyles.lineStyles2 = new MORPHLINESTYLE2[0]; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineMorphShape2Tag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, "DefineMorphShape2", data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + startBounds = sis.readRECT("startBounds"); + endBounds = sis.readRECT("endBounds"); + startEdgeBounds = sis.readRECT("startEdgeBounds"); + endEdgeBounds = sis.readRECT("endEdgeBounds"); + reserved = (int) sis.readUB(6, "reserved"); + usesNonScalingStrokes = sis.readUB(1, "usesNonScalingStrokes") == 1; + usesScalingStrokes = sis.readUB(1, "usesScalingStrokes") == 1; + long offset = sis.readUI32("offset"); + morphFillStyles = sis.readMORPHFILLSTYLEARRAY("morphFillStyles"); + morphLineStyles = sis.readMORPHLINESTYLEARRAY(2, "morphLineStyles"); + startEdges = sis.readSHAPE(2, true, "startEdges"); + endEdges = sis.readSHAPE(2, true, "endEdges"); + } + + @Override + public RECT getStartBounds() { + return startBounds; + } + + @Override + public RECT getEndBounds() { + return endBounds; + } + + @Override + public MORPHFILLSTYLEARRAY getFillStyles() { + return morphFillStyles; + } + + @Override + public MORPHLINESTYLEARRAY getLineStyles() { + return morphLineStyles; + } + + @Override + public SHAPE getStartEdges() { + return startEdges; + } + + @Override + public SHAPE getEndEdges() { + return endEdges; + } + + @Override + public int getShapeNum() { + return 2; + } + + @Override + public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { + List finalRecords = new ArrayList<>(); + FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); + LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); + + int startPosX = 0, startPosY = 0; + int endPosX = 0, endPosY = 0; + int posX = 0, posY = 0; + + for (int startIndex = 0, endIndex = 0; + startIndex < startEdges.shapeRecords.size() + && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { + + SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); + SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); + if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { + StyleChangeRecord scr1; + if (edge1 instanceof StyleChangeRecord) { + scr1 = (StyleChangeRecord) edge1; + if (scr1.stateMoveTo) { + startPosX = scr1.moveDeltaX; + startPosY = scr1.moveDeltaY; + } + } else { + scr1 = new StyleChangeRecord(); + startIndex--; + } + StyleChangeRecord scr2; + if (edge2 instanceof StyleChangeRecord) { + scr2 = (StyleChangeRecord) edge2; + if (scr2.stateMoveTo) { + endPosX = scr2.moveDeltaX; + endPosY = scr2.moveDeltaY; + } + } else { + scr2 = new StyleChangeRecord(); + endIndex--; + } + StyleChangeRecord scr = scr1.clone(); + if (scr1.stateMoveTo || scr2.stateMoveTo) { + scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / 65535; + scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / 65535; + scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; + } + finalRecords.add(scr); + continue; + } + + if (edge1 instanceof EndShapeRecord) { + finalRecords.add(edge1); + break; + } + if (edge2 instanceof EndShapeRecord) { + finalRecords.add(edge2); + break; + } + + if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer1 = null; + if (edge1 instanceof CurvedEdgeRecord) { + cer1 = (CurvedEdgeRecord) edge1; + } else if (edge1 instanceof StraightEdgeRecord) { + cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); + } + CurvedEdgeRecord cer2 = null; + if (edge2 instanceof CurvedEdgeRecord) { + cer2 = (CurvedEdgeRecord) edge2; + } else if (edge2 instanceof StraightEdgeRecord) { + cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); + } + if ((cer2 == null) || (cer1 == null)) { + continue; + } + CurvedEdgeRecord cer = new CurvedEdgeRecord(); + cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / 65535; + cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / 65535; + cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / 65535; + cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / 65535; + startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; + startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; + endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; + endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; + posX += cer.controlDeltaX + cer.anchorDeltaX; + posY += cer.controlDeltaY + cer.anchorDeltaY; + finalRecords.add(cer); + } else { + StraightEdgeRecord ser1 = null; + if (edge1 instanceof StraightEdgeRecord) { + ser1 = (StraightEdgeRecord) edge1; + } + StraightEdgeRecord ser2 = null; + if (edge2 instanceof StraightEdgeRecord) { + ser2 = (StraightEdgeRecord) edge2; + } + if ((ser2 == null) || (ser1 == null)) { + continue; + } + StraightEdgeRecord ser = new StraightEdgeRecord(); + ser.generalLineFlag = true; + ser.vertLineFlag = false; + ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / 65535; + ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / 65535; + startPosX += ser1.deltaX; + startPosY += ser1.deltaY; + endPosX += ser2.deltaX; + endPosY += ser2.deltaY; + posX += ser.deltaX; + posY += ser.deltaX; + finalRecords.add(ser); + } + } + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = fillStyles; + shape.lineStyles = lineStyles; + shape.shapeRecords = finalRecords; + return shape; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); + // shapeNum: 4 + // todo: Currently the generated image is not cached, because the cache + // key contains the hashCode of the finalRecord object, and it is always + // recreated + BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + if (ratio == -2) { + SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); + SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); + SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); + shapeExporter.export(); + } else { + SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); + shapeExporter.export(); + } + } + + @Override + public int getNumFrames() { + return 65536; + } + + @Override + public boolean isSingleFrame() { + // Morpshape is a single frame specified with the ratio + return true; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); + cmse.export(); + return cmse.getShapeData(); + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java index 40b0fb694..ad00592ba 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java @@ -1,408 +1,407 @@ -/* - * 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.tags; - -import com.jpexs.decompiler.flash.SWF; -import com.jpexs.decompiler.flash.SWFInputStream; -import com.jpexs.decompiler.flash.SWFOutputStream; -import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; -import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; -import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; -import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; -import com.jpexs.decompiler.flash.tags.base.BoundedTag; -import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; -import com.jpexs.decompiler.flash.tags.base.RenderContext; -import com.jpexs.decompiler.flash.types.BasicType; -import com.jpexs.decompiler.flash.types.ColorTransform; -import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE; -import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; -import com.jpexs.decompiler.flash.types.MORPHLINESTYLE; -import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; -import com.jpexs.decompiler.flash.types.RECT; -import com.jpexs.decompiler.flash.types.SHAPE; -import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; -import com.jpexs.decompiler.flash.types.annotations.SWFType; -import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; -import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; -import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; -import com.jpexs.helpers.ByteArrayRange; -import com.jpexs.helpers.SerializableImage; -import java.awt.Shape; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -/** - * - * - * @author JPEXS - */ -public class DefineMorphShapeTag extends MorphShapeTag { - - @SWFType(BasicType.UI16) - public int characterId; - - public RECT startBounds; - - public RECT endBounds; - - public MORPHFILLSTYLEARRAY morphFillStyles; - - public MORPHLINESTYLEARRAY morphLineStyles; - - public SHAPE startEdges; - - public SHAPE endEdges; - - public static final int ID = 46; - - public static final int MAX_RATIO = 65535; - - @Override - public void getNeededCharacters(Set needed) { - morphFillStyles.getNeededCharacters(needed); - startEdges.getNeededCharacters(needed); - endEdges.getNeededCharacters(needed); - } - - @Override - public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { - boolean modified = false; - modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); - modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); - modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public boolean removeCharacter(int characterId) { - boolean modified = false; - modified |= morphFillStyles.removeCharacter(characterId); - modified |= startEdges.removeCharacter(characterId); - modified |= endEdges.removeCharacter(characterId); - if (modified) { - setModified(true); - } - return modified; - } - - @Override - public int getCharacterId() { - return characterId; - } - - /** - * Gets data bytes - * - * @return Bytes of data - */ - @Override - public byte[] getData() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - OutputStream os = baos; - SWFOutputStream sos = new SWFOutputStream(os, getVersion()); - try { - sos.writeUI16(characterId); - sos.writeRECT(startBounds); - sos.writeRECT(endBounds); - ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); - SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); - sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 1); - sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 1); - sos2.writeSHAPE(startEdges, 1); - byte[] d = baos2.toByteArray(); - sos.writeUI32(d.length); - sos.write(d); - sos.writeSHAPE(endEdges, 1); - - } catch (IOException e) { - throw new Error("This should never happen.", e); - } - return baos.toByteArray(); - } - - /** - * Constructor - * - * @param swf - */ - public DefineMorphShapeTag(SWF swf) { - super(swf, ID, "DefineMorphShape", null); - characterId = swf.getNextCharacterId(); - startBounds = new RECT(); - endBounds = new RECT(); - startEdges = SHAPE.createEmpty(1); - endEdges = SHAPE.createEmpty(1); - morphFillStyles = new MORPHFILLSTYLEARRAY(); - morphFillStyles.fillStyles = new MORPHFILLSTYLE[0]; - morphLineStyles = new MORPHLINESTYLEARRAY(); - morphLineStyles.lineStyles = new MORPHLINESTYLE[0]; - } - - /** - * Constructor - * - * @param sis - * @param data - * @throws IOException - */ - public DefineMorphShapeTag(SWFInputStream sis, ByteArrayRange data) throws IOException { - super(sis.getSwf(), ID, "DefineMorphShape", data); - readData(sis, data, 0, false, false, false); - } - - @Override - public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { - characterId = sis.readUI16("characterId"); - startBounds = sis.readRECT("startBounds"); - endBounds = sis.readRECT("endBounds"); - long offset = sis.readUI32("offset"); // ignore - morphFillStyles = sis.readMORPHFILLSTYLEARRAY("morphFillStyles"); - morphLineStyles = sis.readMORPHLINESTYLEARRAY(1, "morphLineStyles"); - startEdges = sis.readSHAPE(1, true, "startEdges"); - endEdges = sis.readSHAPE(1, true, "endEdges"); - } - - @Override - public RECT getRect(Set added) { - RECT rect = new RECT(); - rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); - rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); - rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); - rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); - return rect; - } - - @Override - public RECT getStartBounds() { - return startBounds; - } - - @Override - public RECT getEndBounds() { - return endBounds; - } - - @Override - public MORPHFILLSTYLEARRAY getFillStyles() { - return morphFillStyles; - } - - @Override - public MORPHLINESTYLEARRAY getLineStyles() { - return morphLineStyles; - } - - @Override - public SHAPE getStartEdges() { - return startEdges; - } - - @Override - public SHAPE getEndEdges() { - return endEdges; - } - - @Override - public int getShapeNum() { - return 1; - } - - @Override - public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { - List finalRecords = new ArrayList<>(); - FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); - LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); - - int startPosX = 0, startPosY = 0; - int endPosX = 0, endPosY = 0; - int posX = 0, posY = 0; - - for (int startIndex = 0, endIndex = 0; - startIndex < startEdges.shapeRecords.size() - && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { - - SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); - SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); - if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { - StyleChangeRecord scr1; - if (edge1 instanceof StyleChangeRecord) { - scr1 = (StyleChangeRecord) edge1; - if (scr1.stateMoveTo) { - startPosX = scr1.moveDeltaX; - startPosY = scr1.moveDeltaY; - } - } else { - scr1 = new StyleChangeRecord(); - startIndex--; - } - StyleChangeRecord scr2; - if (edge2 instanceof StyleChangeRecord) { - scr2 = (StyleChangeRecord) edge2; - if (scr2.stateMoveTo) { - endPosX = scr2.moveDeltaX; - endPosY = scr2.moveDeltaY; - } - } else { - scr2 = new StyleChangeRecord(); - endIndex--; - } - StyleChangeRecord scr = scr1.clone(); - if (scr1.stateMoveTo || scr2.stateMoveTo) { - scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO; - scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO; - scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; - } - finalRecords.add(scr); - continue; - } - - if (edge1 instanceof EndShapeRecord) { - finalRecords.add(edge1); - break; - } - if (edge2 instanceof EndShapeRecord) { - finalRecords.add(edge2); - break; - } - - if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { - CurvedEdgeRecord cer1 = null; - if (edge1 instanceof CurvedEdgeRecord) { - cer1 = (CurvedEdgeRecord) edge1; - } else if (edge1 instanceof StraightEdgeRecord) { - cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); - } - CurvedEdgeRecord cer2 = null; - if (edge2 instanceof CurvedEdgeRecord) { - cer2 = (CurvedEdgeRecord) edge2; - } else if (edge2 instanceof StraightEdgeRecord) { - cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); - } - if ((cer2 == null) || (cer1 == null)) { - continue; - } - CurvedEdgeRecord cer = new CurvedEdgeRecord(); - cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO; - cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO; - cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO; - cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO; - startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; - startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; - endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; - endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; - posX += cer.controlDeltaX + cer.anchorDeltaX; - posY += cer.controlDeltaY + cer.anchorDeltaY; - finalRecords.add(cer); - } else { - StraightEdgeRecord ser1 = null; - if (edge1 instanceof StraightEdgeRecord) { - ser1 = (StraightEdgeRecord) edge1; - } - StraightEdgeRecord ser2 = null; - if (edge2 instanceof StraightEdgeRecord) { - ser2 = (StraightEdgeRecord) edge2; - } - if ((ser2 == null) || (ser1 == null)) { - continue; - } - StraightEdgeRecord ser = new StraightEdgeRecord(); - ser.generalLineFlag = true; - ser.vertLineFlag = false; - ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO; - ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO; - startPosX += ser1.deltaX; - startPosY += ser1.deltaY; - endPosX += ser2.deltaX; - endPosY += ser2.deltaY; - posX += ser.deltaX; - posY += ser.deltaX; - finalRecords.add(ser); - } - } - SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); - shape.fillStyles = fillStyles; - shape.lineStyles = lineStyles; - shape.shapeRecords = finalRecords; - return shape; - } - - @Override - public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { - SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); - // shapeNum: 3 - // todo: Currently the generated image is not cached, because the cache - // key contains the hashCode of the finalRecord object, and it is always - // recreated - BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); - } - - @Override - public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { - if (ratio == -2) { - SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); - SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); - SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } else { - SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); - SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); - shapeExporter.export(); - } - } - - @Override - public int getNumFrames() { - return 65536; - } - - @Override - public boolean isSingleFrame() { - // Morpshape is a single frame specified with the ratio - return true; - } - - @Override - public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { - return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); - } - - @Override - public String toHtmlCanvas(double unitDivisor) { - CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); - cmse.export(); - - return cmse.getShapeData(); - } - - @Override - public void setCharacterId(int characterId) { - this.characterId = characterId; - } -} +/* + * 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.tags; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.SWFInputStream; +import com.jpexs.decompiler.flash.SWFOutputStream; +import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; +import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter; +import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; +import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; +import com.jpexs.decompiler.flash.tags.base.BoundedTag; +import com.jpexs.decompiler.flash.tags.base.MorphShapeTag; +import com.jpexs.decompiler.flash.tags.base.RenderContext; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.FILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLE; +import com.jpexs.decompiler.flash.types.MORPHFILLSTYLEARRAY; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLE; +import com.jpexs.decompiler.flash.types.MORPHLINESTYLEARRAY; +import com.jpexs.decompiler.flash.types.RECT; +import com.jpexs.decompiler.flash.types.SHAPE; +import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.ByteArrayRange; +import com.jpexs.helpers.SerializableImage; +import java.awt.Shape; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +/** + * + * + * @author JPEXS + */ +public class DefineMorphShapeTag extends MorphShapeTag { + + @SWFType(BasicType.UI16) + public int characterId; + + public RECT startBounds; + + public RECT endBounds; + + public MORPHFILLSTYLEARRAY morphFillStyles; + + public MORPHLINESTYLEARRAY morphLineStyles; + + public SHAPE startEdges; + + public SHAPE endEdges; + + public static final int ID = 46; + + public static final int MAX_RATIO = 65535; + + @Override + public void getNeededCharacters(Set needed) { + morphFillStyles.getNeededCharacters(needed); + startEdges.getNeededCharacters(needed); + endEdges.getNeededCharacters(needed); + } + + @Override + public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { + boolean modified = false; + modified |= morphFillStyles.replaceCharacter(oldCharacterId, newCharacterId); + modified |= startEdges.replaceCharacter(oldCharacterId, newCharacterId); + modified |= endEdges.replaceCharacter(oldCharacterId, newCharacterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public boolean removeCharacter(int characterId) { + boolean modified = false; + modified |= morphFillStyles.removeCharacter(characterId); + modified |= startEdges.removeCharacter(characterId); + modified |= endEdges.removeCharacter(characterId); + if (modified) { + setModified(true); + } + return modified; + } + + @Override + public int getCharacterId() { + return characterId; + } + + /** + * Gets data bytes + * + * @return Bytes of data + */ + @Override + public byte[] getData() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + OutputStream os = baos; + SWFOutputStream sos = new SWFOutputStream(os, getVersion()); + try { + sos.writeUI16(characterId); + sos.writeRECT(startBounds); + sos.writeRECT(endBounds); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); + SWFOutputStream sos2 = new SWFOutputStream(baos2, getVersion()); + sos2.writeMORPHFILLSTYLEARRAY(morphFillStyles, 1); + sos2.writeMORPHLINESTYLEARRAY(morphLineStyles, 1); + sos2.writeSHAPE(startEdges, 1); + byte[] d = baos2.toByteArray(); + sos.writeUI32(d.length); + sos.write(d); + sos.writeSHAPE(endEdges, 1); + + } catch (IOException e) { + throw new Error("This should never happen.", e); + } + return baos.toByteArray(); + } + + /** + * Constructor + * + * @param swf + */ + public DefineMorphShapeTag(SWF swf) { + super(swf, ID, "DefineMorphShape", null); + characterId = swf.getNextCharacterId(); + startBounds = new RECT(); + endBounds = new RECT(); + startEdges = SHAPE.createEmpty(1); + endEdges = SHAPE.createEmpty(1); + morphFillStyles = new MORPHFILLSTYLEARRAY(); + morphFillStyles.fillStyles = new MORPHFILLSTYLE[0]; + morphLineStyles = new MORPHLINESTYLEARRAY(); + morphLineStyles.lineStyles = new MORPHLINESTYLE[0]; + } + + /** + * Constructor + * + * @param sis + * @param data + * @throws IOException + */ + public DefineMorphShapeTag(SWFInputStream sis, ByteArrayRange data) throws IOException { + super(sis.getSwf(), ID, "DefineMorphShape", data); + readData(sis, data, 0, false, false, false); + } + + @Override + public final void readData(SWFInputStream sis, ByteArrayRange data, int level, boolean parallel, boolean skipUnusualTags, boolean lazy) throws IOException { + characterId = sis.readUI16("characterId"); + startBounds = sis.readRECT("startBounds"); + endBounds = sis.readRECT("endBounds"); + long offset = sis.readUI32("offset"); // ignore + morphFillStyles = sis.readMORPHFILLSTYLEARRAY("morphFillStyles"); + morphLineStyles = sis.readMORPHLINESTYLEARRAY(1, "morphLineStyles"); + startEdges = sis.readSHAPE(1, true, "startEdges"); + endEdges = sis.readSHAPE(1, true, "endEdges"); + } + + @Override + public RECT getRect(Set added) { + RECT rect = new RECT(); + rect.Xmin = Math.min(startBounds.Xmin, endBounds.Xmin); + rect.Ymin = Math.min(startBounds.Ymin, endBounds.Ymin); + rect.Xmax = Math.max(startBounds.Xmax, endBounds.Xmax); + rect.Ymax = Math.max(startBounds.Ymax, endBounds.Ymax); + return rect; + } + + @Override + public RECT getStartBounds() { + return startBounds; + } + + @Override + public RECT getEndBounds() { + return endBounds; + } + + @Override + public MORPHFILLSTYLEARRAY getFillStyles() { + return morphFillStyles; + } + + @Override + public MORPHLINESTYLEARRAY getLineStyles() { + return morphLineStyles; + } + + @Override + public SHAPE getStartEdges() { + return startEdges; + } + + @Override + public SHAPE getEndEdges() { + return endEdges; + } + + @Override + public int getShapeNum() { + return 1; + } + + @Override + public SHAPEWITHSTYLE getShapeAtRatio(int ratio) { + List finalRecords = new ArrayList<>(); + FILLSTYLEARRAY fillStyles = morphFillStyles.getFillStylesAt(ratio); + LINESTYLEARRAY lineStyles = morphLineStyles.getLineStylesAt(getShapeNum(), ratio); + + int startPosX = 0, startPosY = 0; + int endPosX = 0, endPosY = 0; + int posX = 0, posY = 0; + + for (int startIndex = 0, endIndex = 0; + startIndex < startEdges.shapeRecords.size() + && endIndex < endEdges.shapeRecords.size(); startIndex++, endIndex++) { + + SHAPERECORD edge1 = startEdges.shapeRecords.get(startIndex); + SHAPERECORD edge2 = endEdges.shapeRecords.get(endIndex); + if (edge1 instanceof StyleChangeRecord || edge2 instanceof StyleChangeRecord) { + StyleChangeRecord scr1; + if (edge1 instanceof StyleChangeRecord) { + scr1 = (StyleChangeRecord) edge1; + if (scr1.stateMoveTo) { + startPosX = scr1.moveDeltaX; + startPosY = scr1.moveDeltaY; + } + } else { + scr1 = new StyleChangeRecord(); + startIndex--; + } + StyleChangeRecord scr2; + if (edge2 instanceof StyleChangeRecord) { + scr2 = (StyleChangeRecord) edge2; + if (scr2.stateMoveTo) { + endPosX = scr2.moveDeltaX; + endPosY = scr2.moveDeltaY; + } + } else { + scr2 = new StyleChangeRecord(); + endIndex--; + } + StyleChangeRecord scr = scr1.clone(); + if (scr1.stateMoveTo || scr2.stateMoveTo) { + scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO; + scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO; + scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY; + } + finalRecords.add(scr); + continue; + } + + if (edge1 instanceof EndShapeRecord) { + finalRecords.add(edge1); + break; + } + if (edge2 instanceof EndShapeRecord) { + finalRecords.add(edge2); + break; + } + + if (edge1 instanceof CurvedEdgeRecord || edge2 instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer1 = null; + if (edge1 instanceof CurvedEdgeRecord) { + cer1 = (CurvedEdgeRecord) edge1; + } else if (edge1 instanceof StraightEdgeRecord) { + cer1 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge1); + } + CurvedEdgeRecord cer2 = null; + if (edge2 instanceof CurvedEdgeRecord) { + cer2 = (CurvedEdgeRecord) edge2; + } else if (edge2 instanceof StraightEdgeRecord) { + cer2 = SHAPERECORD.straightToCurve((StraightEdgeRecord) edge2); + } + if ((cer2 == null) || (cer1 == null)) { + continue; + } + CurvedEdgeRecord cer = new CurvedEdgeRecord(); + cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO; + cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO; + cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO; + cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO; + startPosX += cer1.controlDeltaX + cer1.anchorDeltaX; + startPosY += cer1.controlDeltaY + cer1.anchorDeltaY; + endPosX += cer2.controlDeltaX + cer2.anchorDeltaX; + endPosY += cer2.controlDeltaY + cer2.anchorDeltaY; + posX += cer.controlDeltaX + cer.anchorDeltaX; + posY += cer.controlDeltaY + cer.anchorDeltaY; + finalRecords.add(cer); + } else { + StraightEdgeRecord ser1 = null; + if (edge1 instanceof StraightEdgeRecord) { + ser1 = (StraightEdgeRecord) edge1; + } + StraightEdgeRecord ser2 = null; + if (edge2 instanceof StraightEdgeRecord) { + ser2 = (StraightEdgeRecord) edge2; + } + if ((ser2 == null) || (ser1 == null)) { + continue; + } + StraightEdgeRecord ser = new StraightEdgeRecord(); + ser.generalLineFlag = true; + ser.vertLineFlag = false; + ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO; + ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO; + startPosX += ser1.deltaX; + startPosY += ser1.deltaY; + endPosX += ser2.deltaX; + endPosY += ser2.deltaY; + posX += ser.deltaX; + posY += ser.deltaX; + finalRecords.add(ser); + } + } + SHAPEWITHSTYLE shape = new SHAPEWITHSTYLE(); + shape.fillStyles = fillStyles; + shape.lineStyles = lineStyles; + shape.shapeRecords = finalRecords; + return shape; + } + + @Override + public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, Matrix transformation, ColorTransform colorTransform) { + SHAPEWITHSTYLE shape = getShapeAtRatio(ratio); + // shapeNum: 3 + // todo: Currently the generated image is not cached, because the cache + // key contains the hashCode of the finalRecord object, and it is always + // recreated + BitmapExporter.export(swf, shape, null, image, transformation, colorTransform); + } + + @Override + public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level, double zoom) { + if (ratio == -2) { + SHAPEWITHSTYLE beginShapes = getShapeAtRatio(0); + SHAPEWITHSTYLE endShapes = getShapeAtRatio(65535); + SVGMorphShapeExporter shapeExporter = new SVGMorphShapeExporter(swf, beginShapes, endShapes, exporter, null, colorTransform, zoom); + shapeExporter.export(); + } else { + SHAPEWITHSTYLE shapes = getShapeAtRatio(ratio); + SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, shapes, exporter, null, colorTransform, zoom); + shapeExporter.export(); + } + } + + @Override + public int getNumFrames() { + return 65536; + } + + @Override + public boolean isSingleFrame() { + // Morpshape is a single frame specified with the ratio + return true; + } + + @Override + public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation) { + return transformation.toTransform().createTransformedShape(getShapeAtRatio(ratio).getOutline()); + } + + @Override + public String toHtmlCanvas(double unitDivisor) { + CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0); + cmse.export(); + return cmse.getShapeData(); + } + + @Override + public void setCharacterId(int characterId) { + this.characterId = characterId; + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index e62f663fb..464c15bfc 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -1191,25 +1191,27 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } if (export.isOptionEnabled(ScriptExportMode.class)) { - boolean parallel = Configuration.parallelSpeedUp.get(); - String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); - Path.createDirectorySafe(new File(scriptsFolder)); - ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), !parallel && Configuration.scriptExportSingleFile.get()); - String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); - if (swf.isAS3()) { - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - for (int i = 0; i < as3scripts.size(); i++) { - ScriptPack tls = as3scripts.get(i); - Main.startWork(translate("work.exporting") + " " + (i + 1) + "/" + as3scripts.size() + " " + tls.getPath() + " ..."); - ret.add(tls.export(scriptsFolder, scriptExportSettings, parallel)); + if (as3scripts.size() > 0 || as12scripts.size() > 0) { + boolean parallel = Configuration.parallelSpeedUp.get(); + String scriptsFolder = Path.combine(selFile, ScriptExportSettings.EXPORT_FOLDER_NAME); + Path.createDirectorySafe(new File(scriptsFolder)); + ScriptExportSettings scriptExportSettings = new ScriptExportSettings(export.getValue(ScriptExportMode.class), !parallel && Configuration.scriptExportSingleFile.get()); + String singleFileName = Path.combine(scriptsFolder, swf.getShortFileName() + scriptExportSettings.getFileExtension()); + if (swf.isAS3()) { + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + for (int i = 0; i < as3scripts.size(); i++) { + ScriptPack tls = as3scripts.get(i); + Main.startWork(translate("work.exporting") + " " + (i + 1) + "/" + as3scripts.size() + " " + tls.getPath() + " ..."); + ret.add(tls.export(scriptsFolder, scriptExportSettings, parallel)); + } + } + } else { + Map asmsToExport = swf.getASMs(true, as12scripts, false); + try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { + scriptExportSettings.singleFileWriter = writer; + ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, scriptsFolder, asmsToExport, scriptExportSettings, evl)); } - } - } else { - Map asmsToExport = swf.getASMs(true, as12scripts, false); - try (FileTextWriter writer = scriptExportSettings.singleFile ? new FileTextWriter(Configuration.getCodeFormatting(), new FileOutputStream(singleFileName)) : null) { - scriptExportSettings.singleFileWriter = writer; - ret.addAll(new AS2ScriptExporter().exportAS2ScriptsTimeout(handler, scriptsFolder, asmsToExport, scriptExportSettings, evl)); } } }