diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java
index 66bfc8b38..55a78e147 100644
--- a/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java
+++ b/trunk/src/com/jpexs/decompiler/flash/SWFInputStream.java
@@ -1871,7 +1871,7 @@ public class SWFInputStream extends InputStream {
GRADRECORD ret = new GRADRECORD();
ret.ratio = readUI8();
if (shapeNum >= 3) {
- ret.colorA = readRGBA();
+ ret.color = readRGBA();
} else {
ret.color = readRGB();
}
@@ -1888,7 +1888,7 @@ public class SWFInputStream extends InputStream {
public GRADIENT readGRADIENT(int shapeNum) throws IOException {
GRADIENT ret = new GRADIENT();
ret.spreadMode = (int) readUB(2);
- ret.interPolationMode = (int) readUB(2);
+ ret.interpolationMode = (int) readUB(2);
int numGradients = (int) readUB(4);
ret.gradientRecords = new GRADRECORD[numGradients];
for (int i = 0; i < numGradients; i++) {
@@ -1908,7 +1908,7 @@ public class SWFInputStream extends InputStream {
public FOCALGRADIENT readFOCALGRADIENT(int shapeNum) throws IOException {
FOCALGRADIENT ret = new FOCALGRADIENT();
ret.spreadMode = (int) readUB(2);
- ret.interPolationMode = (int) readUB(2);
+ ret.interpolationMode = (int) readUB(2);
int numGradients = (int) readUB(4);
ret.gradientRecords = new GRADRECORD[numGradients];
for (int i = 0; i < numGradients; i++) {
@@ -1930,7 +1930,7 @@ public class SWFInputStream extends InputStream {
ret.fillStyleType = readUI8();
if (ret.fillStyleType == FILLSTYLE.SOLID) {
if (shapeNum >= 3) {
- ret.colorA = readRGBA();
+ ret.color = readRGBA();
} else {
ret.color = readRGB();
}
@@ -1945,7 +1945,7 @@ public class SWFInputStream extends InputStream {
ret.gradient = readGRADIENT(shapeNum);
}
if (ret.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
- ret.focalGradient = readFOCALGRADIENT(shapeNum);
+ ret.gradient = readFOCALGRADIENT(shapeNum);
}
if ((ret.fillStyleType == FILLSTYLE.REPEATING_BITMAP)
@@ -1993,7 +1993,7 @@ public class SWFInputStream extends InputStream {
ret.color = readRGB();
}
if (shapeNum == 3) {
- ret.colorA = readRGBA();
+ ret.color = readRGBA();
}
return ret;
}
@@ -2047,9 +2047,9 @@ public class SWFInputStream extends InputStream {
ret.lineStyles[i] = readLINESTYLE(shapeNum);
}
} else if (shapeNum == 4) {
- ret.lineStyles2 = new LINESTYLE2[lineStyleCount];
+ ret.lineStyles = new LINESTYLE2[lineStyleCount];
for (int i = 0; i < lineStyleCount; i++) {
- ret.lineStyles2[i] = readLINESTYLE2(shapeNum);
+ ret.lineStyles[i] = readLINESTYLE2(shapeNum);
}
}
return ret;
diff --git a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java
index 5b4ae6826..3f7ae4f70 100644
--- a/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java
+++ b/trunk/src/com/jpexs/decompiler/flash/SWFOutputStream.java
@@ -1035,7 +1035,7 @@ public class SWFOutputStream extends OutputStream {
writeUI8(value.fillStyleType);
if (value.fillStyleType == FILLSTYLE.SOLID) {
if (shapeNum >= 3) {
- writeRGBA(value.colorA);
+ writeRGBA((RGBA) value.color);
} else if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
}
@@ -1050,7 +1050,7 @@ public class SWFOutputStream extends OutputStream {
writeGRADIENT(value.gradient, shapeNum);
}
if (value.fillStyleType == FILLSTYLE.FOCAL_RADIAL_GRADIENT) {
- writeFOCALGRADIENT(value.focalGradient, shapeNum);
+ writeFOCALGRADIENT((FOCALGRADIENT) value.gradient, shapeNum);
}
if ((value.fillStyleType == FILLSTYLE.REPEATING_BITMAP)
@@ -1095,7 +1095,7 @@ public class SWFOutputStream extends OutputStream {
*/
public void writeFOCALGRADIENT(FOCALGRADIENT value, int shapeNum) throws IOException {
writeUB(2, value.spreadMode);
- writeUB(2, value.interPolationMode);
+ writeUB(2, value.interpolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeGRADRECORD(value.gradientRecords[i], shapeNum);
@@ -1112,7 +1112,7 @@ public class SWFOutputStream extends OutputStream {
*/
public void writeGRADIENT(GRADIENT value, int shapeNum) throws IOException {
writeUB(2, value.spreadMode);
- writeUB(2, value.interPolationMode);
+ writeUB(2, value.interpolationMode);
writeUB(4, value.gradientRecords.length);
for (int i = 0; i < value.gradientRecords.length; i++) {
writeGRADRECORD(value.gradientRecords[i], shapeNum);
@@ -1131,7 +1131,7 @@ public class SWFOutputStream extends OutputStream {
if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
} else if (shapeNum == 3) {
- writeRGBA(value.colorA);
+ writeRGBA((RGBA) value.color);
}
}
@@ -1147,7 +1147,7 @@ public class SWFOutputStream extends OutputStream {
if (shapeNum == 1 || shapeNum == 2) {
writeRGB(value.color);
} else if (shapeNum == 3) {
- writeRGBA(value.colorA);
+ writeRGBA((RGBA) value.color);
}
}
@@ -1173,7 +1173,7 @@ public class SWFOutputStream extends OutputStream {
writeUI16(value.miterLimitFactor);
}
if (!value.hasFillFlag) {
- writeRGBA(value.color);
+ writeRGBA((RGBA) value.color);
} else {
writeFILLSTYLE(value.fillType, shapeNum);
}
@@ -1200,7 +1200,7 @@ public class SWFOutputStream extends OutputStream {
writeLINESTYLE(value.lineStyles[i], shapeNum);
}
} else if (shapeNum == 4) {
- lineStyleCount = value.lineStyles2.length;
+ lineStyleCount = value.lineStyles.length;
if (lineStyleCount >= 0xff) {
writeUI8(0xff);
writeUI16(lineStyleCount);
@@ -1208,7 +1208,7 @@ public class SWFOutputStream extends OutputStream {
writeUI8(lineStyleCount);
}
for (int i = 0; i < lineStyleCount; i++) {
- writeLINESTYLE2(value.lineStyles2[i], shapeNum);
+ writeLINESTYLE2((LINESTYLE2) value.lineStyles[i], shapeNum);
}
}
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java b/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java
new file mode 100644
index 000000000..a5de4833f
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/CurvedEdge.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class CurvedEdge extends StraightEdge implements IEdge {
+
+ private Point control;
+
+ CurvedEdge(Point from, Point control, Point to, int lineStyleIdx, int fillStyleIdx) {
+ super(from, to, lineStyleIdx, fillStyleIdx);
+ this.control = control;
+ }
+
+ public Point getControl() {
+ return control;
+ }
+
+ @Override
+ public IEdge reverseWithNewFillStyle(int newFillStyleIdx) {
+ return new CurvedEdge(to, control, from, lineStyleIdx, newFillStyleIdx);
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java
new file mode 100644
index 000000000..7f3215150
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/DefaultSVGShapeExporter.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+import com.jpexs.decompiler.flash.tags.base.ShapeTag;
+import com.jpexs.decompiler.flash.types.MATRIX;
+import com.jpexs.decompiler.flash.types.RGB;
+import java.util.List;
+
+/**
+ *
+ * @author JPEXS, Claus Wahlers
+ */
+public class DefaultSVGShapeExporter extends ShapeExporterBase implements IShapeExporter {
+
+ protected static final String DRAW_COMMAND_L = "L";
+ protected static final String DRAW_COMMAND_Q = "Q";
+
+ protected String currentDrawCommand = "";
+ protected String pathData;
+
+ public DefaultSVGShapeExporter(ShapeTag tag) {
+ super(tag);
+ }
+
+ @Override
+ public void beginShape() {
+ }
+
+ @Override
+ public void endShape(double xMin, double yMin, double xMax, double yMax) {
+ }
+
+ @Override
+ public void beginFills() {
+ }
+
+ @Override
+ public void endFills() {
+ }
+
+ @Override
+ public void beginLines() {
+ }
+
+ @Override
+ public void endLines() {
+ finalizePath();
+ }
+
+ @Override
+ public void beginFill(RGB color) {
+ finalizePath();
+ }
+
+ @Override
+ public void beginGradientFill(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ finalizePath();
+ }
+
+ @Override
+ public void beginBitmapFill(int bitmapId, MATRIX matrix, boolean repeat, boolean smooth) {
+ finalizePath();
+ }
+
+ @Override
+ public void endFill() {
+ finalizePath();
+ }
+
+ @Override
+ public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
+ finalizePath();
+ }
+
+ @Override
+ public void lineGradientStyle(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ }
+
+ @Override
+ public void moveTo(double x, double y) {
+ currentDrawCommand = "";
+ pathData += "M"
+ + roundPixels20(x) + " "
+ + roundPixels20(y) + " ";
+ }
+
+ @Override
+ public void lineTo(double x, double y) {
+ if (currentDrawCommand != DRAW_COMMAND_L) {
+ currentDrawCommand = DRAW_COMMAND_L;
+ pathData += "L";
+ }
+ pathData += roundPixels20(x) + " "
+ + roundPixels20(y) + " ";
+ }
+
+ @Override
+ public void curveTo(double controlX, double controlY, double anchorX, double anchorY) {
+ if (currentDrawCommand != DRAW_COMMAND_Q) {
+ currentDrawCommand = DRAW_COMMAND_Q;
+ pathData += "Q";
+ }
+ pathData += roundPixels20(controlX) + " "
+ + roundPixels20(controlY) + " "
+ + roundPixels20(anchorX) + " "
+ + roundPixels20(anchorY) + " ";
+ }
+
+ protected void finalizePath() {
+ pathData = "";
+ currentDrawCommand = "";
+ }
+
+ protected double roundPixels20(double pixels) {
+ return Math.round(pixels * 100) / 100.0;
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/IEdge.java b/trunk/src/com/jpexs/decompiler/flash/exporters/IEdge.java
new file mode 100644
index 000000000..1c7342308
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/IEdge.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+/**
+ *
+ * @author JPEXS
+ */
+public interface IEdge {
+
+ public Point getFrom();
+
+ public Point getTo();
+
+ public int getLineStyleIdx();
+
+ public int getFillStyleIdx();
+
+ public IEdge reverseWithNewFillStyle(int newFillStyleIdx);
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java
new file mode 100644
index 000000000..05c25826c
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/IShapeExporter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+import com.jpexs.decompiler.flash.types.MATRIX;
+import com.jpexs.decompiler.flash.types.RGB;
+import java.util.List;
+
+/**
+ *
+ * @author JPEXS
+ */
+public interface IShapeExporter {
+
+ public void beginShape();
+
+ public void endShape(double xMin, double yMin, double xMax, double yMax);
+
+ public void beginFills();
+
+ public void endFills();
+
+ public void beginLines();
+
+ public void endLines();
+
+ public void beginFill(RGB color);
+
+ public void beginGradientFill(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
+
+ public void beginBitmapFill(int bitmapId, MATRIX matrix, boolean repeat, boolean smooth);
+
+ public void endFill();
+
+ public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit);
+
+ public void lineGradientStyle(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio);
+
+ public void moveTo(double x, double y);
+
+ public void lineTo(double x, double y);
+
+ public void curveTo(double controlX, double controlY, double anchorX, double anchorY);
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java b/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java
new file mode 100644
index 000000000..e903a4d74
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/Point.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class Point {
+
+ public double x;
+ public double y;
+
+ Point(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public int hashCode() {
+ long bits = Double.doubleToLongBits(x);
+ bits ^= Double.doubleToLongBits(y) * 31;
+ return (((int) bits) ^ ((int) (bits >> 32)));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Point) {
+ Point pt = (Point) obj;
+ return (x == pt.x) && (y == pt.y);
+ }
+ return super.equals(obj);
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java b/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java
new file mode 100644
index 000000000..95944ce3c
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/Rectangle.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class Rectangle {
+
+ public double xMin;
+ public double yMin;
+ public double xMax;
+ public double yMax;
+
+ Rectangle(double xMin, double yMin, double xMax, double yMax) {
+ this.xMin = xMin;
+ this.yMin = yMin;
+ this.xMax = xMax;
+ this.yMax = yMax;
+ }
+
+ public int hashCode() {
+ long bits = Double.doubleToLongBits(xMin);
+ bits += Double.doubleToLongBits(yMin) * 37;
+ bits += Double.doubleToLongBits(xMax) * 43;
+ bits += Double.doubleToLongBits(yMax) * 47;
+ return (((int) bits) ^ ((int) (bits >> 32)));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Rectangle) {
+ Rectangle r = (Rectangle) obj;
+ return (xMin == r.xMin) && (yMin == r.yMin) && (xMax == r.xMax) && (yMax == r.yMax);
+ }
+ return super.equals(obj);
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java
new file mode 100644
index 000000000..5c7c3fdb1
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/SVGShapeExporter.java
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+import com.jpexs.decompiler.flash.SWF;
+import com.jpexs.decompiler.flash.tags.Tag;
+import com.jpexs.decompiler.flash.tags.base.ImageTag;
+import com.jpexs.decompiler.flash.tags.base.ShapeTag;
+import com.jpexs.decompiler.flash.types.FILLSTYLE;
+import com.jpexs.decompiler.flash.types.GRADIENT;
+import com.jpexs.decompiler.flash.types.LINESTYLE2;
+import com.jpexs.decompiler.flash.types.MATRIX;
+import com.jpexs.decompiler.flash.types.RGB;
+import com.jpexs.decompiler.flash.types.RGBA;
+import com.jpexs.helpers.Helper;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.imageio.ImageIO;
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Element;
+
+/**
+ *
+ * @author JPEXS, Claus Wahlers
+ */
+public class SVGShapeExporter extends DefaultSVGShapeExporter {
+
+ protected static final String sNamespace = "http://www.w3.org/2000/svg";
+ protected static final String xlinkNamespace = "http://www.w3.org/1999/xlink";
+
+ protected Document _svg;
+ protected Element _svgDefs;
+ protected Element _svgG;
+ protected Element path;
+ protected List gradients;
+ protected int lastPatternId;
+ private SWF swf;
+
+ public SVGShapeExporter(SWF swf, ShapeTag tag) {
+ super(tag);
+ this.swf = swf;
+ }
+
+ public String getSVG() {
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ StringWriter writer = new StringWriter();
+ try {
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ DOMSource source = new DOMSource(_svg);
+ StreamResult result = new StreamResult(writer);
+ transformer.transform(source, result);
+ } catch (TransformerException ex) {
+ Logger.getLogger(SVGShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ return writer.toString();
+ }
+
+ @Override
+ public void beginShape() {
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ DOMImplementation impl = docBuilder.getDOMImplementation();
+ DocumentType svgDocType = impl.createDocumentType("svg", "-//W3C//DTD SVG 1.0//EN",
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
+ _svg = impl.createDocument(sNamespace, "svg", svgDocType);
+ Element svgRoot = _svg.getDocumentElement();
+ svgRoot.setAttribute("xmlns:xlink", xlinkNamespace);
+ _svgDefs = _svg.createElement("defs");
+ svgRoot.appendChild(_svgDefs);
+ _svgG = _svg.createElement("g");
+ svgRoot.appendChild(_svgG);
+ } catch (ParserConfigurationException ex) {
+ Logger.getLogger(SVGShapeExporter.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ gradients = new ArrayList<>();
+ }
+
+ @Override
+ public void endShape(double xMin, double yMin, double xMax, double yMax) {
+ _svgG.setAttribute("transform", "matrix(1, 0, 0, 1, "
+ + roundPixels20(-xMin) + ", " + roundPixels20(-yMin) + ")");
+ }
+
+ @Override
+ public void beginFill(RGB color) {
+ finalizePath();
+ path.setAttribute("stroke", "none");
+ path.setAttribute("fill", color.toHexRGB());
+ if (color instanceof RGBA) {
+ RGBA colorA = (RGBA) color;
+ if (colorA.alpha != 255) {
+ path.setAttribute("fill-opacity", Float.toString(colorA.getAlphaFloat()));
+ }
+ }
+ }
+
+ @Override
+ public void beginGradientFill(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ finalizePath();
+ Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
+ ? _svg.createElement("linearGradient")
+ : _svg.createElement("radialGradient");
+ populateGradientElement(gradient, type, colors, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio);
+ int id = gradients.indexOf(gradient);
+ if (id < 0) {
+ // todo: filter same gradients
+ id = gradients.size();
+ gradients.add(gradient);
+ }
+ gradient.setAttribute("id", "gradient" + id);
+ path.setAttribute("stroke", "none");
+ path.setAttribute("fill", "url(#gradient" + id + ")");
+ _svgDefs.appendChild(gradient);
+ }
+
+ @Override
+ public void beginBitmapFill(int bitmapId, MATRIX matrix, boolean repeat, boolean smooth) {
+ finalizePath();
+ ImageTag image = null;
+ for (Tag t : swf.tags) {
+ if (t instanceof ImageTag) {
+ ImageTag i = (ImageTag) t;
+ if (i.getCharacterId() == bitmapId) {
+ image = i;
+ break;
+ }
+ }
+ }
+ if (image != null) {
+ BufferedImage img = image.getImage(swf.tags);
+ if (img != null) {
+ int width = img.getWidth();
+ int height = img.getHeight();
+ lastPatternId++;
+ String patternId = "PatternID_" + lastPatternId;
+ String format = image.getImageFormat();
+ InputStream imageStream = image.getImageData();
+ byte[] imageData;
+ if (imageStream != null) {
+ imageData = Helper.readStream(image.getImageData());
+ } else {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ ImageIO.write(img, format.toUpperCase(Locale.ENGLISH), baos);
+ } catch (IOException ex) {
+ }
+ imageData = baos.toByteArray();
+ }
+ String base64ImgData = DatatypeConverter.printBase64Binary(imageData);
+ float translateX = 0;
+ float translateY = 0;
+ float rotateSkew0 = 0;
+ float rotateSkew1 = 0;
+ float scaleX = 1;
+ float scaleY = 1;
+ if (matrix != null) {
+ translateX = SWF.twipToPixel(matrix.translateX);
+ translateY = SWF.twipToPixel(matrix.translateY);
+ if (matrix.hasRotate) {
+ rotateSkew0 = matrix.getRotateSkew0Float();
+ rotateSkew1 = matrix.getRotateSkew1Float();
+ }
+ if (matrix.hasScale) {
+ scaleX = SWF.twipToPixel((int) matrix.getScaleXFloat());
+ scaleY = SWF.twipToPixel((int) matrix.getScaleYFloat());
+ }
+ }
+ path.setAttribute("style", "fill:url(#" + patternId + ")");
+ Element pattern = _svg.createElement("pattern");
+ pattern.setAttribute("id", patternId);
+ pattern.setAttribute("patternUnits", "userSpaceOnUse");
+ pattern.setAttribute("overflow", "visible");
+ pattern.setAttribute("width", "" + width);
+ pattern.setAttribute("height", "" + height);
+ pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
+ pattern.setAttribute("patternTransform", "matrix(" + scaleX + ", " + rotateSkew0
+ + ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")");
+ Element imageElement = _svg.createElement("image");
+ imageElement.setAttribute("width", "" + width);
+ imageElement.setAttribute("height", "" + height);
+ imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
+ pattern.appendChild(imageElement);
+ _svgG.appendChild(pattern);
+ }
+ }
+ }
+
+ @Override
+ public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
+ finalizePath();
+ path.setAttribute("fill", "none");
+ path.setAttribute("stroke", color.toHexRGB());
+ path.setAttribute("stroke-width", Double.toString(thickness == 0 ? 1 : thickness));
+ if (color instanceof RGBA) {
+ RGBA colorA = (RGBA) color;
+ if (colorA.alpha != 255) {
+ path.setAttribute("stroke-opacity", Float.toString(colorA.getAlphaFloat()));
+ }
+ }
+ switch (startCaps) {
+ case LINESTYLE2.NO_CAP:
+ path.setAttribute("stroke-linecap", "butt");
+ break;
+ case LINESTYLE2.SQUARE_CAP:
+ path.setAttribute("stroke-linecap", "square");
+ break;
+ default:
+ path.setAttribute("stroke-linecap", "round");
+ break;
+ }
+ switch (joints) {
+ case LINESTYLE2.BEVEL_JOIN:
+ path.setAttribute("stroke-linejoin", "bevel");
+ break;
+ case LINESTYLE2.ROUND_JOIN:
+ path.setAttribute("stroke-linejoin", "round");
+ break;
+ default:
+ path.setAttribute("stroke-linejoin", "miter");
+ if (miterLimit >= 1 && miterLimit != 4) {
+ path.setAttribute("stroke-miterlimit", Integer.toString(miterLimit));
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void lineGradientStyle(int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ path.removeAttribute("stroke-opacity");
+ Element gradient = (type == FILLSTYLE.LINEAR_GRADIENT)
+ ? _svg.createElement("linearGradient")
+ : _svg.createElement("radialGradient");
+ populateGradientElement(gradient, type, colors, ratios, matrix, spreadMethod, interpolationMethod, focalPointRatio);
+ int id = gradients.indexOf(gradient);
+ if (id < 0) {
+ // todo: filter same gradients
+ id = gradients.size();
+ gradients.add(gradient);
+ }
+ gradient.setAttribute("id", "gradient" + id);
+ path.setAttribute("stroke", "url(#gradient" + id + ")");
+ path.setAttribute("fill", "none");
+ _svgDefs.appendChild(gradient);
+ }
+
+ @Override
+ protected void finalizePath() {
+ if (path != null && pathData != "") {
+ path.setAttribute("d", pathData.trim());
+ _svgG.appendChild(path);
+ }
+ path = _svg.createElement("path");
+ super.finalizePath();
+ }
+
+ protected void populateGradientElement(Element gradient, int type, List colors, List ratios, MATRIX matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ gradient.setAttribute("gradientUnits", "userSpaceOnUse");
+ if (type == FILLSTYLE.LINEAR_GRADIENT) {
+ gradient.setAttribute("x1", "-819.2");
+ gradient.setAttribute("x2", "819.2");
+ } else {
+ gradient.setAttribute("r", "819.2");
+ gradient.setAttribute("cx", "0");
+ gradient.setAttribute("cy", "0");
+ if (focalPointRatio != 0) {
+ gradient.setAttribute("fx", Double.toString(819.2 * focalPointRatio));
+ gradient.setAttribute("fy", "0");
+ }
+ }
+ switch (spreadMethod) {
+ case GRADIENT.SPREAD_PAD_MODE:
+ gradient.setAttribute("spreadMethod", "pad");
+ break;
+ case GRADIENT.SPREAD_REFLECT_MODE:
+ gradient.setAttribute("spreadMethod", "reflect");
+ break;
+ case GRADIENT.SPREAD_REPEAT_MODE:
+ gradient.setAttribute("spreadMethod", "repeat");
+ break;
+ }
+ if (interpolationMethod == GRADIENT.INTERPOLATION_LINEAR_RGB_MODE) {
+ gradient.setAttribute("color-interpolation", "linearRGB");
+ }
+ if (matrix != null) {
+ float translateX = SWF.twipToPixel(matrix.translateX);
+ float translateY = SWF.twipToPixel(matrix.translateY);
+ float rotateSkew0 = 0;
+ float rotateSkew1 = 0;
+ float scaleX = 1;
+ float scaleY = 1;
+ if (matrix.hasRotate) {
+ rotateSkew0 = matrix.getRotateSkew0Float();
+ rotateSkew1 = matrix.getRotateSkew1Float();
+ }
+ if (matrix.hasScale) {
+ scaleX = SWF.twipToPixel((int) matrix.getScaleXFloat());
+ scaleY = SWF.twipToPixel((int) matrix.getScaleYFloat());
+ }
+ gradient.setAttribute("gradientTransform", "matrix(" + scaleX + ", " + rotateSkew0
+ + ", " + rotateSkew1 + ", " + scaleY + ", " + translateX + ", " + translateY + ")");
+ }
+ for (int i = 0; i < colors.size(); i++) {
+ Element gradientEntry = _svg.createElement("stop");
+ gradient.setAttribute("offset", Double.toString(ratios.get(i) / 255));
+ RGB color = colors.get(i);
+ //if(colors.get(i) != 0) {
+ gradientEntry.setAttribute("stop-color", color.toHexRGB());
+ //}
+ if (color instanceof RGBA) {
+ RGBA colorA = (RGBA) color;
+ if (colorA.alpha != 255) {
+ gradientEntry.setAttribute("stop-opacity", Float.toString(colorA.getAlphaFloat()));
+ }
+ }
+ gradient.appendChild(gradientEntry);
+ }
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java b/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java
new file mode 100644
index 000000000..ee0c28cd2
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/ShapeExporterBase.java
@@ -0,0 +1,538 @@
+/*
+ * Copyright (C) 2010-2013 JPEXS
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package com.jpexs.decompiler.flash.exporters;
+
+import com.jpexs.decompiler.flash.tags.base.ShapeTag;
+import com.jpexs.decompiler.flash.types.FILLSTYLE;
+import com.jpexs.decompiler.flash.types.FOCALGRADIENT;
+import com.jpexs.decompiler.flash.types.GRADRECORD;
+import com.jpexs.decompiler.flash.types.LINESTYLE;
+import com.jpexs.decompiler.flash.types.LINESTYLE2;
+import com.jpexs.decompiler.flash.types.MATRIX;
+import com.jpexs.decompiler.flash.types.RECT;
+import com.jpexs.decompiler.flash.types.RGB;
+import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord;
+import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
+import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD;
+import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord;
+import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord;
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author JPEXS, Claus Wahlers
+ */
+public abstract class ShapeExporterBase implements IShapeExporter {
+
+ private final ShapeTag tag;
+
+ private static final double unitDivisor = 20;
+
+ protected List _fillStyles;
+ protected List _lineStyles;
+
+ protected List