diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java index db62ffde4..20dee20f0 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/CanvasMorphShapeExporter.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.morphshape; import com.jpexs.decompiler.flash.SWF; @@ -39,6 +40,10 @@ import com.jpexs.helpers.SerializableImage; */ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { + protected static final String DRAW_COMMAND_M = "M"; + protected static final String DRAW_COMMAND_L = "L"; + protected static final String DRAW_COMMAND_Q = "Q"; + protected String currentDrawCommand = ""; protected double deltaX = 0; protected double deltaY = 0; protected String pathData = ""; @@ -262,8 +267,9 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { @Override public void lineStyle(double thickness, double thicknessEnd, RGB color, RGB colorEnd, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { finalizePath(); - thickness /= unitDivisor; - thicknessEnd /= unitDivisor; + thickness /= SWF.unitDivisor; + thicknessEnd /= SWF.unitDivisor; + strokeData += "\tvar scaleMode = \""+scaleMode+"\";\r\n"; if (color != null) { //for gradient line fill strokeData += "\tctx.strokeStyle=" + useRatioColor(color, colorEnd) + ";\r\n"; } @@ -370,35 +376,43 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { preStrokeData += "\tlcanvas.height=canvas.height;\r\n"; preStrokeData += "\tvar lctx = lcanvas.getContext(\"2d\");\r\n"; preStrokeData += "\tenhanceContext(lctx);\r\n"; - preStrokeData += "\tlctx.applyTransforms(ctx._matrices);\r\n"; + preStrokeData += "\tlctx.applyTransforms(ctx._matrix);\r\n"; preStrokeData += "\tctx = lctx;\r\n"; strokeData = preStrokeData + strokeData; } @Override public void moveTo(double x, double y, double x2, double y2) { + currentDrawCommand = DRAW_COMMAND_M; + pathData += currentDrawCommand + " "; x += deltaX; y += deltaY; x2 += deltaX; y2 += deltaY; - pathData += "\tctx.moveTo(" - + useRatioPos(x, x2) + "," - + useRatioPos(y, y2) + ");\r\n"; + pathData += Helper.doubleStr(x/unitDivisor) + " " + Helper.doubleStr(x2/unitDivisor) + " " + + Helper.doubleStr(y/unitDivisor) + " " + Helper.doubleStr(y2/unitDivisor) + " "; } @Override public void lineTo(double x, double y, double x2, double y2) { + if (!currentDrawCommand.equals(DRAW_COMMAND_L)) { + currentDrawCommand = DRAW_COMMAND_L; + pathData += currentDrawCommand + " "; + } x += deltaX; y += deltaY; x2 += deltaX; y2 += deltaY; - pathData += "\tctx.lineTo(" - + useRatioPos(x, x2) + "," - + useRatioPos(y, y2) + ");\r\n"; + pathData += Helper.doubleStr(x/unitDivisor) + " " + Helper.doubleStr(x2/unitDivisor) + " " + + Helper.doubleStr(y/unitDivisor) + " " + Helper.doubleStr(y2/unitDivisor) + " "; } @Override public void curveTo(double controlX, double controlY, double anchorX, double anchorY, double controlX2, double controlY2, double anchorX2, double anchorY2) { + if (!currentDrawCommand.equals(DRAW_COMMAND_Q)) { + currentDrawCommand = DRAW_COMMAND_Q; + pathData += currentDrawCommand + " "; + } controlX += deltaX; anchorX += deltaX; controlY += deltaY; @@ -409,28 +423,29 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { controlY2 += deltaY; anchorY2 += deltaY; - pathData += "\tctx.quadraticCurveTo(" + useRatioPos(controlX, controlX2) + "," - + useRatioPos(controlY, controlY2) + "," - + useRatioPos(anchorX, anchorX2) + "," - + useRatioPos(anchorY, anchorY2) + ");\r\n"; + pathData += Helper.doubleStr(controlX/unitDivisor) + " " + Helper.doubleStr(controlX2/unitDivisor) + " " + + Helper.doubleStr(controlY/unitDivisor) + " " + Helper.doubleStr(controlY2/unitDivisor) + " " + + Helper.doubleStr(anchorX/unitDivisor) + " " + Helper.doubleStr(anchorX2/unitDivisor) + " " + + Helper.doubleStr(anchorY/unitDivisor) + " " + Helper.doubleStr(anchorY2/unitDivisor) + " "; } protected void finalizePath() { if (!"".equals(pathData)) { - pathData = "\tctx.beginPath();\r\n" + pathData + "\tctx.closePath();\r\n"; + String drawStroke = "\tdrawMorphPath(ctx,\"" + pathData.trim() + "\",ratio,true,scaleMode);\r\n"; + String drawFill = "\tdrawMorphPath(ctx,\"" + pathData.trim() + "\",ratio,false);\r\n";; + pathData = ""; if (lineFillData != null) { String preLineFillData = ""; preLineFillData += "\tvar oldctx = ctx;\r\n"; preLineFillData += "\tctx.save();\r\n"; preLineFillData += strokeData; - preLineFillData += pathData; - preLineFillData += "\tctx.stroke();\r\n"; + preLineFillData += drawStroke; preLineFillData += "\tvar lfcanvas = document.createElement(\"canvas\");\r\n"; preLineFillData += "\tlfcanvas.width = canvas.width;\r\n"; preLineFillData += "\tlfcanvas.height = canvas.height;\r\n"; preLineFillData += "\tvar lfctx = lfcanvas.getContext(\"2d\");\r\n"; preLineFillData += "\tenhanceContext(lfctx);\r\n"; - preLineFillData += "\tlfctx.applyTransforms(ctx._matrices);\r\n"; + preLineFillData += "\tlfctx.applyTransforms(ctx._matrix);\r\n"; preLineFillData += "\tctx = lfctx;"; if (lineLastRadColor != null) { preLineFillData += "\tctx.fillStyle=" + lineLastRadColor + ";\r\n ctx.fill(\"evenodd\");\r\n"; @@ -479,12 +494,12 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase { shapeData += pathData; } else { if (!"".equals(fillData)) { - pathData += "\tctx.fill(\"evenodd\");\r\n"; + pathData += drawFill + "\r\n\tctx.fill(\"evenodd\");\r\n"; } shapeData += fillData + pathData; } if (!"".equals(strokeData)) { - shapeData += "\tctx.stroke();\r\n"; + shapeData += drawStroke+"\r\n"; //"\tctx.stroke();\r\n"; } else if (lineFillData != null) { shapeData += lineFillData; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java index 46bc07041..981d3994b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/morphshape/MorphShapeExporterBase.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.morphshape; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; @@ -396,9 +397,9 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter { if (lineStyle2.noHScaleFlag && lineStyle2.noVScaleFlag) { scaleMode = "NONE"; } else if (lineStyle2.noHScaleFlag) { - scaleMode = "HORIZONTAL"; - } else if (lineStyle2.noVScaleFlag) { scaleMode = "VERTICAL"; + } else if (lineStyle2.noVScaleFlag) { + scaleMode = "HORIZONTAL"; } pixelHintingFlag = lineStyle2.pixelHintingFlag; startCapStyle = lineStyle2.startCapStyle; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java index 6d1942ef3..d2f13538b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/shape/CanvasShapeExporter.java @@ -286,7 +286,8 @@ public class CanvasShapeExporter extends ShapeExporterBase { @Override public void lineStyle(double thickness, RGB color, boolean pixelHinting, String scaleMode, int startCaps, int endCaps, int joints, int miterLimit) { finalizePath(); - thickness /= unitDivisor; + thickness /= SWF.unitDivisor; + strokeData += "\tvar scaleMode = \""+scaleMode+"\";\r\n"; if (color != null) { //gradient lines have no color strokeData += "\tctx.strokeStyle=" + color(color) + ";\r\n"; @@ -374,7 +375,7 @@ public class CanvasShapeExporter extends ShapeExporterBase { preStrokeData += "\tlcanvas.height=canvas.height;\r\n"; preStrokeData += "\tvar lctx = lcanvas.getContext(\"2d\");\r\n"; preStrokeData += "\tenhanceContext(lctx);\r\n"; - preStrokeData += "\tlctx.applyTransforms(ctx._matrices);\r\n"; + preStrokeData += "\tlctx.applyTransforms(ctx._matrix);\r\n"; preStrokeData += "\tctx = lctx;\r\n"; strokeData = preStrokeData + strokeData; } @@ -419,21 +420,21 @@ public class CanvasShapeExporter extends ShapeExporterBase { protected void finalizePath() { if (!"".equals(pathData)) { - pathData = "\tdrawPath(ctx,\"" + pathData + "\");\r\n"; - + String drawStroke = "\tdrawPath(ctx,\"" + pathData.trim() + "\",true,scaleMode);\r\n"; + String drawFill = "\tdrawPath(ctx,\"" + pathData.trim() + "\",false);\r\n";; + pathData = ""; if (lineFillData != null) { String preLineFillData = ""; preLineFillData += "\tvar oldctx = ctx;\r\n"; preLineFillData += "\tctx.save();\r\n"; preLineFillData += strokeData; - preLineFillData += pathData; - preLineFillData += "\tctx.stroke();\r\n"; + preLineFillData += drawStroke; preLineFillData += "\tvar lfcanvas = document.createElement(\"canvas\");\r\n"; preLineFillData += "\tlfcanvas.width = canvas.width;\r\n"; preLineFillData += "\tlfcanvas.height=canvas.height;\r\n"; preLineFillData += "\tvar lfctx = lfcanvas.getContext(\"2d\");\r\n"; preLineFillData += "\tenhanceContext(lfctx);\r\n"; - preLineFillData += "\tlfctx.applyTransforms(ctx._matrices);\r\n"; + preLineFillData += "\tlfctx.applyTransforms(ctx._matrix);\r\n"; preLineFillData += "\tctx = lfctx;"; if (lineLastRadColor != null) { preLineFillData += "\tctx.fillStyle=" + lineLastRadColor + ";\r\n\tctx.fill(\"evenodd\");\r\n"; @@ -482,12 +483,12 @@ public class CanvasShapeExporter extends ShapeExporterBase { shapeData += pathData; } else { if (!"".equals(fillData)) { - pathData += "\tctx.fill(\"evenodd\");\r\n"; + pathData += drawFill + "\tctx.fill(\"evenodd\");\r\n"; } shapeData += fillData + pathData; } if (!"".equals(strokeData)) { - shapeData += "\tctx.stroke();\r\n"; + shapeData += drawStroke +"\r\n"; } else if (lineFillData != null) { shapeData += lineFillData; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/helpers/resource/canvas.js b/libsrc/ffdec_lib/src/com/jpexs/helpers/resource/canvas.js index cbe3a3d13..f66d21ecb 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/helpers/resource/canvas.js +++ b/libsrc/ffdec_lib/src/com/jpexs/helpers/resource/canvas.js @@ -771,17 +771,37 @@ BlendModes.blendCanvas = function(src, dst, result, modeIndex) { }; +function concatMatrix(m1,m2) { + var result= [1,0,0,1,0,0]; + var scaleX = 0; + var rotateSkew0 = 1; + var rotateSkew1= 2; + var scaleY = 3; + var translateX = 4; + var translateY = 5; + + result[scaleX] = m2[scaleX] * m1[scaleX] + m2[rotateSkew1] * m1[rotateSkew0]; + result[rotateSkew0] = m2[rotateSkew0] * m1[scaleX] + m2[scaleY] * m1[rotateSkew0]; + result[rotateSkew1] = m2[scaleX] * m1[rotateSkew1] + m2[rotateSkew1] * m1[scaleY]; + result[scaleY] = m2[rotateSkew0] * m1[rotateSkew1] + m2[scaleY] * m1[scaleY]; + result[translateX] = m2[scaleX] * m1[translateX] + m2[rotateSkew1] * m1[translateY] + m2[translateX]; + result[translateY] = m2[rotateSkew0] * m1[translateX] + m2[scaleY] * m1[translateY] + m2[translateY]; + + return result; + } + + var enhanceContext = function(context) { var m = [1, 0, 0, 1, 0, 0]; - context._matrices = [m]; + context._matrix = m; //the stack of saved matrices - context._savedMatrices = [[m]]; + context._savedMatrices = [m]; //[[m]]; var super_ = context.__proto__; context.__proto__ = ({ save: function() { - this._savedMatrices.push(this._matrices.slice()); + this._savedMatrices.push(this._matrix); //.slice() super_.save.call(this); }, //if the stack of matrices we're managing doesn't have a saved matrix, @@ -790,7 +810,7 @@ var enhanceContext = function(context) { if (this._savedMatrices.length == 0) return; super_.restore.call(this); - this._matrices = this._savedMatrices.pop(); + this._matrix = this._savedMatrices.pop(); }, scale: function(x, y) { super_.scale.call(this, x, y); @@ -802,22 +822,24 @@ var enhanceContext = function(context) { super_.translate.call(this, x, y); }, transform: function(a, b, c, d, e, f) { - this._matrices.push([a, b, c, d, e, f]); + this._matrix = concatMatrix(this._matrix,[a,b,c,d,e,f]); super_.transform.call(this, a, b, c, d, e, f); }, setTransform: function(a, b, c, d, e, f) { - this._matrices = []; - this._matrices.push([a, b, c, d, e, f]); + this._matrix = [a, b, c, d, e, f]; super_.setTransform.call(this, a, b, c, d, e, f); }, resetTransform: function() { super_.resetTransform.call(this); }, applyTransforms: function(m) { - this.setTransform(1, 0, 0, 1, 0, 0); - for (var i = 0; i < m.length; i++) { - this.transform(m[i][0], m[i][1], m[i][2], m[i][3], m[i][4], m[i][5]); - } + this.setTransform(m[0], m[1], m[2], m[3], m[4], m[5]) + }, + applyTransformToPoint: function(p){ + var ret = {}; + ret.x = this._matrix[0]*p.x + this._matrix[1]*p.y + this._matrix[4]; + ret.y = this._matrix[2]*p.x + this._matrix[3]*p.y + this._matrix[5]; + return ret; }, __proto__: super_ }); @@ -964,10 +986,116 @@ function stopDrag(e) { } -function drawPath(ctx, p) { - ctx.beginPath(); +function drawMorphPath(ctx, p, ratio, doStroke, scaleMode){ var parts = p.split(" "); var len = parts.length; + if(doStroke){ + for (var i = 0; i < len; i++) { + switch(parts[i]){ + case '': + break; + case 'L': + case 'M': + case 'Q': + break; + default: + var k = ctx.applyTransformToPoint({x:parts[i],y:parts[i+2]}); parts[i] = k.x; parts[i+2] = k.y; + k = ctx.applyTransformToPoint({x:parts[i+1],y:parts[i+3]}); parts[i+1] = k.x; parts[i+3] = k.y; + i+=3; + } + } + + switch(scaleMode){ + case "NONE": + break; + case "NORMAL": + ctx.lineWidth*=20*Math.max(ctx._matrix[0],ctx._matrix[3]); + break; + case "VERTICAL": + ctx.lineWidth*=20*ctx._matrix[3]; + break; + case "HORIZONTAL": + ctx.lineWidth*=20*ctx._matrix[0]; + break; + } + + ctx.save(); + ctx.setTransform(1,0,0,1,0,0); + } + ctx.beginPath(); + var drawCommand = ""; + for (var i = 0; i < len; i++) { + switch (parts[i]) { + case 'L': + case 'M': + case 'Q': + drawCommand = parts[i]; + break; + default: + switch (drawCommand) { + case 'L': + ctx.lineTo(useRatio(parts[i],parts[i+1],ratio), useRatio(parts[i + 2],parts[i + 3],ratio)); + i += 3; + break; + case 'M': + ctx.moveTo(useRatio(parts[i],parts[i+1],ratio), useRatio(parts[i + 2],parts[i + 3],ratio)); + i += 3; + break; + case 'Q': + ctx.quadraticCurveTo(useRatio(parts[i],parts[i+1],ratio),useRatio(parts[i+2],parts[i+3],ratio), + useRatio(parts[i+4],parts[i+5],ratio),useRatio(parts[i+6],parts[i+7],ratio)); + i += 7; + break; + } + break; + } + } + if(doStroke){ + ctx.stroke(); + ctx.restore(); + } +} + +function useRatio(v1,v2,ratio){ + return v1*1+(v2-v1)*ratio/65535; +} + +function drawPath(ctx, p, doStroke, scaleMode) { + var parts = p.split(" "); + var len = parts.length; + if(doStroke){ + for (var i = 0; i < len; i++) { + switch(parts[i]){ + case 'L': + case 'M': + case 'Q': + break; + default: + var k = ctx.applyTransformToPoint({x:parts[i],y:parts[i+1]}); + parts[i] = k.x; + parts[i+1] = k.y; + i++; + } + } + + switch(scaleMode){ + case "NONE": + break; + case "NORMAL": + ctx.lineWidth*=20*Math.max(ctx._matrix[0],ctx._matrix[3]); + break; + case "VERTICAL": + ctx.lineWidth*=20*ctx._matrix[3]; + break; + case "HORIZONTAL": + ctx.lineWidth*=20*ctx._matrix[0]; + break; + } + + ctx.save(); + ctx.setTransform(1,0,0,1,0,0); + } + ctx.beginPath(); var drawCommand = ""; for (var i = 0; i < len; i++) { switch (parts[i]) { @@ -994,4 +1122,8 @@ function drawPath(ctx, p) { break; } } + if(doStroke){ + ctx.stroke(); + ctx.restore(); + } } \ No newline at end of file