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 cbff13bd8..add534d9d 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 @@ -34,7 +34,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; @@ -84,8 +83,6 @@ public class SVGExporter { public Map exportedTags = new HashMap<>(); - public Set exportedSmallStrokesTags = new HashSet<>(); - public Map> exportedChars = new HashMap<>(); private final Map lastIds = new HashMap<>(); @@ -550,11 +547,11 @@ public class SVGExporter { _svgGs.peek().appendChild(filtersElement); } - public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, boolean hasSmallStrokes) { - return addUse(transform, boundRect, href, instanceName, scalingRect, null, null, BlendMode.NORMAL, new ArrayList<>(), hasSmallStrokes); + public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect) { + return addUse(transform, boundRect, href, instanceName, scalingRect, null, null, BlendMode.NORMAL, new ArrayList<>()); } - public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode, List filters, boolean hasSmallStrokes) { + public Element addUse(Matrix transform, RECT boundRect, String href, String instanceName, RECT scalingRect, String characterId, String characterName, int blendMode, List filters) { if (scalingRect != null && (transform == null || (Double.compare(transform.rotateSkew0, 0.0) == 0 && Double.compare(transform.rotateSkew1, 0.0) == 0))) { addScalingGridUse(transform, boundRect, href, instanceName, scalingRect, characterId, characterName, blendMode, filters); return null; //?? @@ -574,10 +571,7 @@ public class SVGExporter { if (characterName != null && !characterName.isEmpty()) { image.setAttribute("ffdec:characterName", characterName); } - if (hasSmallStrokes) { - image.setAttribute("ffdec:has-small-stroke", "true"); - } - + setBlendMode(image, blendMode); handleFilters(image, filters); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index f24852279..f63b8b162 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -962,7 +962,7 @@ public abstract class TextTag extends DrawableTag { } if (!"".equals(charId)) { - Element charImage = exporter.addUse(mat, bounds, charId, null, null, false); + Element charImage = exporter.addUse(mat, bounds, charId, null, null); RGBA colorA = new RGBA(textColor); charImage.setAttribute("fill", colorA.toHexRGB()); if (colorA.alpha != 255) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 3268c54e9..ba7098b26 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -59,18 +59,22 @@ import com.jpexs.decompiler.flash.types.BlendMode; import com.jpexs.decompiler.flash.types.CLIPACTIONS; import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.decompiler.flash.types.ColorTransform; +import com.jpexs.decompiler.flash.types.LINESTYLE; +import com.jpexs.decompiler.flash.types.LINESTYLE2; +import com.jpexs.decompiler.flash.types.LINESTYLEARRAY; import com.jpexs.decompiler.flash.types.MATRIX; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.SOUNDINFO; import com.jpexs.decompiler.flash.types.filters.BlendComposite; import com.jpexs.decompiler.flash.types.filters.FILTER; +import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; +import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; import com.jpexs.helpers.Helper; import com.jpexs.helpers.SerializableImage; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; @@ -84,7 +88,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -1585,6 +1588,65 @@ public class Timeline { g.setClip(prevClip); } + /** + * Check whether (inner) shape tags have strokes smaller than 1px + * + * @param exporter SVG exporter + * @param drawableTag Drawable tag + * @param matrix Matrix + * @return True if has small strokes + */ + private boolean tagHasSmallStrokes(SVGExporter exporter, DrawableTag drawableTag, Matrix matrix) { + if (drawableTag instanceof Timelined) { + Timelined tim = (Timelined) drawableTag; + for (Frame fr : tim.getTimeline().frames) { + for (DepthState ds : fr.layers.values()) { + Matrix subMat = matrix.concatenate(new Matrix(ds.matrix)); + CharacterTag cht = ds.getCharacter(); + if ((cht instanceof DrawableTag) && tagHasSmallStrokes(exporter, (DrawableTag) cht, subMat)) { + return true; + } + } + } + } + if (drawableTag instanceof ShapeTag) { + com.jpexs.decompiler.flash.exporters.commonshape.Point p00 = matrix.transform(0, 0); + com.jpexs.decompiler.flash.exporters.commonshape.Point p11 = matrix.transform(1, 1); + double thicknessScale = p00.distanceTo(p11) / Math.sqrt(2); + + ShapeTag st = (ShapeTag) drawableTag; + List lineStyles = new ArrayList<>(); + lineStyles.add(st.getShapes().lineStyles); + + for (SHAPERECORD rec : st.getShapes().shapeRecords) { + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateNewStyles) { + lineStyles.add(scr.lineStyles); + } + } + } + + for (LINESTYLEARRAY lsArr : lineStyles) { + if (lsArr.lineStyles != null) { + for (LINESTYLE ls : lsArr.lineStyles) { + if (ls.width * exporter.getZoom() * thicknessScale < 1 * SWF.unitDivisor) { + return true; + } + } + } + if (lsArr.lineStyles2 != null) { + for (LINESTYLE2 ls : lsArr.lineStyles2) { + if (ls.width * exporter.getZoom() * thicknessScale < 1 * SWF.unitDivisor) { + return true; + } + } + } + } + } + return false; + } + /** * Converts specified frame to SVG. * @@ -1652,7 +1714,7 @@ public class Timeline { Matrix layerMatrix = new Matrix(layer.getDrawingMatrix()); Matrix absMat = strokeTransformation.concatenate(layerMatrix); - + if (character instanceof DrawableTag) { DrawableTag drawable = (DrawableTag) character; @@ -1678,26 +1740,24 @@ public class Timeline { boolean createNew = false; SVGExporter.ExportKey exportKey = new SVGExporter.ExportKey(drawableTag, clrTrans, layer.ratio, layer.clipDepth > -1); - if (exporter.exportedTags.containsKey(exportKey) - && !exporter.exportedSmallStrokesTags.contains(exportKey)) { + boolean hasSmallStroke = tagHasSmallStrokes(exporter, drawable, absMat); + + if (!hasSmallStroke && exporter.exportedTags.containsKey(exportKey)) { assetName = exporter.exportedTags.get(exportKey); } else { assetName = getTagIdPrefix(drawableTag, exporter); - exporter.exportedTags.put(exportKey, assetName); + if (!hasSmallStroke) { + exporter.exportedTags.put(exportKey, assetName); + } createNew = true; } - boolean hasSmallStrokes = false; if (createNew) { exporter.createDefGroup(new ExportRectangle(boundRect), assetName); drawable.toSVG(exporter, layer.ratio, clrTrans, level + 1, transformation, absMat); - hasSmallStrokes = exporter.hasSmallStrokes(); - exporter.endGroup(); + exporter.endGroup(); } Matrix mat = Matrix.getTranslateInstance(rect.xMin, rect.yMin).preConcatenate(new Matrix(layer.matrix)); - exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames()), layer.blendMode, layer.filters, hasSmallStrokes); - if (hasSmallStrokes) { - exporter.exportedSmallStrokesTags.add(exportKey); - } + exporter.addUse(mat, boundRect, assetName, layer.instanceName, scalingGrid == null ? null : scalingGrid.splitter, String.valueOf(drawable.getCharacterId()), String.join("___", drawable.getClassNames()), layer.blendMode, layer.filters); } } }