From 38ed5ee829f9c926656d853580547ee9c3a20328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 28 Oct 2023 17:41:45 +0200 Subject: [PATCH] Fixed #2031 FLA export - morphshapes with duplicated strokes, timelines with multiple shape tweens --- CHANGELOG.md | 2 + .../decompiler/flash/xfl/XFLConverter.java | 64 +++++++++++++++---- 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6c21dde7..7be8c80d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ All notable changes to this project will be documented in this file. - SVG import - linear gradients - SVG import - Do not use fill winding nonzero when only stroking - Morphshape SVG export - closing the stroke +- [#2031] FLA export - morphshapes with duplicated strokes, timelines with multiple shape tweens ### Changed - Basic tag info panel always visible even when nothing to display (to avoid flickering) @@ -3230,6 +3231,7 @@ Major version of SWF to XML export changed to 2. [#1768]: https://www.free-decompiler.com/flash/issues/1768 [#2013]: https://www.free-decompiler.com/flash/issues/2013 [#2104]: https://www.free-decompiler.com/flash/issues/2104 +[#2031]: https://www.free-decompiler.com/flash/issues/2031 [#2099]: https://www.free-decompiler.com/flash/issues/2099 [#2090]: https://www.free-decompiler.com/flash/issues/2090 [#2079]: https://www.free-decompiler.com/flash/issues/2079 diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java index ac88e1903..710e8d3a2 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/xfl/XFLConverter.java @@ -242,22 +242,18 @@ public class XFLConverter { return "" + strValue; } - private static void convertShapeEdge(MATRIX mat, ShapeRecordAdvanced record, double x, double y, StringBuilder ret) { + private static String convertShapeEdge(ShapeRecordAdvanced record, double x, double y) { if (record instanceof StyleChangeRecordAdvanced) { StyleChangeRecordAdvanced scr = (StyleChangeRecordAdvanced) record; Point2D p = new Point2D.Double(scr.moveDeltaX, scr.moveDeltaY); if (scr.stateMoveTo) { - ret.append("! ").append(formatEdgeDouble(p.getX(), false)).append(" ").append(formatEdgeDouble(p.getY(), false)); + return "! " + formatEdgeDouble(p.getX(), false) + " " + formatEdgeDouble(p.getY(), false); } } else if (record instanceof StraightEdgeRecordAdvanced) { StraightEdgeRecordAdvanced ser = (StraightEdgeRecordAdvanced) record; - y += ser.deltaY; - x += ser.deltaX; - Point2D p = new Point2D.Double(x, y); - ret.append("| "); - ret.append(formatEdgeDouble(p.getX(), false)); - ret.append(" "); - ret.append(formatEdgeDouble(p.getY(), false)); + Point2D p = new Point2D.Double(x + ser.deltaX, y + ser.deltaY); + return "! " + formatEdgeDouble(x, false) + " " + formatEdgeDouble(y, false) + + "| " + formatEdgeDouble(p.getX(), false) + " " + formatEdgeDouble(p.getY(), false); } else if (record instanceof CurvedEdgeRecordAdvanced) { CurvedEdgeRecordAdvanced cer = (CurvedEdgeRecordAdvanced) record; double controlX = cer.controlDeltaX + x; @@ -266,8 +262,10 @@ public class XFLConverter { double anchorY = cer.anchorDeltaY + controlY; Point2D control = new Point2D.Double(controlX, controlY); Point2D anchor = new Point.Double(anchorX, anchorY); - ret.append("[ ").append(formatEdgeDouble(control.getX(), true)).append(" ").append(formatEdgeDouble(control.getY(), true)).append(" ").append(formatEdgeDouble(anchor.getX(), true)).append(" ").append(formatEdgeDouble(anchor.getY(), true)); + return "! " + formatEdgeDouble(x, false) + " " + formatEdgeDouble(y, false) + + "[ " + formatEdgeDouble(control.getX(), true) + " " + formatEdgeDouble(control.getY(), true) + " " + formatEdgeDouble(anchor.getX(), true) + " " + formatEdgeDouble(anchor.getY(), true); } + return ""; } private static void convertShapeEdges(boolean close, double startX, double startY, MATRIX mat, List recordsAdvanced, StringBuilder ret) { @@ -289,6 +287,10 @@ public class XFLConverter { double lastMoveToX = startX; double lastMoveToY = startY; + int fillStyle0 = 0; + int fillStyle1 = 0; + int lineStyle = 0; + List edges = new ArrayList<>(); for (ShapeRecordAdvanced rec : recordsAdvanced) { if (rec instanceof StyleChangeRecordAdvanced) { StyleChangeRecordAdvanced scr = (StyleChangeRecordAdvanced) rec; @@ -296,15 +298,43 @@ public class XFLConverter { lastMoveToX = scr.moveDeltaX; lastMoveToY = scr.moveDeltaY; } + if (scr.stateNewStyles) { + fillStyle0 = 0; + fillStyle1 = 0; + lineStyle = 0; + } + if (scr.stateLineStyle) { + lineStyle = scr.lineStyle; + } + if (scr.stateFillStyle0) { + fillStyle0 = scr.fillStyle0; + } + if (scr.stateFillStyle1) { + fillStyle1 = scr.fillStyle1; + } } - convertShapeEdge(mat, rec, x, y, ret); + + + String edge = convertShapeEdge(rec, x, y); + + //ignore duplicated edges with only strokes #2031 + if (fillStyle0 == 0 && fillStyle1 == 0 && lineStyle != 0) { + if (!edges.contains(edge)) { + edges.add(edge); + ret.append(edge); + } + } else { + edges.add(edge); + ret.append(edge); + } + x = rec.changeX(x); y = rec.changeY(y); } //hack for morphshapes. TODO: make this better if (close && (Double.compare(lastMoveToX, x) != 0 || Double.compare(lastMoveToY, y) != 0)) { StraightEdgeRecordAdvanced ser = new StraightEdgeRecordAdvanced(lastMoveToX - x, lastMoveToY - y); - convertShapeEdge(mat, ser, x, y, ret); + ret.append(convertShapeEdge(ser, x, y)); } } @@ -2370,6 +2400,14 @@ public class XFLConverter { if (newCharId == -1) { newCharId = characterId; } + if (characterId != -1 && newCharId != characterId) { + if (shapeTween && character != null) { + MorphShapeTag m = (MorphShapeTag) character; + shapeTweener = m; + shapeTween = false; + lastTweenRatio = ratio; + } + } characterId = newCharId; if (characters.containsKey(characterId)) { character = characters.get(characterId); @@ -2460,7 +2498,7 @@ public class XFLConverter { if (shapeTweener != null) { MorphShapeTag m = shapeTweener; XFLXmlWriter addLastWriter = new XFLXmlWriter(); - SHAPEWITHSTYLE endShape = m.getShapeAtRatio(lastTweenRatio); + SHAPEWITHSTYLE endShape = m.getShapeAtRatio(65535); //lastTweenRatio); convertShape(characters, matrix, m.getShapeNum() == 1 ? 3 : 4, endShape.shapeRecords, m.getFillStyles().getFillStylesAt(lastTweenRatio), m.getLineStyles().getLineStylesAt(m.getShapeNum(), lastTweenRatio), true, false, addLastWriter); duration--; convertFrame(true, null, null, frame - duration, duration, "", lastElements, files, writer2);