diff --git a/trunk/src/com/jpexs/decompiler/flash/SWF.java b/trunk/src/com/jpexs/decompiler/flash/SWF.java index d7aa3b96f..8f17965a8 100644 --- a/trunk/src/com/jpexs/decompiler/flash/SWF.java +++ b/trunk/src/com/jpexs/decompiler/flash/SWF.java @@ -1482,7 +1482,7 @@ public final class SWF implements TreeItem, Timelined { fos.write(Utf8Helper.getBytes("}\r\n")); - fos.write(Utf8Helper.getBytes("var frame = 0;\r\n")); + fos.write(Utf8Helper.getBytes("var frame = -1;\r\n")); fos.write(Utf8Helper.getBytes("var frames = [];\r\n")); for (int i : fframes) { fos.write(Utf8Helper.getBytes("frames.push(" + i + ");\r\n")); @@ -1493,7 +1493,7 @@ public final class SWF implements TreeItem, Timelined { fos.write(Utf8Helper.getBytes("\t"+currentName + "(ctx,frames[frame],0);\r\n")); fos.write(Utf8Helper.getBytes("}\r\n")); - fos.write(Utf8Helper.getBytes("window.setInterval(function(){nextFrame(ctx)}," + (int) (1000.0 / timeline.swf.frameRate) + ");\r\n")); + fos.write(Utf8Helper.getBytes("if(frames.length==1){nextFrame(ctx);}else{window.setInterval(function(){nextFrame(ctx);}," + (int) (1000.0 / timeline.swf.frameRate) + ");};\r\n")); } if (Configuration.packJavaScripts.get()) { 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 a2802ce98..9f2c1dfd7 100644 --- a/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java +++ b/trunk/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java @@ -52,14 +52,80 @@ public class CanvasShapeExporter extends ShapeExporterBase { protected int repeatCnt = 0; protected double unitDivisor; protected RGB basicFill; - + protected String lineFillData = null; + protected String lineLastRadColor = null; + protected Matrix lineFillMatrix = null; + protected int lineRepeatCnt = 0; - public static String getJsPrefix(){ - return "var c=document.getElementById(\"myCanvas\");\r\n" - + "var ctx=c.getContext(\"2d\");\r\n"; + public static String getJsPrefix() { + return "var canvas=document.getElementById(\"myCanvas\");\r\n" + + "var ctx=canvas.getContext(\"2d\");\r\n" + + "var enhanceContext = function(context) {\r\n" + + " var m = [1,0,0,1,0,0];\r\n" + + " context._matrices = [m];\r\n" + + "\r\n" + + " //the stack of saved matrices\r\n" + + " context._savedMatrices = [[m]];\r\n" + + "\r\n" + + " var super_ = context.__proto__;\r\n" + + " context.__proto__ = ({\r\n" + + "\r\n" + + " save: function() {\r\n" + + " this._savedMatrices.push(this._matrices.slice());\r\n" + + " super_.save.call(this);\r\n" + + " },\r\n" + + "\r\n" + + " //if the stack of matrices we're managing doesn't have a saved matrix,\r\n" + + " //we won't even call the context's original `restore` method.\r\n" + + " restore: function() {\r\n" + + " if(this._savedMatrices.length == 0)\r\n" + + " return;\r\n" + + " super_.restore.call(this);\r\n" + + " this._matrices = this._savedMatrices.pop();\r\n" + + " },\r\n" + + "\r\n" + + " scale: function(x, y) {\r\n" + + " super_.scale.call(this, x, y);\r\n" + + " },\r\n" + + "\r\n" + + " rotate: function(theta) {\r\n" + + " super_.rotate.call(this, theta);\r\n" + + " },\r\n" + + "\r\n" + + " translate: function(x, y) {\r\n" + + " super_.translate.call(this, x, y);\r\n" + + " },\r\n" + + "\r\n" + + " transform: function(a, b, c, d, e, f) {\r\n" + + " this._matrices.push([a,b,c,d,e,f]);\r\n" + + " super_.transform.call(this, a, b, c, d, e, f);\r\n" + + " },\r\n" + + "\r\n" + + " setTransform: function(a, b, c, d, e, f) {\r\n" + + " this._matrices=[];\r\n" + + " this._matrices.push([a,b,c,d,e,f]);\r\n" + + " super_.setTransform.call(this, a, b, c, d, e, f);\r\n" + + " },\r\n" + + "\r\n" + + " resetTransform: function() {\r\n" + + " super_.resetTransform.call(this);\r\n" + + " },\r\n" + + "\r\n" + + " applyTransforms: function(m) {\r\n" + + " this.setTransform(1,0,0,1,0,0);" + + " for(var i=0;i\r\n" + "\r\n" + "" @@ -71,32 +137,31 @@ public class CanvasShapeExporter extends ShapeExporterBase { + "Your browser does not support the HTML5 canvas tag.\r\n" + "\r\n" + "\r\n" - + "\r\n" + "\r\n" + ""; } + public String getHtml() { RECT r = shape.getBounds(); int width = (int) (r.getWidth() / unitDivisor); int height = (int) (r.getHeight() / unitDivisor); - - return getHtmlPrefix(width, height)+getJsPrefix()+shapeData+getHtmlSuffix(); + + return getHtmlPrefix(width, height) + getJsPrefix() + shapeData + getHtmlSuffix(); } public String getShapeData() { return shapeData; } - - - public CanvasShapeExporter(RGB basicFill,double unitDivisor,SWF swf, SHAPE shape, ColorTransform colorTransform, int deltaX, int deltaY) { - super(shape, colorTransform); + public CanvasShapeExporter(RGB basicFill, double unitDivisor, SWF swf, SHAPE shape, ColorTransform colorTransform, int deltaX, int deltaY) { + super(shape, colorTransform); this.swf = swf; this.unitDivisor = unitDivisor; this.basicFill = basicFill; @@ -133,10 +198,10 @@ public class CanvasShapeExporter extends ShapeExporterBase { @Override public void beginFill(RGB color) { finalizePath(); - if(color == null){ - color = basicFill; + if (color == null) { + color = basicFill; } - fillData += "\tctx.fillStyle=\"" + color(color) + "\";\r\n"; + fillData += "\tctx.fillStyle=\"" + color(color) + "\";\r\n"; } @Override @@ -167,8 +232,8 @@ public class CanvasShapeExporter extends ShapeExporterBase { matrix.translateX += deltaX / unitDivisor; matrix.translateY += deltaY / unitDivisor; - - fillData += "\tvar grd=ctx.createRadialGradient("+focalPointRatio*16384+",0,0,0,0," + (16384 + 32768 * repeatCnt) + ");\r\n"; + + fillData += "\tvar grd=ctx.createRadialGradient(" + focalPointRatio * 16384 + ",0,0,0,0," + (16384 + 32768 * repeatCnt) + ");\r\n"; } int repeatTotal = repeatCnt * 2 + 1; double oneHeight = 1.0 / repeatTotal; @@ -191,11 +256,11 @@ public class CanvasShapeExporter extends ShapeExporterBase { } public static String color(Color color) { - return color(new RGBA(color.getRed(),color.getGreen(),color.getBlue(),color.getAlpha())); + return color(new RGBA(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha())); } - + public static String color(RGB rgb) { - if ((rgb instanceof RGBA)&&(((RGBA) rgb).alpha<255)) { + if ((rgb instanceof RGBA) && (((RGBA) rgb).alpha < 255)) { RGBA rgba = (RGBA) rgb; return "rgba(" + rgba.red + "," + rgba.green + "," + rgba.blue + "," + rgba.getAlphaFloat() + ")"; } else { @@ -220,7 +285,7 @@ public class CanvasShapeExporter extends ShapeExporterBase { if (image != null) { SerializableImage img = image.getImage(); if (img != null) { - colorTransform.apply(img); + colorTransform.apply(img); if (matrix != null) { matrix.translateX /= unitDivisor; matrix.translateY /= unitDivisor; @@ -231,8 +296,7 @@ public class CanvasShapeExporter extends ShapeExporterBase { fillMatrix = matrix; } - - fillData += "\tvar pat=ctx.createPattern(image"+bitmapId+",\"repeat\");\r\n"; + fillData += "\tvar pat=ctx.createPattern(image" + bitmapId + ",\"repeat\");\r\n"; fillData += "\tctx.fillStyle = pat;\r\n"; } } @@ -248,7 +312,9 @@ public class CanvasShapeExporter extends ShapeExporterBase { finalizePath(); thickness /= unitDivisor; - strokeData += "\tctx.strokeStyle=\"" + color(color) + "\";\r\n"; + if (color != null) { //gradient lines have no color + strokeData += "\tctx.strokeStyle=\"" + color(color) + "\";\r\n"; + } strokeData += "\tctx.lineWidth=" + Double.toString(thickness == 0 ? 1 : thickness) + ";\r\n"; switch (startCaps) { case LINESTYLE2.NO_CAP: @@ -277,7 +343,64 @@ public class CanvasShapeExporter extends ShapeExporterBase { @Override public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, Matrix matrix, int spreadMethod, int interpolationMethod, float focalPointRatio) { - //TODO + lineFillData = ""; + + + //TODO: How many repeats is ideal? + final int REPEAT_CNT = 5; + + lineRepeatCnt = spreadMethod == GRADIENT.SPREAD_PAD_MODE ? 0 : REPEAT_CNT; + + if (type == FILLSTYLE.LINEAR_GRADIENT) { + Point start = matrix.transform(new Point(-16384 - 32768 * lineRepeatCnt, 0)); + Point end = matrix.transform(new Point(16384 + 32768 * lineRepeatCnt, 0)); + start.x += deltaX; + start.y += deltaY; + end.x += deltaX; + end.y += deltaY; + lineFillData += "\tvar grd=ctx.createLinearGradient(" + Double.toString(start.x / unitDivisor) + "," + Double.toString(start.y / unitDivisor) + "," + Double.toString(end.x / unitDivisor) + "," + Double.toString(end.y / unitDivisor) + ");\r\n"; + } else { + matrix.translateX /= unitDivisor; + matrix.translateY /= unitDivisor; + matrix.scaleX /= unitDivisor; + matrix.scaleY /= unitDivisor; + matrix.rotateSkew0 /= unitDivisor; + matrix.rotateSkew1 /= unitDivisor; + lineFillMatrix = matrix; + + matrix.translateX += deltaX / unitDivisor; + matrix.translateY += deltaY / unitDivisor; + + lineFillData += "\tvar grd=ctx.createRadialGradient(" + focalPointRatio * 16384 + ",0,0,0,0," + (16384 + 32768 * lineRepeatCnt) + ");\r\n"; + } + int repeatTotal = lineRepeatCnt * 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 (GRADRECORD r : gradientRecords) { + lineFillData += "\tgrd.addColorStop(" + Double.toString(pos + (oneHeight * (revert ? 255 - r.ratio : r.ratio) / 255.0)) + ",\"" + color(r.color) + "\");\r\n"; + lineLastRadColor = color(r.color); + } + pos += oneHeight; + } + lineFillData += "\tctx.fillStyle = grd;\r\n"; + + String preStrokeData = ""; + + preStrokeData += "var lcanvas = document.createElement(\"canvas\");\r\n"; + preStrokeData += "lcanvas.width = canvas.width;\r\nlcanvas.height=canvas.height;\r\n"; + preStrokeData += "var lctx = lcanvas.getContext(\"2d\");\r\n"; + preStrokeData += "enhanceContext(lctx);\r\n"; + preStrokeData += "lctx.applyTransforms(ctx._matrices);\r\n"; + preStrokeData += "ctx = lctx;\r\n"; + strokeData = preStrokeData + strokeData; } @Override @@ -311,15 +434,60 @@ public class CanvasShapeExporter extends ShapeExporterBase { protected void finalizePath() { if (!"".equals(pathData)) { - pathData = "\tctx.beginPath();\r\n" + pathData + "\tctx.closePath();\r\n" + strokeData; + pathData = "\tctx.beginPath();\r\n" + pathData + "\tctx.closePath();\r\n"; + if(lineFillData!=null){ + String preLineFillData = ""; + preLineFillData += "var oldctx = ctx;\r\n"; + preLineFillData += "ctx.save();\r\n"; + preLineFillData += strokeData; + preLineFillData += pathData; + preLineFillData += "ctx.stroke();\r\n"; + preLineFillData += "var lfcanvas = document.createElement(\"canvas\");\r\n"; + preLineFillData += "lfcanvas.width = canvas.width;\r\nlfcanvas.height=canvas.height;\r\n"; + preLineFillData += "var lfctx = lfcanvas.getContext(\"2d\");\r\n"; + preLineFillData += "enhanceContext(lfctx);\r\n"; + preLineFillData += "lfctx.applyTransforms(ctx._matrices);\r\n"; + preLineFillData += "ctx = lfctx;"; + if (lineLastRadColor != null) { + preLineFillData += "\tctx.fillStyle=\"" + lineLastRadColor + "\";\r\n ctx.fill(\"evenodd\");\r\n"; + } + //preLineFillData += pathData; + //preLineFillData += "\tctx.save();\r\n"; + //preLineFillData += "\tctx.clip();\r\n"; + preLineFillData += "\tctx.transform(" + lineFillMatrix.scaleX + "," + lineFillMatrix.rotateSkew0 + "," + lineFillMatrix.rotateSkew1 + "," + lineFillMatrix.scaleY + "," + lineFillMatrix.translateX + "," + lineFillMatrix.translateY + ");\r\n"; + lineFillData = preLineFillData + lineFillData; + lineFillData += "\tctx.fillRect(" + (-16384 - 32768 * lineRepeatCnt) + "," + (-16384 - 32768 * lineRepeatCnt) + "," + (2 * 16384 + 32768 * 2 * lineRepeatCnt) + "," + (2 * 16384 + 32768 * 2 * lineRepeatCnt) + ");\r\n"; + //lineFillData += "\tctx.restore();\r\n"; + + lineFillData += "\tctx = oldctx;\r\n"; + + + //lcanvas - stroke + //lfcanvas - stroke background + + lineFillData += "var limgd = lctx.getImageData(0, 0, lcanvas.width, lcanvas.height);\r\n" + + "var lpix = limgd.data;\r\n" + + "var lfimgd = lfctx.getImageData(0, 0, lfcanvas.width, lfcanvas.height);\r\n" + + "var lfpix = lfimgd.data;\r\n" + + "var imgd = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n" + + "var pix = imgd.data;\r\n" + + "for (var i = 0; i < lpix.length; i += 4) {\r\n" + + " if(lpix[i+3]>0){ pix[i] = lfpix[i]; pix[i+1] = lfpix[i+1]; pix[i+2] = lfpix[i+2]; pix[i+3] = lfpix[i+3];}\r\n" + + "}\r\n" + + "ctx.putImageData(imgd, 0, 0);\r\n"; + lineFillData += "ctx.restore();\r\n"; + strokeData = ""; + }else{ + pathData += strokeData; + } if (fillMatrix != null) { if (lastRadColor != null) { pathData += "\tctx.fillStyle=\"" + lastRadColor + "\";\r\n ctx.fill(\"evenodd\");\r\n"; } pathData += "\tctx.save();\r\n"; pathData += "\tctx.clip();\r\n"; - pathData += "\tctx.transform(" + fillMatrix.scaleX + "," + fillMatrix.rotateSkew0 + "," + fillMatrix.rotateSkew1 + "," + fillMatrix.scaleY + "," + fillMatrix.translateX + "," + fillMatrix.translateY + ");\r\n"; + pathData += "\tctx.transform(" + fillMatrix.scaleX + "," + fillMatrix.rotateSkew0 + "," + fillMatrix.rotateSkew1 + "," + fillMatrix.scaleY + "," + fillMatrix.translateX + "," + fillMatrix.translateY + ");\r\n"; pathData += fillData; pathData += "\tctx.fillRect(" + (-16384 - 32768 * repeatCnt) + "," + (-16384 - 32768 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + "," + (2 * 16384 + 32768 * 2 * repeatCnt) + ");\r\n"; pathData += "\tctx.restore();\r\n"; @@ -332,14 +500,20 @@ public class CanvasShapeExporter extends ShapeExporterBase { } if (!"".equals(strokeData)) { shapeData += "\tctx.stroke();\r\n"; + }else if(lineFillData!=null){ + shapeData += lineFillData; } } repeatCnt = 0; + lineRepeatCnt = 0; pathData = ""; fillData = ""; strokeData = ""; fillMatrix = null; lastRadColor = null; + lineFillData = null; + lineLastRadColor = null; + lineFillMatrix = null; } }