diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b954b81b..bcbaf2bae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ All notable changes to this project will be documented in this file. and using font embed dialog for fonts - Replacing morphshapes - SVG Export - stroke-bitmapId, fill-bitmapId attribute +- Morphshape SVG Export - bitmap fill strokes +- SVG Export/Import - retain bitmap fill smoothed attribute ### Fixed - [#1306], [#1768] Maximizing window on other than main monitor 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 7094cede9..45ffd4fc1 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 @@ -530,4 +530,9 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { private String useRatioColor(RGB color, RGB colorEnd) { return "tocolor(ctrans.apply([" + useRatioInt(color.red, colorEnd.red) + "," + useRatioInt(color.green, colorEnd.green) + "," + useRatioInt(color.blue, colorEnd.blue) + ",((" + useRatioInt((color instanceof RGBA) ? ((RGBA) color).alpha : 255, (colorEnd instanceof RGBA) ? ((RGBA) colorEnd).alpha : 255) + ")/255)]))"; } + + @Override + public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { + //TODO + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java index b46e7f9e6..110bcb996 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java @@ -51,6 +51,8 @@ public interface IMorphShapeExporter { public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd); + public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform); + public void moveTo(double x, double y, double x2, double y2); public void lineTo(double x, double y, double x2, double y2); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java index b95ca458e..38b706f1a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java @@ -472,6 +472,19 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter { (fillStyleEnd.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyleEnd.gradient).focalPoint : 0 ); break; + case FILLSTYLE.CLIPPED_BITMAP: + case FILLSTYLE.REPEATING_BITMAP: + case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP: + case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP: + Matrix bmatrix = new Matrix(fillStyle.bitmapMatrix); + Matrix bmatrixEnd = new Matrix(fillStyleEnd.bitmapMatrix); + lineBitmapStyle(fillStyle.bitmapId, + bmatrix, + bmatrixEnd, + (fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP), + (fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.CLIPPED_BITMAP), + colorTransform); + break; } } } else { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java index 3800f19e9..5d82e9df8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java @@ -106,6 +106,16 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { @Override public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { finalizePath(); + String patternId = getPattern(bitmapId, matrix, matrixEnd, smooth); + path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId); + if (patternId != null) { + path.setAttribute("style", "fill:url(#" + patternId + ")"); + return; + } + path.setAttribute("fill", "#ff0000"); + } + + public String getPattern(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean smooth) { ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImageCached(); @@ -121,7 +131,6 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { ImageFormat format = image.getImageFormat(); byte[] imageData = Helper.readStream(image.getConvertedImageData()); String base64ImgData = Helper.byteArrayToBase64String(imageData); - path.setAttribute("style", "fill:url(#" + patternId + ")"); Element pattern = exporter.createElement("pattern"); pattern.setAttribute("id", patternId); pattern.setAttribute("patternUnits", "userSpaceOnUse"); @@ -129,6 +138,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { pattern.setAttribute("width", "" + width); pattern.setAttribute("height", "" + height); pattern.setAttribute("viewBox", "0 0 " + width + " " + height); + pattern.setAttribute("ffdec:smoothed", smooth ? "true" : "false"); if (matrix != null) { matrix = matrix.clone(); matrix.rotateSkew0 *= zoom / SWF.unitDivisor; @@ -148,8 +158,10 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData); pattern.appendChild(imageElement); exporter.addToGroup(pattern); + return patternId; } } + return null; } @Override @@ -460,6 +472,20 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { } } + @Override + public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) { + path.removeAttribute("stroke-opacity"); + + String patternId = getPattern(bitmapId, matrix, matrixEnd, smooth); + path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId); + + if (patternId != null) { + path.setAttribute("style", "stroke:url(#" + patternId + ")"); + return; + } + path.setAttribute("stroke", "#ff0000"); + } + protected double roundPixels400(double pixels) { return Math.round(pixels * 10000) / 10000.0; } 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 a47f38a60..7666183a4 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 @@ -107,7 +107,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { exporter.addToDefs(gradient); } - private String getPattern(int bitmapId, Matrix matrix, ColorTransform colorTransform) { + private String getPattern(int bitmapId, Matrix matrix, ColorTransform colorTransform, boolean smoothed) { ImageTag image = swf.getImage(bitmapId); if (image != null) { SerializableImage img = image.getImageCached(); @@ -131,6 +131,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { pattern.setAttribute("width", "" + width); pattern.setAttribute("height", "" + height); pattern.setAttribute("viewBox", "0 0 " + width + " " + height); + pattern.setAttribute("ffdec:smoothed", smoothed ? "true" : "false"); if (matrix != null) { pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom)); } @@ -152,13 +153,13 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { return; } finalizePath(); - String patternId = getPattern(bitmapId, matrix, colorTransform); + String patternId = getPattern(bitmapId, matrix, colorTransform, smooth); + path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId); if (patternId != null) { path.setAttribute("style", "fill:url(#" + patternId + ")"); return; } path.setAttribute("fill", "#ff0000"); - path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId); } @Override @@ -227,11 +228,13 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter { @Override public void lineBitmapStyle(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) { - String patternId = getPattern(bitmapId, matrix, colorTransform); + String patternId = getPattern(bitmapId, matrix, colorTransform, smooth); + path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId); if (patternId != null) { path.setAttribute("stroke", "url(#" + patternId + ")"); - path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId); + return; } + path.setAttribute("stroke", "#ff0000"); } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/morphshape/MorphShapeGenerator.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/morphshape/MorphShapeGenerator.java index a8a67ba8c..c9ceb17e5 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/morphshape/MorphShapeGenerator.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/morphshape/MorphShapeGenerator.java @@ -235,8 +235,9 @@ public class MorphShapeGenerator { } for (int i = 0; i < startLineStyles.size(); i++) { - LINESTYLE2 lsEnd = endLineStyles.get(i); - if (lsEnd.hasFillFlag && lsEnd.fillType.hasBitmap()) { + LINESTYLE2 lsStart = startLineStyles.get(i); + LINESTYLE2 lsEnd = endLineStyles.get(i); + if (lsEnd.hasFillFlag && lsEnd.fillType.hasBitmap() && lsStart.fillType.bitmapId != lsEnd.fillType.bitmapId) { swf.removeTag(swf.getImage(lsEnd.fillType.bitmapId)); } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgBitmapFill.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgBitmapFill.java index 14b1b364f..682e8fbaa 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgBitmapFill.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgBitmapFill.java @@ -27,6 +27,8 @@ class SvgBitmapFill extends SvgFill { public String patternTransform; public int characterId; + + public boolean smoothed = true; @Override public Color toColor() { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java index 5e5bbada1..d5d440f64 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgImporter.java @@ -1892,7 +1892,7 @@ public class SvgImporter { } } else if (fill instanceof SvgBitmapFill) { SvgBitmapFill bfill = (SvgBitmapFill) fill; - fillStyle.fillStyleType = FILLSTYLE.REPEATING_BITMAP; + fillStyle.fillStyleType = bfill.smoothed ? FILLSTYLE.REPEATING_BITMAP : FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP; fillStyle.bitmapId = bfill.characterId; Matrix fillMatrix = Matrix.parseSvgMatrix(bfill.patternTransform, SWF.unitDivisor, SWF.unitDivisor); fillMatrix = transform.concatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).concatenate(fillMatrix); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java index f5fb8d54b..bd9900c52 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/svg/SvgStyle.java @@ -572,6 +572,17 @@ class SvgStyle { if (e.hasAttribute("patternTransform")) { bitmapFill.patternTransform = e.getAttribute("patternTransform"); } + if (e.hasAttribute("ffdec:smoothed")) { + String smoothedValue = e.getAttribute("ffdec:smoothed").trim(); + if ("true".equals(smoothedValue)) { + bitmapFill.smoothed = true; + } + if ("false".equals(smoothedValue)) { + bitmapFill.smoothed = false; + } + } else { + bitmapFill.smoothed = true; + } return bitmapFill; } @@ -618,6 +629,17 @@ class SvgStyle { if (e.hasAttribute("patternTransform")) { bitmapFill.patternTransform = e.getAttribute("patternTransform"); } + if (e.hasAttribute("ffdec:smoothed")) { + String smoothedValue = e.getAttribute("ffdec:smoothed").trim(); + if ("true".equals(smoothedValue)) { + bitmapFill.smoothed = true; + } + if ("false".equals(smoothedValue)) { + bitmapFill.smoothed = false; + } + } else { + bitmapFill.smoothed = true; + } cachedBitmaps.put(elementId, imageTag.characterID); return bitmapFill;