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 5bfbb62b0..bf7dfc8de 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 @@ -245,7 +245,7 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { } @Override - public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { + public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { finalizePath(); thickness /= SWF.unitDivisor; thicknessEnd /= SWF.unitDivisor; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java index 001e713f1..9cd3c1ec8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java @@ -92,7 +92,7 @@ public abstract class DefaultSVGMorphShapeExporter extends MorphShapeExporterBas } @Override - public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { + public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { finalizePath(); } 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 22cc49011..8f19641e6 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 @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.morphshape; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; @@ -46,7 +47,7 @@ public interface IMorphShapeExporter { public void endFill(); - public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit); + public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit); public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd); 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 6b74af96a..18631d07c 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 @@ -199,12 +199,10 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter { if (straightEdgeRecord.generalLineFlag) { xPos += straightEdgeRecord.deltaX; yPos += straightEdgeRecord.deltaY; + } else if (straightEdgeRecord.vertLineFlag) { + yPos += straightEdgeRecord.deltaY; } else { - if (straightEdgeRecord.vertLineFlag) { - yPos += straightEdgeRecord.deltaY; - } else { - xPos += straightEdgeRecord.deltaX; - } + xPos += straightEdgeRecord.deltaX; } StraightEdgeRecord straightEdgeRecordEnd = (StraightEdgeRecord) shapeRecordEnd; @@ -213,12 +211,10 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter { if (straightEdgeRecordEnd.generalLineFlag) { xPosEnd += straightEdgeRecordEnd.deltaX; yPosEnd += straightEdgeRecordEnd.deltaY; + } else if (straightEdgeRecordEnd.vertLineFlag) { + yPosEnd += straightEdgeRecordEnd.deltaY; } else { - if (straightEdgeRecordEnd.vertLineFlag) { - yPosEnd += straightEdgeRecordEnd.deltaY; - } else { - xPosEnd += straightEdgeRecordEnd.deltaX; - } + xPosEnd += straightEdgeRecordEnd.deltaX; } subPath.add(new StraightMorphEdge(xPosFrom, yPosFrom, xPos, yPos, xPosEndFrom, yPosEndFrom, xPosEnd, yPosEnd, currentLineStyleIdx, currentFillStyleIdx1)); @@ -397,7 +393,7 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter { int startCapStyle = LINESTYLE2.ROUND_CAP; int endCapStyle = LINESTYLE2.ROUND_CAP; int joinStyle = LINESTYLE2.ROUND_JOIN; - int miterLimitFactor = 3; + float miterLimitFactor = 3f; boolean hasFillFlag = false; if (lineStyle instanceof LINESTYLE2) { LINESTYLE2 lineStyle2 = (LINESTYLE2) lineStyle; 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 a28e7e993..63682b0e5 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 @@ -147,7 +147,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { } @Override - public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { + public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, float miterLimit) { finalizePath(); thickness *= zoom / SWF.unitDivisor; thicknessEnd *= zoom / SWF.unitDivisor; @@ -187,8 +187,8 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter { break; default: path.setAttribute("stroke-linejoin", "miter"); - if (miterLimit >= 1 && miterLimit != 4) { - path.setAttribute("stroke-miterlimit", Integer.toString(miterLimit)); + if (miterLimit >= 1 && miterLimit != 4f) { + path.setAttribute("stroke-miterlimit", Double.toString(miterLimit)); } break; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerPlugin.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerPlugin.java index 940142d19..825b1be5b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerPlugin.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/SWFDecompilerPlugin.java @@ -52,9 +52,10 @@ public class SWFDecompilerPlugin { private static final List listeners = new ArrayList<>(); - public static void loadPlugins() { + public static File getPluginsDir() { + File pluginPath = null; + try { - File pluginPath = null; String pluginPathConfig = Configuration.pluginPath.get(); if (pluginPathConfig != null && !pluginPathConfig.isEmpty()) { pluginPath = new File(pluginPathConfig); @@ -65,20 +66,25 @@ public class SWFDecompilerPlugin { File dir = f.getAbsoluteFile().getParentFile().getParentFile(); pluginPath = new File(Path.combine(dir.getPath(), "plugins")).getCanonicalFile(); } - - if (pluginPath.exists()) { - System.out.println("Loading plugins from " + pluginPath.getPath()); - File[] files = pluginPath.listFiles(); - if (files != null) { - for (File file : files) { - System.out.println("Loading plugin: " + file.getPath()); - loadPlugin(file.getPath()); - } - } - } } catch (IOException | URISyntaxException ex) { Logger.getLogger(SWFDecompilerPlugin.class.getName()).log(Level.SEVERE, null, ex); } + return pluginPath; + } + + public static void loadPlugins() { + File pluginPath = getPluginsDir(); + if (pluginPath != null && pluginPath.exists()) { + System.out.println("Loading plugins from " + pluginPath.getPath()); + File[] files = pluginPath.listFiles(); + if (files != null) { + for (File file : files) { + System.out.println("Loading plugin: " + file.getPath()); + loadPlugin(file.getPath()); + } + } + } + } public static void loadPlugin(String path) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java index 9f2bf130f..9761ab3fd 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ShapeImporter.java @@ -870,6 +870,9 @@ public class ShapeImporter { } private void processRect(int shapeNum, SHAPEWITHSTYLE shapes, Element childElement, Matrix transform, SvgStyle style) { + + Point startPoint = new Point(0, 0); + String attr = childElement.getAttribute("x"); double x = attr.length() > 0 ? Double.parseDouble(attr) : 0; @@ -909,6 +912,8 @@ public class ShapeImporter { scr.command = 'M'; scr.params = new double[]{x + width, y + ry}; pathCommands.add(scr); + startPoint.x = x + width; + startPoint.y = y + ry; double sqrt2RXHalf = Math.sqrt(2) * rx / 2; double sqrt2Minus1RX = (Math.sqrt(2) - 1) * rx; @@ -956,6 +961,8 @@ public class ShapeImporter { PathCommand scr = new PathCommand(); scr.command = 'M'; scr.params = new double[]{x, y}; + startPoint.x = x; + startPoint.y = y; pathCommands.add(scr); double[] points = new double[]{ @@ -973,6 +980,11 @@ public class ShapeImporter { } } + PathCommand serz = new PathCommand(); + serz.command = 'Z'; + serz.params = new double[]{startPoint.x, startPoint.y}; + pathCommands.add(serz); + processCommands(shapeNum, shapes, pathCommands, transform, style); } @@ -1093,183 +1105,194 @@ public class ShapeImporter { //Test for SVG public static void main(String[] args) throws IOException, InterruptedException { //svgTest("pservers-grad-01-b"); - svgTest("pservers-grad-05-b"); + svgTest("pservers-grad-07-b"); + } + + private void applyFillGradients(SvgFill fill, FILLSTYLE fillStyle, RECT bounds, StyleChangeRecord scr, Matrix transform, int shapeNum, SvgStyle style) { + if (fill == null || fillStyle == null) { + return; + } + if (fill instanceof SvgGradient) { + SvgGradient gfill = (SvgGradient) fill; + Matrix gradientMatrix = Matrix.parseSvgMatrix(gfill.gradientTransform, SWF.unitDivisor, 1); + gradientMatrix = transform.concatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).concatenate(gradientMatrix); + fillStyle.gradientMatrix = gradientMatrix.toMATRIX(); + if (fill instanceof SvgLinearGradient) { + SvgLinearGradient lgfill = (SvgLinearGradient) fill; + fillStyle.fillStyleType = FILLSTYLE.LINEAR_GRADIENT; + fillStyle.gradient = new GRADIENT(); + double x1; + if (lgfill.x1.endsWith("%")) { + x1 = Double.parseDouble(lgfill.x1.substring(0, lgfill.x1.length() - 1)) / 100; + } else { + x1 = Double.parseDouble(lgfill.x1); + } + //x1 = x1 - (-819.2); + + double y1; + if (lgfill.y1.endsWith("%")) { + y1 = Double.parseDouble(lgfill.y1.substring(0, lgfill.y1.length() - 1)) / 100; + } else { + y1 = Double.parseDouble(lgfill.y1); + } + double x2; + if (lgfill.x2.endsWith("%")) { + x2 = Double.parseDouble(lgfill.x2.substring(0, lgfill.x2.length() - 1)) / 100; + } else { + x2 = Double.parseDouble(lgfill.x2); + } + //x2 = x2 - 819.2; + double y2; + if (lgfill.y2.endsWith("%")) { + y2 = Double.parseDouble(lgfill.y2.substring(0, lgfill.y2.length() - 1)) / 100; + } else { + y2 = Double.parseDouble(lgfill.y2); + } + x1 = x1 * SWF.unitDivisor; + y1 = y1 * SWF.unitDivisor; + x2 = x2 * SWF.unitDivisor; + y2 = y2 * SWF.unitDivisor; + + Matrix boundingBoxMatrix = new Matrix(); + if (lgfill.gradientUnits == SvgGradientUnits.OBJECT_BOUNDING_BOX) { + boundingBoxMatrix.scaleX = (bounds.Xmax - bounds.Xmin) / SWF.unitDivisor; + boundingBoxMatrix.rotateSkew0 = 0; + boundingBoxMatrix.rotateSkew1 = 0; + boundingBoxMatrix.scaleY = (bounds.Ymax - bounds.Ymin) / SWF.unitDivisor; + boundingBoxMatrix.translateX = bounds.Xmin; + boundingBoxMatrix.translateY = bounds.Ymin; + } + + Matrix xyMatrix = new Matrix(); + xyMatrix.scaleX = x2 - x1; + xyMatrix.rotateSkew0 = y2 - y1; + xyMatrix.rotateSkew1 = -xyMatrix.rotateSkew0; + xyMatrix.scaleY = xyMatrix.scaleX; + + xyMatrix = xyMatrix.preConcatenate(boundingBoxMatrix); + + Matrix zeroStartMatrix = Matrix.getTranslateInstance(0.5, 0); + + Matrix scaleMatrix = Matrix.getScaleInstance(1 / 16384.0 / 2); + Matrix transMatrix = Matrix.getTranslateInstance(x1, y1); + + Matrix tMatrix = new Matrix(); + tMatrix = tMatrix.preConcatenate(scaleMatrix); + tMatrix = tMatrix.preConcatenate(zeroStartMatrix); + tMatrix = tMatrix.preConcatenate(xyMatrix); + + tMatrix = tMatrix.preConcatenate(transMatrix); + Point p1 = tMatrix.transform(new Point(-16384, 0)); + Point p2 = tMatrix.transform(new Point(16384, 0)); + + tMatrix = tMatrix.preConcatenate(new Matrix(fillStyle.gradientMatrix)); + fillStyle.gradientMatrix = tMatrix.toMATRIX(); + } else if (fill instanceof SvgRadialGradient) { + SvgRadialGradient rgfill = (SvgRadialGradient) fill; + double cx; + if (rgfill.cx.endsWith("%")) { + cx = Double.parseDouble(rgfill.cx.substring(0, rgfill.cx.length() - 1)) / 100; + } else { + cx = Double.parseDouble(rgfill.cx); + } + double cy; + if (rgfill.cy.endsWith("%")) { + cy = Double.parseDouble(rgfill.cy.substring(0, rgfill.cy.length() - 1)) / 100; + } else { + cy = Double.parseDouble(rgfill.cy); + } + + double r; + if (rgfill.r.endsWith("%")) { + r = Double.parseDouble(rgfill.r.substring(0, rgfill.r.length() - 1)) / 100; + } else { + r = Double.parseDouble(rgfill.r); + } + + Matrix boundingBoxMatrix = new Matrix(); + if (rgfill.gradientUnits == SvgGradientUnits.OBJECT_BOUNDING_BOX) { + boundingBoxMatrix.scaleX = (bounds.Xmax - bounds.Xmin) / SWF.unitDivisor; + boundingBoxMatrix.rotateSkew0 = 0; + boundingBoxMatrix.rotateSkew1 = 0; + boundingBoxMatrix.scaleY = (bounds.Ymax - bounds.Ymin) / SWF.unitDivisor; + boundingBoxMatrix.translateX = bounds.Xmin; + boundingBoxMatrix.translateY = bounds.Ymin; + } + + fillStyle.gradientMatrix = Matrix.getTranslateInstance(SWF.unitDivisor * cx, SWF.unitDivisor * cy).concatenate(new Matrix(fillStyle.gradientMatrix)).concatenate(Matrix.getScaleInstance(r / 819.2)).preConcatenate(boundingBoxMatrix).toMATRIX(); + + double fx; + if (rgfill.fx.endsWith("%")) { + fx = Double.parseDouble(rgfill.fx.substring(0, rgfill.fx.length() - 1)) / 100; + } else { + fx = Double.parseDouble(rgfill.fx); + } + double fy; + if (rgfill.fy.endsWith("%")) { + fy = Double.parseDouble(rgfill.fy.substring(0, rgfill.fy.length() - 1)) / 100; + } else { + fy = Double.parseDouble(rgfill.fy); + } + if (!rgfill.fx.equals(rgfill.cx) || !rgfill.fy.equals(rgfill.cy)) { + fillStyle.fillStyleType = FILLSTYLE.FOCAL_RADIAL_GRADIENT; + fillStyle.gradient = new FOCALGRADIENT(); + FOCALGRADIENT fg = (FOCALGRADIENT) fillStyle.gradient; + double f = Math.sqrt((fx - cx) * (fx - cx) + (fy - cy) * (fy - cy)) / 819.2; + fg.focalPoint = (float) f; + } else { + fillStyle.fillStyleType = FILLSTYLE.RADIAL_GRADIENT; + fillStyle.gradient = new GRADIENT(); + } + } + switch (gfill.spreadMethod) { + case PAD: + fillStyle.gradient.spreadMode = GRADIENT.SPREAD_PAD_MODE; + break; + case REFLECT: + fillStyle.gradient.spreadMode = GRADIENT.SPREAD_REFLECT_MODE; + break; + case REPEAT: + fillStyle.gradient.spreadMode = GRADIENT.SPREAD_REPEAT_MODE; + break; + } + switch (gfill.interpolation) { + case LINEAR_RGB: + fillStyle.gradient.interpolationMode = GRADIENT.INTERPOLATION_LINEAR_RGB_MODE; + break; + case SRGB: + fillStyle.gradient.interpolationMode = GRADIENT.INTERPOLATION_RGB_MODE; + break; + } + + fillStyle.gradient.gradientRecords = new GRADRECORD[gfill.stops.size()]; + for (int i = 0; i < gfill.stops.size(); i++) { + SvgStop stop = gfill.stops.get(i); + Color color = stop.color; + color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) Math.round(color.getAlpha() * style.opacity)); + fillStyle.gradient.gradientRecords[i] = new GRADRECORD(); + fillStyle.gradient.gradientRecords[i].inShape3 = shapeNum >= 3; + fillStyle.gradient.gradientRecords[i].color = getRGB(shapeNum, color); + fillStyle.gradient.gradientRecords[i].ratio = (int) Math.round(stop.offset * 255); + } + } else if (fill instanceof SvgBitmapFill) { + SvgBitmapFill bfill = (SvgBitmapFill) fill; + fillStyle.fillStyleType = FILLSTYLE.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); + fillStyle.bitmapMatrix = fillMatrix.toMATRIX(); + } } private void applyStyleGradients(RECT bounds, StyleChangeRecord scr, Matrix transform, int shapeNum, SvgStyle style) { SvgFill fill = style.getFillWithOpacity(); if (fill != null) { - if (fill instanceof SvgGradient) { - FILLSTYLE fillStyle = scr.fillStyles.fillStyles[0]; - SvgGradient gfill = (SvgGradient) fill; - Matrix gradientMatrix = Matrix.parseSvgMatrix(gfill.gradientTransform, SWF.unitDivisor, 1); - gradientMatrix = transform.concatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).concatenate(gradientMatrix); - fillStyle.gradientMatrix = gradientMatrix.toMATRIX(); - if (fill instanceof SvgLinearGradient) { - SvgLinearGradient lgfill = (SvgLinearGradient) fill; - fillStyle.fillStyleType = FILLSTYLE.LINEAR_GRADIENT; - fillStyle.gradient = new GRADIENT(); - double x1; - if (lgfill.x1.endsWith("%")) { - x1 = Double.parseDouble(lgfill.x1.substring(0, lgfill.x1.length() - 1)) / 100; - } else { - x1 = Double.parseDouble(lgfill.x1); - } - //x1 = x1 - (-819.2); - - double y1; - if (lgfill.y1.endsWith("%")) { - y1 = Double.parseDouble(lgfill.y1.substring(0, lgfill.y1.length() - 1)) / 100; - } else { - y1 = Double.parseDouble(lgfill.y1); - } - double x2; - if (lgfill.x2.endsWith("%")) { - x2 = Double.parseDouble(lgfill.x2.substring(0, lgfill.x2.length() - 1)) / 100; - } else { - x2 = Double.parseDouble(lgfill.x2); - } - //x2 = x2 - 819.2; - double y2; - if (lgfill.y2.endsWith("%")) { - y2 = Double.parseDouble(lgfill.y2.substring(0, lgfill.y2.length() - 1)) / 100; - } else { - y2 = Double.parseDouble(lgfill.y2); - } - x1 = x1 * SWF.unitDivisor; - y1 = y1 * SWF.unitDivisor; - x2 = x2 * SWF.unitDivisor; - y2 = y2 * SWF.unitDivisor; - - Matrix boundingBoxMatrix = new Matrix(); - if (lgfill.gradientUnits == SvgGradientUnits.OBJECT_BOUNDING_BOX) { - boundingBoxMatrix.scaleX = (bounds.Xmax - bounds.Xmin) / SWF.unitDivisor; - boundingBoxMatrix.rotateSkew0 = 0; - boundingBoxMatrix.rotateSkew1 = 0; - boundingBoxMatrix.scaleY = (bounds.Ymax - bounds.Ymin) / SWF.unitDivisor; - boundingBoxMatrix.translateX = bounds.Xmin; - boundingBoxMatrix.translateY = bounds.Ymin; - } - - Matrix xyMatrix = new Matrix(); - xyMatrix.scaleX = x2 - x1; - xyMatrix.rotateSkew0 = y2 - y1; - xyMatrix.rotateSkew1 = -xyMatrix.rotateSkew0; - xyMatrix.scaleY = xyMatrix.scaleX; - - xyMatrix = xyMatrix.preConcatenate(boundingBoxMatrix); - - Matrix zeroStartMatrix = Matrix.getTranslateInstance(0.5, 0); - - Matrix scaleMatrix = Matrix.getScaleInstance(1 / 16384.0 / 2); - Matrix transMatrix = Matrix.getTranslateInstance(x1, y1); - - Matrix tMatrix = new Matrix(); - tMatrix = tMatrix.preConcatenate(scaleMatrix); - tMatrix = tMatrix.preConcatenate(zeroStartMatrix); - tMatrix = tMatrix.preConcatenate(xyMatrix); - - tMatrix = tMatrix.preConcatenate(transMatrix); - Point p1 = tMatrix.transform(new Point(-16384, 0)); - Point p2 = tMatrix.transform(new Point(16384, 0)); - - tMatrix = tMatrix.preConcatenate(new Matrix(fillStyle.gradientMatrix)); - fillStyle.gradientMatrix = tMatrix.toMATRIX(); - } else if (fill instanceof SvgRadialGradient) { - SvgRadialGradient rgfill = (SvgRadialGradient) fill; - double cx; - if (rgfill.cx.endsWith("%")) { - cx = Double.parseDouble(rgfill.cx.substring(0, rgfill.cx.length() - 1)) / 100; - } else { - cx = Double.parseDouble(rgfill.cx); - } - double cy; - if (rgfill.cy.endsWith("%")) { - cy = Double.parseDouble(rgfill.cy.substring(0, rgfill.cy.length() - 1)) / 100; - } else { - cy = Double.parseDouble(rgfill.cy); - } - - double r; - if (rgfill.r.endsWith("%")) { - r = Double.parseDouble(rgfill.r.substring(0, rgfill.r.length() - 1)) / 100; - } else { - r = Double.parseDouble(rgfill.r); - } - - Matrix boundingBoxMatrix = new Matrix(); - if (rgfill.gradientUnits == SvgGradientUnits.OBJECT_BOUNDING_BOX) { - boundingBoxMatrix.scaleX = (bounds.Xmax - bounds.Xmin) / SWF.unitDivisor; - boundingBoxMatrix.rotateSkew0 = 0; - boundingBoxMatrix.rotateSkew1 = 0; - boundingBoxMatrix.scaleY = (bounds.Ymax - bounds.Ymin) / SWF.unitDivisor; - boundingBoxMatrix.translateX = bounds.Xmin; - boundingBoxMatrix.translateY = bounds.Ymin; - } - - fillStyle.gradientMatrix = Matrix.getTranslateInstance(SWF.unitDivisor * cx, SWF.unitDivisor * cy).concatenate(new Matrix(fillStyle.gradientMatrix)).concatenate(Matrix.getScaleInstance(r / 819.2)).preConcatenate(boundingBoxMatrix).toMATRIX(); - - double fx; - if (rgfill.fx.endsWith("%")) { - fx = Double.parseDouble(rgfill.fx.substring(0, rgfill.fx.length() - 1)) / 100; - } else { - fx = Double.parseDouble(rgfill.fx); - } - double fy; - if (rgfill.fy.endsWith("%")) { - fy = Double.parseDouble(rgfill.fy.substring(0, rgfill.fy.length() - 1)) / 100; - } else { - fy = Double.parseDouble(rgfill.fy); - } - if (!rgfill.fx.equals(rgfill.cx) || !rgfill.fy.equals(rgfill.cy)) { - fillStyle.fillStyleType = FILLSTYLE.FOCAL_RADIAL_GRADIENT; - fillStyle.gradient = new FOCALGRADIENT(); - FOCALGRADIENT fg = (FOCALGRADIENT) fillStyle.gradient; - double f = Math.sqrt((fx - cx) * (fx - cx) + (fy - cy) * (fy - cy)) / 819.2; - fg.focalPoint = (float) f; - } else { - fillStyle.fillStyleType = FILLSTYLE.RADIAL_GRADIENT; - fillStyle.gradient = new GRADIENT(); - } - } - switch (gfill.spreadMethod) { - case PAD: - fillStyle.gradient.spreadMode = GRADIENT.SPREAD_PAD_MODE; - break; - case REFLECT: - fillStyle.gradient.spreadMode = GRADIENT.SPREAD_REFLECT_MODE; - break; - case REPEAT: - fillStyle.gradient.spreadMode = GRADIENT.SPREAD_REPEAT_MODE; - break; - } - switch (gfill.interpolation) { - case LINEAR_RGB: - fillStyle.gradient.interpolationMode = GRADIENT.INTERPOLATION_LINEAR_RGB_MODE; - break; - case SRGB: - fillStyle.gradient.interpolationMode = GRADIENT.INTERPOLATION_RGB_MODE; - break; - } - - fillStyle.gradient.gradientRecords = new GRADRECORD[gfill.stops.size()]; - for (int i = 0; i < gfill.stops.size(); i++) { - SvgStop stop = gfill.stops.get(i); - Color color = stop.color; - color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) Math.round(color.getAlpha() * style.opacity)); - fillStyle.gradient.gradientRecords[i] = new GRADRECORD(); - fillStyle.gradient.gradientRecords[i].inShape3 = shapeNum >= 3; - fillStyle.gradient.gradientRecords[i].color = getRGB(shapeNum, color); - fillStyle.gradient.gradientRecords[i].ratio = (int) Math.round(stop.offset * 255); - } - } else if (fill instanceof SvgBitmapFill) { - FILLSTYLE fillStyle = scr.fillStyles.fillStyles[0]; - SvgBitmapFill bfill = (SvgBitmapFill) fill; - fillStyle.fillStyleType = FILLSTYLE.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); - fillStyle.bitmapMatrix = fillMatrix.toMATRIX(); + applyFillGradients(fill, scr.fillStyles.fillStyles[0], bounds, scr, transform, shapeNum, style); + } + SvgFill strokeFill = style.getStrokeFillWithOpacity(); + if (strokeFill != null) { + if (scr.lineStyles.lineStyles.length > 0 && scr.lineStyles.lineStyles[0] instanceof LINESTYLE2) { + applyFillGradients(strokeFill, ((LINESTYLE2) scr.lineStyles.lineStyles[0]).fillType, bounds, scr, transform, shapeNum, style); } } } @@ -1300,7 +1323,7 @@ public class ShapeImporter { } scr.lineStyles = new LINESTYLEARRAY(); - SvgFill strokeFill = style.getStrokeColorWithOpacity(); + SvgFill strokeFill = style.getStrokeFillWithOpacity(); if (strokeFill != null) { Color lineColor = strokeFill.toColor(); @@ -1317,12 +1340,17 @@ public class ShapeImporter { : lineCap == SvgLineCap.SQUARE ? LINESTYLE2.SQUARE_CAP : 0; lineStyle2.startCapStyle = swfCap; lineStyle2.endCapStyle = swfCap; + if (!(strokeFill instanceof SvgColor)) { + lineStyle2.hasFillFlag = true; + lineStyle2.fillType = new FILLSTYLE(); + //...apply in second step - applyStyleGradients + }//Single color does not need fillType attribute int swfJoin = lineJoin == SvgLineJoin.MITER ? LINESTYLE2.MITER_JOIN : lineJoin == SvgLineJoin.ROUND ? LINESTYLE2.ROUND_JOIN : lineJoin == SvgLineJoin.BEVEL ? LINESTYLE2.BEVEL_JOIN : 0; lineStyle2.joinStyle = swfJoin; - lineStyle2.miterLimitFactor = (int) Math.round(style.strokeMiterLimit * 256); + lineStyle2.miterLimitFactor = (float) style.strokeMiterLimit; } else { if (lineCap != SvgLineCap.ROUND) { showWarning("lineCapNotSupported", "LineCap style not supported in shape " + shapeNum); @@ -2185,6 +2213,23 @@ public class ShapeImporter { return new SvgColor(fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(), opacity); } + public SvgFill getStrokeFillWithOpacity() { + if (strokeFill == null) { + return null; + } + if (!(strokeFill instanceof SvgColor)) { + return strokeFill; + } + Color strokeFillColor = ((SvgColor) strokeFill).color; + + int opacity = (int) Math.round(this.opacity * strokeOpacity * 255); + if (opacity == 255) { + return strokeFill; + } + + return new SvgColor(strokeFillColor.getRed(), strokeFillColor.getGreen(), strokeFillColor.getBlue(), opacity); + } + public SvgFill getStrokeColorWithOpacity() { if (strokeFill == null) { return null; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index ac3d67571..25fbd845a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -63,9 +63,9 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable { @SWFType(value = BasicType.UB, count = 2) public int endCapStyle; - @SWFType(BasicType.UI16) + @SWFType(BasicType.FIXED8) @Conditional(value = "joinStyle", options = MITER_JOIN) - public int miterLimitFactor; + public float miterLimitFactor; public FILLSTYLE fillType; 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 9d5db8b79..aa14ade00 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 @@ -216,8 +216,8 @@ public class XFLConverter { + "" - + "" - + ""); + + "" + + ""); } private static void convertLineStyle(HashMap characters, LINESTYLE2 ls, int shapeNum, StringBuilder ret) { @@ -250,7 +250,7 @@ public class XFLConverter { break; case LINESTYLE2.MITER_JOIN: params.append(" joints=\"miter\""); - float miterLimitFactor = toFloat(ls.miterLimitFactor); + float miterLimitFactor = ls.miterLimitFactor; if (miterLimitFactor != 3.0f) { params.append(" miterLimit=\"").append(miterLimitFactor).append("\""); } @@ -274,10 +274,6 @@ public class XFLConverter { ret.append(""); } - private static float toFloat(int i) { - return ((float) i) / (1 << 16); - } - private static void convertFillStyle(MATRIX mat, HashMap characters, FILLSTYLE fs, int shapeNum, StringBuilder ret) { /* todo: use matrix if (mat == null) { @@ -2183,7 +2179,7 @@ public class XFLConverter { if (ret2.length() > 0) { ret.append("" + "").append(ret2).append("" - + ""); + + ""); } }