diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java
index fdefaf759..f6e9f674e 100644
--- a/trunk/src/com/jpexs/decompiler/flash/SWF.java
+++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java
@@ -1441,12 +1441,12 @@ public final class SWF implements TreeItem, Timelined {
fos.write(Utf8Helper.getBytes("window.setInterval(function(){nextFrame(ctx)}," + (int) (1000.0 / timeline.swf.frameRate) + ");\r\n"));
}
- if (Configuration.packJavaScripts.get()) {
+ /* if (Configuration.packJavaScripts.get()) {
JPacker.main(new String[]{"-q", "-b", "62", "-o", fmin.getAbsolutePath(), f.getAbsolutePath()});
f.delete();
- } else {
+ } else {*/
f.renameTo(fmin);
- }
+ //}
File fh = new File(foutdir + File.separator + "frames.html");
try (FileOutputStream fos = new FileOutputStream(fh); FileInputStream fis = new FileInputStream(fmin)) {
diff --git a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
index daf2145b1..fcf113d53 100644
--- a/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
+++ b/trunk/src/com/jpexs/decompiler/flash/console/CommandLineArgumentParser.java
@@ -31,6 +31,7 @@ import com.jpexs.decompiler.flash.exporters.modes.BinaryDataExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
import com.jpexs.decompiler.flash.exporters.modes.FramesExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode;
+import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
import com.jpexs.decompiler.flash.exporters.modes.MovieExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode;
import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode;
@@ -40,6 +41,7 @@ import com.jpexs.decompiler.flash.exporters.settings.BinaryDataExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.FontExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.FramesExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings;
+import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.MovieExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings;
import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings;
@@ -546,6 +548,7 @@ public class CommandLineArgumentParser {
"script",
"image",
"shape",
+ "morphshape",
"movie",
"sound",
"binarydata",
@@ -665,6 +668,11 @@ public class CommandLineArgumentParser {
exfile.exportShapes(handler, outDir.getAbsolutePath() + (exportFormats.length > 1 ? File.separator + "shapes" : ""),
new ShapeExportSettings(enumFromStr(formats.get("shape"), ShapeExportMode.class)));
}
+ case "morphshape": {
+ System.out.println("Exporting morphshapes...");
+ exfile.exportMorphShapes(handler, outDir.getAbsolutePath() + (exportFormats.length > 1 ? File.separator + "morphshapes" : ""),
+ new MorphShapeExportSettings(enumFromStr(formats.get("morphshape"), MorphShapeExportMode.class)));
+ }
break;
case "script":
case "as":
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java
index 0a19b7e56..ab2e9f136 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/MorphShapeExporter.java
@@ -19,9 +19,13 @@ package com.jpexs.decompiler.flash.exporters;
import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler;
import com.jpexs.decompiler.flash.RetryTask;
import com.jpexs.decompiler.flash.RunnableIOEx;
+import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
+import com.jpexs.decompiler.flash.exporters.modes.MorphShapeExportMode;
+import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.settings.MorphShapeExportSettings;
+import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
@@ -60,7 +64,7 @@ public class MorphShapeExporter {
if (t instanceof CharacterTag) {
characterID = ((CharacterTag) t).getCharacterId();
}
- String ext = "svg";
+ String ext = settings.mode==MorphShapeExportMode.CANVAS?"html":"svg";
final File file = new File(outdir + File.separator + characterID + "." + ext);
final int fcharacterID = characterID;
@@ -77,6 +81,15 @@ public class MorphShapeExporter {
fos.write(Utf8Helper.getBytes(exporter.getSVG()));
}
break;
+ case CANVAS:
+ try (FileOutputStream fos = new FileOutputStream(file)) {
+ int deltaX = -Math.min(mst.getStartBounds().Xmin,mst.getEndBounds().Xmin);
+ int deltaY = -Math.min(mst.getStartBounds().Ymin,mst.getEndBounds().Ymin);
+ CanvasMorphShapeExporter cse = new CanvasMorphShapeExporter(((Tag)mst).getSwf(),mst.getShapeAtRatio(0),mst.getShapeAtRatio(DefineMorphShapeTag.MAX_RATIO), new CXFORMWITHALPHA(),SWF.unitDivisor,deltaX,deltaY);
+ cse.export();
+ fos.write(Utf8Helper.getBytes(cse.getHtml()));
+ }
+ break;
}
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java b/trunk/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java
index 1416a36e3..9f2eb7ab0 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/modes/MorphShapeExportMode.java
@@ -23,7 +23,8 @@ package com.jpexs.decompiler.flash.exporters.modes;
public enum MorphShapeExportMode {
//TODO: implement other morphshape export modes
- SVG
+ SVG,
+ CANVAS
//PNG,
//GIF,
//AVI
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java
new file mode 100644
index 000000000..3375f9c07
--- /dev/null
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2010-2014 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.morphshape;
+
+import com.jpexs.decompiler.flash.SWF;
+import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
+import com.jpexs.decompiler.flash.exporters.commonshape.Point;
+import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter;
+import static com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter.color;
+import static com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter.getHtmlPrefix;
+import static com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter.getHtmlSuffix;
+import static com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter.getJsPrefix;
+import com.jpexs.decompiler.flash.tags.DefineMorphShapeTag;
+import com.jpexs.decompiler.flash.tags.Tag;
+import com.jpexs.decompiler.flash.tags.base.ImageTag;
+import com.jpexs.decompiler.flash.tags.base.MorphShapeTag;
+import com.jpexs.decompiler.flash.types.ColorTransform;
+import com.jpexs.decompiler.flash.types.FILLSTYLE;
+import com.jpexs.decompiler.flash.types.GRADIENT;
+import com.jpexs.decompiler.flash.types.GRADRECORD;
+import com.jpexs.decompiler.flash.types.LINESTYLE2;
+import com.jpexs.decompiler.flash.types.RECT;
+import com.jpexs.decompiler.flash.types.RGB;
+import com.jpexs.decompiler.flash.types.RGBA;
+import com.jpexs.decompiler.flash.types.SHAPE;
+import com.jpexs.helpers.Helper;
+import com.jpexs.helpers.SerializableImage;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+import javax.imageio.ImageIO;
+import javax.xml.bind.DatatypeConverter;
+
+/**
+ *
+ * @author JPEXS
+ */
+public class CanvasMorphShapeExporter extends MorphShapeExporterBase {
+
+ protected double deltaX = 0;
+ protected double deltaY = 0;
+ protected String pathData = "";
+ protected String fillData = "";
+ protected double unitDivisor;
+ protected String shapeData = "";
+ protected String strokeData = "";
+ protected Matrix fillMatrix = null;
+ protected Matrix fillMatrixEnd = null;
+ protected String lastRadColor = null;
+ protected int repeatCnt = 0;
+ protected SWF swf;
+
+
+
+ public CanvasMorphShapeExporter(SWF swf,SHAPE shape, SHAPE endShape, ColorTransform colorTransform, double unitDivisor,int deltaX, int deltaY) {
+ super(shape, endShape, colorTransform);
+ this.deltaX = deltaX;
+ this.deltaY = deltaY;
+ this.unitDivisor = unitDivisor;
+ this.swf = swf;
+ }
+
+
+ public String getHtml() {
+ int width = (int) (Math.max(shape.getBounds().getWidth(),shapeEnd.getBounds().getWidth())/unitDivisor);
+ int height = (int) (Math.max(shape.getBounds().getHeight(),shapeEnd.getBounds().getHeight())/unitDivisor);
+
+ return CanvasShapeExporter.getHtmlPrefix(width, height)+getJsPrefix()+shapeData+getJsSuffix(width,height)+CanvasShapeExporter.getHtmlSuffix();
+ }
+
+
+ public static String getJsSuffix(int width,int height){
+ String ret = "";
+ ret += "}\r\n";
+ int step = Math.round(65535 / 100);
+ int rate = 10;
+ ret += "var step = "+step+";\r\n";
+ ret += "var ratio = -1;\r\n";
+ ret += "function nextFrame(ctx){\r\n";
+ ret +="\tctx.clearRect(0,0," + width + "," + height + ");\r\n";
+ ret +="\tratio = (ratio+step)%65535;\r\n";
+ ret +="\tmorphshape(ctx,ratio);\r\n";
+ ret +="}\r\n";
+
+ ret +="window.setInterval(function(){nextFrame(ctx)},"+rate+");\r\n";
+ return ret;
+ }
+
+ public static String getJsPrefix(){
+ String ret = CanvasShapeExporter.getJsPrefix();
+ ret+="function morphshape(ctx,ratio){\r\n";
+ return ret;
+ }
+
+ @Override
+ public void beginShape() {
+ }
+
+ @Override
+ public void endShape() {
+ }
+
+ @Override
+ public void beginFills() {
+ }
+
+ @Override
+ public void endFills() {
+ }
+
+ @Override
+ public void beginLines() {
+ }
+
+ @Override
+ public void endLines() {
+ finalizePath();
+ }
+
+ @Override
+ public void beginFill(RGB color, RGB colorEnd) {
+ finalizePath();
+ fillData += "ctx.fillStyle="+useRatioColor(color,colorEnd)+";\r\n";
+ }
+
+ @Override
+ public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ finalizePath();
+
+ //TODO: How many repeats is ideal?
+ final int REPEAT_CNT = 5;
+
+ repeatCnt = spreadMethod == GRADIENT.SPREAD_PAD_MODE ? 0 : REPEAT_CNT;
+
+ if (type == FILLSTYLE.LINEAR_GRADIENT) {
+ Point start = matrix.transform(new Point(-16384 - 32768 * repeatCnt, 0));
+ Point end = matrix.transform(new Point(16384 + 32768 * repeatCnt, 0));
+ start.x += deltaX;
+ start.y += deltaY;
+ end.x += deltaX;
+ end.y += deltaY;
+
+
+ Point start2 = matrixEnd.transform(new Point(-16384 - 32768 * repeatCnt, 0));
+ Point end2 = matrixEnd.transform(new Point(16384 + 32768 * repeatCnt, 0));
+ start2.x += deltaX;
+ start2.y += deltaY;
+ end2.x += deltaX;
+ end2.y += deltaY;
+
+ fillData += "var grd=ctx.createLinearGradient(" + useRatioPos(start.x, start2.x) + "," + useRatioPos(start.y, start2.y) + "," + useRatioPos(end.x, end2.x) + "," + useRatioPos(end.y, end2.y) + ");\r\n";
+ } else {
+ matrix.translateX /= unitDivisor;
+ matrix.translateY /= unitDivisor;
+ matrix.scaleX /= unitDivisor;
+ matrix.scaleY /= unitDivisor;
+ matrix.rotateSkew0 /= unitDivisor;
+ matrix.rotateSkew1 /= unitDivisor;
+ matrix.translateX += deltaX / unitDivisor;
+ matrix.translateY += deltaY / unitDivisor;
+ fillMatrix = matrix;
+
+
+
+
+ matrixEnd.translateX /= unitDivisor;
+ matrixEnd.translateY /= unitDivisor;
+ matrixEnd.scaleX /= unitDivisor;
+ matrixEnd.scaleY /= unitDivisor;
+ matrixEnd.rotateSkew0 /= unitDivisor;
+ matrixEnd.rotateSkew1 /= unitDivisor;
+ matrixEnd.translateX += deltaX / unitDivisor;
+ matrixEnd.translateY += deltaY / unitDivisor;
+ fillMatrixEnd = matrixEnd;
+
+
+ fillData += "var grd=ctx.createRadialGradient("+focalPointRatio*16384+",0,0,0,0," + (16384 + 32768 * repeatCnt) + ");\r\n";
+ }
+ int repeatTotal = repeatCnt * 2 + 1;
+ double oneHeight = 1.0 / repeatTotal;
+ double pos = 0;
+ boolean revert = false;
+ if (type != FILLSTYLE.LINEAR_GRADIENT && spreadMethod == GRADIENT.SPREAD_REFLECT_MODE) {
+ revert = true;
+ }
+ for (int i = 0; i < repeatTotal; i++) {
+ if (spreadMethod == GRADIENT.SPREAD_REFLECT_MODE) {
+ revert = !revert;
+ }
+ for(int j=0;j1) s = 1;\r\n";
+ fillData += "grd.addColorStop(s," + useRatioColor(r.color,r2.color) + ");\r\n";
+ lastRadColor = useRatioColor(r.color,r2.color);
+ }
+ pos += oneHeight;
+ }
+ fillData += "ctx.fillStyle = grd;\r\n";
+ }
+
+ @Override
+ public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
+ 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) {
+ SerializableImage img = image.getImage();
+ if (img != null) {
+ colorTransform.apply(img);
+ 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.getBufferedImage(), format.toUpperCase(Locale.ENGLISH), baos);
+ } catch (IOException ex) {
+ }
+ imageData = baos.toByteArray();
+ }
+ String base64ImgData = DatatypeConverter.printBase64Binary(imageData);
+ if (matrix != null) {
+ fillMatrix = matrix.clone();
+ fillMatrix.translateX /= unitDivisor;
+ fillMatrix.translateY /= unitDivisor;
+ fillMatrix.scaleX /= unitDivisor;
+ fillMatrix.scaleY /= unitDivisor;
+ fillMatrix.rotateSkew0 /= unitDivisor;
+ fillMatrix.rotateSkew1 /= unitDivisor;
+ fillMatrix.translateX += deltaX / unitDivisor;
+ fillMatrix.translateY += deltaY / unitDivisor;
+
+
+ fillMatrixEnd = matrixEnd.clone();
+ fillMatrixEnd.translateX /= unitDivisor;
+ fillMatrixEnd.translateY /= unitDivisor;
+ fillMatrixEnd.scaleX /= unitDivisor;
+ fillMatrixEnd.scaleY /= unitDivisor;
+ fillMatrixEnd.rotateSkew0 /= unitDivisor;
+ fillMatrixEnd.rotateSkew1 /= unitDivisor;
+ fillMatrixEnd.translateX += deltaX / unitDivisor;
+ fillMatrixEnd.translateY += deltaY / unitDivisor;
+
+ }
+
+ fillData += "var img = document.createElement(\"img\");\r\nimg.src=\"data:image/" + format + ";base64," + base64ImgData + "\";\r\n";
+ fillData += "var pat=ctx.createPattern(img,\"repeat\");\r\n";
+ fillData += "ctx.fillStyle = pat;\r\n";
+ }
+ }
+ }
+
+ @Override
+ public void endFill() {
+ finalizePath();
+ }
+
+ @Override
+ public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) {
+ finalizePath();
+ thickness /= unitDivisor;
+ thicknessEnd /= unitDivisor;
+
+ strokeData += "ctx.strokeStyle=" + useRatioColor(color,colorEnd) + ";\r\n";
+ strokeData += "ctx.lineWidth="+useRatioDouble(thickness,thicknessEnd)+";\r\n";
+ switch (startCaps) {
+ case LINESTYLE2.NO_CAP:
+ strokeData += "ctx.lineCap=\"butt\";\r\n";
+ break;
+ case LINESTYLE2.SQUARE_CAP:
+ strokeData += "ctx.lineCap=\"square\";\r\n";
+ break;
+ default:
+ strokeData += "ctx.lineCap=\"round\";\r\n";
+ break;
+ }
+ switch (joints) {
+ case LINESTYLE2.BEVEL_JOIN:
+ strokeData += "ctx.lineJoin=\"bevel\";\r\n";
+ break;
+ case LINESTYLE2.ROUND_JOIN:
+ strokeData += "ctx.lineJoin=\"round\";\r\n";
+ break;
+ default:
+ strokeData += "ctx.lineJoin=\"miter\";\r\n";
+ strokeData += "ctx.miterLimit=" + Integer.toString(miterLimit) + ";\r\n";
+ break;
+ }
+ }
+
+ @Override
+ public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio) {
+ //TODO
+ }
+
+ @Override
+ public void moveTo(double x, double y, double x2, double y2) {
+ x += deltaX;
+ y += deltaY;
+ x2 += deltaX;
+ y2 += deltaY;
+ pathData += "ctx.moveTo("
+ + useRatioPos(x,x2) + ","
+ + useRatioPos(y,y2) + ");\r\n";
+ }
+
+ @Override
+ public void lineTo(double x, double y, double x2, double y2) {
+ x += deltaX;
+ y += deltaY;
+ x2 += deltaX;
+ y2 += deltaY;
+ pathData += "ctx.lineTo("
+ + useRatioPos(x,x2) + ","
+ + useRatioPos(y,y2) + ");\r\n";
+ }
+
+ @Override
+ public void curveTo(double controlX, double controlY, double anchorX, double anchorY, double controlX2, double controlY2, double anchorX2, double anchorY2) {
+ controlX += deltaX;
+ anchorX += deltaX;
+ controlY += deltaY;
+ anchorY += deltaY;
+
+ controlX2 += deltaX;
+ anchorX2 += deltaX;
+ controlY2 += deltaY;
+ anchorY2 += deltaY;
+
+
+ pathData += "ctx.quadraticCurveTo(" + useRatioPos(controlX,controlX2) + ","
+ + useRatioPos(controlY,controlY2) + ","
+ + useRatioPos(anchorX,anchorX2) + ","
+ + useRatioPos(anchorY,anchorY2) + ");\r\n";
+ }
+
+ protected void finalizePath() {
+ if (!"".equals(pathData)) {
+ pathData = "ctx.beginPath();\r\n" + pathData + "ctx.closePath();\r\n" + strokeData;
+
+ if (fillMatrix != null) {
+ if (lastRadColor != null) {
+ pathData += "ctx.fillStyle=" + lastRadColor + ";\r\n ctx.fill(\"evenodd\");\r\n";
+ }
+ pathData += "ctx.save();\r\n";
+ pathData += "ctx.clip();\r\n";
+ pathData += "ctx.transform(" + useRatioDouble(fillMatrix.scaleX,fillMatrixEnd.scaleX) + "," + useRatioDouble(fillMatrix.rotateSkew0,fillMatrixEnd.rotateSkew0) + "," + useRatioDouble(fillMatrix.rotateSkew1,fillMatrixEnd.rotateSkew1) + "," + useRatioDouble(fillMatrix.scaleY,fillMatrixEnd.scaleY) + "," + useRatioDouble(fillMatrix.translateX,fillMatrixEnd.translateX) + "," + useRatioDouble(fillMatrix.translateY,fillMatrixEnd.translateY) + ");\r\n";
+ pathData += "console.log('m:'+("+useRatioDouble(fillMatrix.scaleX,fillMatrixEnd.scaleX)+")+','+("+useRatioDouble(fillMatrix.scaleY,fillMatrixEnd.scaleY)+")+','+("+useRatioDouble(fillMatrix.rotateSkew0,fillMatrixEnd.rotateSkew0)+")+','+("+useRatioDouble(fillMatrix.rotateSkew1,fillMatrixEnd.rotateSkew1)+"));";
+ pathData += fillData;
+ pathData += "ctx.fillRect(" + (-16384 - 32768 * repeatCnt) + "," + (-16384 - 32768 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + ");\r\n";
+ pathData += "ctx.restore();\r\n";
+ shapeData += pathData;
+ } else {
+ if (!"".equals(fillData)) {
+ pathData += "ctx.fill(\"evenodd\");\r\n";
+ }
+ shapeData += fillData + pathData;
+ }
+ if (!"".equals(strokeData)) {
+ shapeData += "ctx.stroke();\r\n";
+ }
+ }
+
+ repeatCnt = 0;
+ pathData = "";
+ fillData = "";
+ strokeData = "";
+ fillMatrix = null;
+ fillMatrixEnd = null;
+ lastRadColor = null;
+ }
+
+ private String useRatioPos(double a, double b){
+ return (a / unitDivisor) + "+ratio*(" +((b-a)/unitDivisor)+")/"+DefineMorphShapeTag.MAX_RATIO;
+ }
+
+ private String useRatioInt(int a, int b){
+ return "Math.round("+ a + "+ratio*(" +((b-a))+")/"+DefineMorphShapeTag.MAX_RATIO+")";
+ }
+
+ private String useRatioDouble(double a, double b){
+ return "" + a + "+ratio*(" +((b-a))+")/"+DefineMorphShapeTag.MAX_RATIO;
+ }
+
+ public String getShapeData() {
+ return shapeData;
+ }
+
+ private String useRatioColor(RGB color, RGB colorEnd){
+ return "\"rgba(\"+" + 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)+\")\"";
+ }
+}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java
index 6ebfd78dd..c5421473e 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/DefaultSVGMorphShapeExporter.java
@@ -76,7 +76,7 @@ public abstract class DefaultSVGMorphShapeExporter extends MorphShapeExporterBas
}
@Override
- public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
+ public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
finalizePath();
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java
index 2efc56f15..673011d47 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/IMorphShapeExporter.java
@@ -43,7 +43,7 @@ public interface IMorphShapeExporter {
public void beginGradientFill(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio);
- public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform);
+ public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform);
public void endFill();
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java
index 0621c50e7..ea2973cbb 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java
@@ -329,10 +329,12 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP:
case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP:
// Bitmap fill
- matrix = new Matrix(fillStyle.bitmapMatrix);
+ matrix = new Matrix(fillStyle.bitmapMatrix);
+ matrixEnd = new Matrix(fillStyleEnd.bitmapMatrix);
beginBitmapFill(
fillStyle.bitmapId,
matrix,
+ matrixEnd,
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP),
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.CLIPPED_BITMAP),
colorTransform
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java
index 307535e07..7e12db363 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/SVGMorphShapeExporter.java
@@ -103,7 +103,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
@Override
- public void beginBitmapFill(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
+ public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
finalizePath();
ImageTag image = null;
for (Tag t : swf.tags) {
@@ -145,6 +145,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
pattern.setAttribute("width", "" + width);
pattern.setAttribute("height", "" + height);
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
+ //TODO: animate matrix
if (matrix != null) {
double translateX = roundPixels400(matrix.translateX / SWF.unitDivisor);
double translateY = roundPixels400(matrix.translateY / SWF.unitDivisor);
diff --git a/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java b/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java
index 7978b4018..18eae62e4 100644
--- a/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java
+++ b/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java
@@ -104,6 +104,8 @@ public class CanvasShapeExporter extends ShapeExporterBase {
this.swf = swf;
this.unitDivisor = unitDivisor;
this.basicFill = basicFill;
+ this.deltaX = deltaX;
+ this.deltaY = deltaY;
}
@Override
@@ -169,10 +171,8 @@ public class CanvasShapeExporter extends ShapeExporterBase {
matrix.translateX += deltaX / unitDivisor;
matrix.translateY += deltaY / unitDivisor;
-
- //TODO: Focal point
-
- fillData += "var grd=ctx.createRadialGradient(0,0,0,0,0," + (16384 + 32768 * repeatCnt) + ");\r\n";
+
+ fillData += "var grd=ctx.createRadialGradient("+focalPointRatio*16384+",0,0,0,0," + (16384 + 32768 * repeatCnt) + ");\r\n";
}
int repeatTotal = repeatCnt * 2 + 1;
double oneHeight = 1.0 / repeatTotal;
@@ -247,7 +247,6 @@ public class CanvasShapeExporter extends ShapeExporterBase {
matrix.rotateSkew0 /= unitDivisor;
matrix.rotateSkew1 /= unitDivisor;
fillMatrix = matrix;
-
}
fillData += "var img = document.createElement(\"img\"); img.src=\"data:image/" + format + ";base64," + base64ImgData + "\";\r\n";
@@ -338,7 +337,7 @@ public class CanvasShapeExporter extends ShapeExporterBase {
}
pathData += "ctx.save();\r\n";
pathData += "ctx.clip();\r\n";
- pathData += "ctx.transform(" + fillMatrix.scaleX + "," + fillMatrix.rotateSkew0 + "," + fillMatrix.rotateSkew1 + "," + fillMatrix.scaleY + "," + fillMatrix.translateX + "," + fillMatrix.translateY + ");\r\n";
+ pathData += "ctx.transform(" + fillMatrix.scaleX + "," + fillMatrix.rotateSkew0 + "," + fillMatrix.rotateSkew1 + "," + fillMatrix.scaleY + "," + fillMatrix.translateX + "," + fillMatrix.translateY + ");\r\n";
pathData += fillData;
pathData += "ctx.fillRect(" + (-16384 - 32768 * repeatCnt) + "," + (-16384 - 32768 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + ");\r\n";
pathData += "ctx.restore();\r\n";
diff --git a/trunk/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties b/trunk/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties
index dc0bfc611..f7b3bd0db 100644
--- a/trunk/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties
+++ b/trunk/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties
@@ -52,6 +52,7 @@ button.cancel = Cancel
morphshapes = Morphshapes
morphshapes.gif = GIF
morphshapes.svg = SVG
+morphshapes.canvas = HTML5 Canvas
frames = Frames
frames.png = PNG
diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java
index ef580d156..7ca43aba9 100644
--- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java
+++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShape2Tag.java
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
+import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
@@ -77,6 +78,7 @@ public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag
public SHAPE startEdges;
public SHAPE endEdges;
public static final int ID = 84;
+ public static final int MAX_RATIO = 65535;
@Override
public Set getNeededCharacters() {
@@ -358,6 +360,9 @@ public class DefineMorphShape2Tag extends CharacterTag implements MorphShapeTag
@Override
public String toHtmlCanvas(double unitDivisor) {
- return ""; //TODO
+ CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0);
+ cmse.export();
+
+ return cmse.getShapeData();
}
}
diff --git a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java
index 5f729f214..fdca4f7b7 100644
--- a/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java
+++ b/trunk/src/com/jpexs/decompiler/flash/tags/DefineMorphShapeTag.java
@@ -21,6 +21,7 @@ import com.jpexs.decompiler.flash.SWFInputStream;
import com.jpexs.decompiler.flash.SWFOutputStream;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
+import com.jpexs.decompiler.flash.exporters.morphshape.CanvasMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.morphshape.SVGMorphShapeExporter;
import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter;
import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter;
@@ -69,6 +70,7 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
public SHAPE startEdges;
public SHAPE endEdges;
public static final int ID = 46;
+ public static final int MAX_RATIO = 65535;
@Override
public Set getNeededCharacters() {
@@ -221,8 +223,8 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
}
StyleChangeRecord scr = (StyleChangeRecord) scr1.clone();
if (scr1.stateMoveTo || scr2.stateMoveTo) {
- scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / 65535;
- scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / 65535;
+ scr.moveDeltaX = startPosX + (endPosX - startPosX) * ratio / MAX_RATIO;
+ scr.moveDeltaY = startPosY + (endPosY - startPosY) * ratio / MAX_RATIO;
scr.stateMoveTo = scr.moveDeltaX != posX || scr.moveDeltaY != posY;
}
finalRecords.add(scr);
@@ -255,10 +257,10 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
continue;
}
CurvedEdgeRecord cer = new CurvedEdgeRecord();
- cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / 65535;
- cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / 65535;
- cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / 65535;
- cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / 65535;
+ cer.controlDeltaX = cer1.controlDeltaX + (cer2.controlDeltaX - cer1.controlDeltaX) * ratio / MAX_RATIO;
+ cer.controlDeltaY = cer1.controlDeltaY + (cer2.controlDeltaY - cer1.controlDeltaY) * ratio / MAX_RATIO;
+ cer.anchorDeltaX = cer1.anchorDeltaX + (cer2.anchorDeltaX - cer1.anchorDeltaX) * ratio / MAX_RATIO;
+ cer.anchorDeltaY = cer1.anchorDeltaY + (cer2.anchorDeltaY - cer1.anchorDeltaY) * ratio / MAX_RATIO;
startPosX += cer1.controlDeltaX + cer1.anchorDeltaX;
startPosY += cer1.controlDeltaY + cer1.anchorDeltaY;
endPosX += cer2.controlDeltaX + cer2.anchorDeltaX;
@@ -281,8 +283,8 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
StraightEdgeRecord ser = new StraightEdgeRecord();
ser.generalLineFlag = true;
ser.vertLineFlag = false;
- ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / 65535;
- ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / 65535;
+ ser.deltaX = ser1.deltaX + (ser2.deltaX - ser1.deltaX) * ratio / MAX_RATIO;
+ ser.deltaY = ser1.deltaY + (ser2.deltaY - ser1.deltaY) * ratio / MAX_RATIO;
startPosX += ser1.deltaX;
startPosY += ser1.deltaY;
endPosX += ser2.deltaX;
@@ -341,6 +343,9 @@ public class DefineMorphShapeTag extends CharacterTag implements MorphShapeTag {
@Override
public String toHtmlCanvas(double unitDivisor) {
- return ""; //TODO
+ CanvasMorphShapeExporter cmse = new CanvasMorphShapeExporter(swf, getShapeAtRatio(0), getShapeAtRatio(MAX_RATIO), new ColorTransform(), unitDivisor, 0, 0);
+ cmse.export();
+
+ return cmse.getShapeData();
}
}