From 824a3d2f96a57c9c06d3e69b993b7ba74e8c3ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=F8=EDk?= Date: Sat, 26 Apr 2014 10:52:52 +0200 Subject: [PATCH] MorphShapes Canvas export --- trunk/src/com/jpexs/decompiler/flash/SWF.java | 6 +- .../console/CommandLineArgumentParser.java | 8 + .../flash/exporters/MorphShapeExporter.java | 15 +- .../exporters/modes/MorphShapeExportMode.java | 3 +- .../morphshape/CanvasMorphShapeExporter.java | 421 ++++++++++++++++++ .../DefaultSVGMorphShapeExporter.java | 2 +- .../morphshape/IMorphShapeExporter.java | 2 +- .../morphshape/MorphShapeExporterBase.java | 4 +- .../morphshape/SVGMorphShapeExporter.java | 3 +- .../exporters/shape/CanvasShapeExporter.java | 11 +- .../flash/gui/locales/ExportDialog.properties | 1 + .../flash/tags/DefineMorphShape2Tag.java | 7 +- .../flash/tags/DefineMorphShapeTag.java | 23 +- 13 files changed, 481 insertions(+), 25 deletions(-) create mode 100644 trunk/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java 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(); } }