From 87d0bfc761f518f0aea71f6a359925144f190d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Thu, 26 Oct 2023 20:05:26 +0200 Subject: [PATCH] Added SVG Export - stroke-bitmapId, fill-bitmapId attribute Fixed Generic tag editor - morphshape fill - show bitmapId for repeating bitmap fill, gradient matrix for focal gradient Changed SVG export - attributes like data-characterId and data-characterName moved under `ffdec:` namespace --- CHANGELOG.md | 3 ++ .../exporters/commonshape/SVGExporter.java | 15 +++--- .../exporters/shape/SVGShapeExporter.java | 3 +- .../decompiler/flash/types/FOCALGRADIENT.java | 50 +++++++++++++++++++ .../decompiler/flash/types/GRADIENT.java | 13 ++++- .../flash/types/MORPHFILLSTYLE.java | 12 ++--- 6 files changed, 81 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7a6dd7a..f66240fec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - Context menu items to create new tags (shape, morphshape, sprite, image, movie, sound, binaryData) from files and using font embed dialog for fonts - Replacing morphshapes +- SVG Export - stroke-bitmapId, fill-bitmapId attribute ### Fixed - [#1306], [#1768] Maximizing window on other than main monitor @@ -26,9 +27,11 @@ All notable changes to this project will be documented in this file. - miterLimitFactor is FIXED8 value in MORPHLINESTYLE2 - Display of morphshape end shape to be exactly at 65535 ratio - SVG import - duplicated image on bitmap fill style +- Generic tag editor - morphshape fill - show bitmapId for repeating bitmap fill, gradient matrix for focal gradient ### Changed - Basic tag info panel always visible even when nothing to display (to avoid flickering) +- SVG export - attributes like data-characterId and data-characterName moved under `ffdec:` namespace ## [19.1.2] - 2023-10-16 ### Fixed diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java index c13d9a7d5..7ebfa603a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/commonshape/SVGExporter.java @@ -61,6 +61,8 @@ public class SVGExporter { protected static final String sNamespace = "http://www.w3.org/2000/svg"; protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink"; + + protected static final String ffdecNamespace = "https://www.free-decompiler.com/flash"; protected Document _svg; @@ -97,6 +99,7 @@ public class SVGExporter { _svg = impl.createDocument(sNamespace, "svg", svgDocType); Element svgRoot = _svg.getDocumentElement(); svgRoot.setAttribute("xmlns:xlink", xlinkNamespace); + svgRoot.setAttribute("xmlns:ffdec", ffdecNamespace); if (bounds != null) { if (Configuration.svgRetainBounds.get()) { svgRoot.setAttribute("width", (bounds.xMax / SWF.unitDivisor) + "px"); @@ -416,10 +419,10 @@ public class SVGExporter { image.setAttribute("id", instanceName); } if (characterId != null) { - image.setAttribute("data-characterId", characterId); + image.setAttribute("ffdec:characterId", characterId); } - if (characterName != null) { - image.setAttribute("data-characterName", characterName); + if (characterName != null && !characterName.isEmpty()) { + image.setAttribute("ffdec:characterName", characterName); } setBlendMode(image, blendMode); handleFilters(image, filters); @@ -469,10 +472,10 @@ public class SVGExporter { image.setAttribute("id", instanceName); } if (characterId != null) { - image.setAttribute("data-characterId", characterId); + image.setAttribute("ffdec:characterId", characterId); } - if (characterName != null) { - image.setAttribute("data-characterName", characterName); + if (characterName != null && !characterName.isEmpty()) { + image.setAttribute("ffdec:characterName", characterName); } setBlendMode(image, blendMode); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java index 83a743d60..081002bb8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/SVGShapeExporter.java @@ -158,6 +158,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { return; } path.setAttribute("fill", "#ff0000"); + path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId); } @Override @@ -229,7 +230,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { String patternId = getPattern(bitmapId, matrix, colorTransform); if (patternId != null) { path.setAttribute("stroke", "url(#" + patternId + ")"); - return; + path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FOCALGRADIENT.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FOCALGRADIENT.java index 373f4573e..69107b668 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FOCALGRADIENT.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FOCALGRADIENT.java @@ -27,4 +27,54 @@ public class FOCALGRADIENT extends GRADIENT implements Serializable { @SWFType(BasicType.FIXED8) public float focalPoint; + + @Override + public boolean isCompatibleGradient(GRADIENT otherGradient) { + if (interpolationMode != otherGradient.interpolationMode) { + return false; + } + if (spreadMode != otherGradient.spreadMode) { + return false; + } + if (gradientRecords.length != otherGradient.gradientRecords.length) { + return false; + } + return true; + } + + @Override + public MORPHGRADIENT toMorphGradient() { + MORPHFOCALGRADIENT morphGradient = new MORPHFOCALGRADIENT(); + morphGradient.interPolationMode = interpolationMode; + morphGradient.spreadMode = spreadMode; + morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length]; + for (int i = 0; i < gradientRecords.length; i++) { + morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(); + } + morphGradient.startFocalPoint = focalPoint; + morphGradient.startFocalPoint = focalPoint; + + return morphGradient; + } + + @Override + public MORPHGRADIENT toMorphGradient(GRADIENT endGradient) { + if (!isCompatibleGradient(endGradient)) { + return null; + } + MORPHFOCALGRADIENT morphGradient = new MORPHFOCALGRADIENT(); + morphGradient.interPolationMode = interpolationMode; + morphGradient.spreadMode = spreadMode; + morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length]; + for (int i = 0; i < gradientRecords.length; i++) { + morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(); + } + morphGradient.startFocalPoint = focalPoint; + if (endGradient instanceof FOCALGRADIENT) { + morphGradient.endFocalPoint = ((FOCALGRADIENT)endGradient).focalPoint; + } else { + morphGradient.endFocalPoint = 0; + } + return morphGradient; + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java index f4b290658..c9a566e24 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/GRADIENT.java @@ -63,7 +63,7 @@ public class GRADIENT implements Serializable { @SWFArray(value = "record") public GRADRECORD[] gradientRecords = new GRADRECORD[0]; - public boolean isCompatibleGradient(GRADIENT otherGradient) { + public boolean isCompatibleGradient(GRADIENT otherGradient) { if (interpolationMode != otherGradient.interpolationMode) { return false; } @@ -91,13 +91,22 @@ public class GRADIENT implements Serializable { if (!isCompatibleGradient(endGradient)) { return null; } - MORPHGRADIENT morphGradient = new MORPHGRADIENT(); + MORPHGRADIENT morphGradient; + if (endGradient instanceof FOCALGRADIENT) { + morphGradient = new MORPHFOCALGRADIENT(); + } else { + morphGradient = new MORPHGRADIENT(); + } morphGradient.interPolationMode = interpolationMode; morphGradient.spreadMode = spreadMode; morphGradient.gradientRecords = new MORPHGRADRECORD[gradientRecords.length]; for (int i = 0; i < gradientRecords.length; i++) { morphGradient.gradientRecords[i] = gradientRecords[i].toMorphGradRecord(); } + if (endGradient instanceof FOCALGRADIENT) { + ((MORPHFOCALGRADIENT)morphGradient).startFocalPoint = 0; + ((MORPHFOCALGRADIENT)morphGradient).endFocalPoint = ((FOCALGRADIENT)endGradient).focalPoint; + } return morphGradient; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java index 09e82c05e..767060a94 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java @@ -65,22 +65,22 @@ public class MORPHFILLSTYLE implements NeedsCharacters, Serializable { @Conditional(value = "fillStyleType", options = {SOLID}) public RGBA endColor; - @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT}) + @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT, FOCAL_RADIAL_GRADIENT}) public MATRIX startGradientMatrix; - @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT}) + @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT, FOCAL_RADIAL_GRADIENT}) public MATRIX endGradientMatrix; - @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT}) + @Conditional(value = "fillStyleType", options = {LINEAR_GRADIENT, RADIAL_GRADIENT, FOCAL_RADIAL_GRADIENT}) public MORPHGRADIENT gradient; - @Conditional(value = "fillStyleType", options = {CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) + @Conditional(value = "fillStyleType", options = {REPEATING_BITMAP, CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) public int bitmapId; - @Conditional(value = "fillStyleType", options = {CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) + @Conditional(value = "fillStyleType", options = {REPEATING_BITMAP, CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) public MATRIX startBitmapMatrix; - @Conditional(value = "fillStyleType", options = {CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) + @Conditional(value = "fillStyleType", options = {REPEATING_BITMAP, CLIPPED_BITMAP, NON_SMOOTHED_REPEATING_BITMAP, NON_SMOOTHED_CLIPPED_BITMAP}) public MATRIX endBitmapMatrix; @Override