Files
jpexs-decompiler/libsrc/ffdec_lib/src/com/jpexs/helpers/resource/canvas.js
T

1121 lines
39 KiB
JavaScript

/**
* JPEXS Free Flash Decompiler Filters
*/
Filters = {};
var createCanvas = function (width, height) {
var c = document.createElement("canvas");
c.width = width;
c.height = height;
c.style.display = "none";
//temporary add to document to get this work (getImageData, etc.)
document.body.appendChild(c);
document.body.removeChild(c);
return c;
};
Filters._premultiply = function (data) {
var len = data.length;
for (var i = 0; i < len; i += 4) {
var f = data[i + 3] * 0.003921569;
data[i] = Math.round(data[i] * f);
data[i + 1] = Math.round(data[i + 1] * f);
data[i + 2] = Math.round(data[i + 2] * f);
}
};
Filters._unpremultiply = function (data) {
var len = data.length;
for (var i = 0; i < len; i += 4) {
var a = data[i + 3];
if (a == 0 || a == 255) {
continue;
}
var f = 255 / a;
var r = (data[i] * f);
var g = (data[i + 1] * f);
var b = (data[i + 2] * f);
if (r > 255) {
r = 255;
}
if (g > 255) {
g = 255;
}
if (b > 255) {
b = 255;
}
data[i] = r;
data[i + 1] = g;
data[i + 2] = b;
}
};
Filters._boxBlurHorizontal = function (pixels, mask, w, h, radius, maskType) {
var index = 0;
var newColors = [];
for (var y = 0; y < h; y++) {
var hits = 0;
var r = 0;
var g = 0;
var b = 0;
var a = 0;
for (var x = -radius * 4; x < w * 4; x += 4) {
var oldPixel = x - radius * 4 - 4;
if (oldPixel >= 0) {
if ((maskType == 0) || (maskType == 1 && mask[index + oldPixel + 3] > 0) || (maskType == 2 && mask[index + oldPixel + 3] < 255)) {
a -= pixels[index + oldPixel + 3];
r -= pixels[index + oldPixel];
g -= pixels[index + oldPixel + 1];
b -= pixels[index + oldPixel + 2];
hits--;
}
}
var newPixel = x + radius * 4;
if (newPixel < w * 4) {
if ((maskType == 0) || (maskType == 1 && mask[index + newPixel + 3] > 0) || (maskType == 2 && mask[index + newPixel + 3] < 255)) {
a += pixels[index + newPixel + 3];
r += pixels[index + newPixel];
g += pixels[index + newPixel + 1];
b += pixels[index + newPixel + 2];
hits++;
}
}
if (x >= 0) {
if ((maskType == 0) || (maskType == 1 && mask[index + x + 3] > 0) || (maskType == 2 && mask[index + x + 3] < 255)) {
if (hits == 0) {
newColors[x] = 0;
newColors[x + 1] = 0;
newColors[x + 2] = 0;
newColors[x + 3] = 0;
} else {
newColors[x] = Math.round(r / hits);
newColors[x + 1] = Math.round(g / hits);
newColors[x + 2] = Math.round(b / hits);
newColors[x + 3] = Math.round(a / hits);
}
} else {
newColors[x] = 0;
newColors[x + 1] = 0;
newColors[x + 2] = 0;
newColors[x + 3] = 0;
}
}
}
for (var p = 0; p < w * 4; p += 4) {
pixels[index + p] = newColors[p];
pixels[index + p + 1] = newColors[p + 1];
pixels[index + p + 2] = newColors[p + 2];
pixels[index + p + 3] = newColors[p + 3];
}
index += w * 4;
}
};
Filters._boxBlurVertical = function (pixels, mask, w, h, radius, maskType) {
var newColors = [];
var oldPixelOffset = -(radius + 1) * w * 4;
var newPixelOffset = (radius) * w * 4;
for (var x = 0; x < w * 4; x += 4) {
var hits = 0;
var r = 0;
var g = 0;
var b = 0;
var a = 0;
var index = -radius * w * 4 + x;
for (var y = -radius; y < h; y++) {
var oldPixel = y - radius - 1;
if (oldPixel >= 0) {
if ((maskType == 0) || (maskType == 1 && mask[index + oldPixelOffset + 3] > 0) || (maskType == 2 && mask[index + oldPixelOffset + 3] < 255)) {
a -= pixels[index + oldPixelOffset + 3];
r -= pixels[index + oldPixelOffset];
g -= pixels[index + oldPixelOffset + 1];
b -= pixels[index + oldPixelOffset + 2];
hits--;
}
}
var newPixel = y + radius;
if (newPixel < h) {
if ((maskType == 0) || (maskType == 1 && mask[index + newPixelOffset + 3] > 0) || (maskType == 2 && mask[index + newPixelOffset + 3] < 255)) {
a += pixels[index + newPixelOffset + 3];
r += pixels[index + newPixelOffset];
g += pixels[index + newPixelOffset + 1];
b += pixels[index + newPixelOffset + 2];
hits++;
}
}
if (y >= 0) {
if ((maskType == 0) || (maskType == 1 && mask[y * w * 4 + x + 3] > 0) || (maskType == 2 && mask[y * w * 4 + x + 3] < 255)) {
if (hits == 0) {
newColors[4 * y] = 0;
newColors[4 * y + 1] = 0;
newColors[4 * y + 2] = 0;
newColors[4 * y + 3] = 0;
} else {
newColors[4 * y] = Math.round(r / hits);
newColors[4 * y + 1] = Math.round(g / hits);
newColors[4 * y + 2] = Math.round(b / hits);
newColors[4 * y + 3] = Math.round(a / hits);
}
} else {
newColors[4 * y] = 0;
newColors[4 * y + 1] = 0;
newColors[4 * y + 2] = 0;
newColors[4 * y + 3] = 0;
}
}
index += w * 4;
}
for (var y = 0; y < h; y++) {
pixels[y * w * 4 + x] = newColors[4 * y];
pixels[y * w * 4 + x + 1] = newColors[4 * y + 1];
pixels[y * w * 4 + x + 2] = newColors[4 * y + 2];
pixels[y * w * 4 + x + 3] = newColors[4 * y + 3];
}
}
};
Filters.blur = function (canvas, ctx, hRadius, vRadius, iterations, mask, maskType) {
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = imgData.data;
Filters._premultiply(data);
for (var i = 0; i < iterations; i++) {
Filters._boxBlurHorizontal(data, mask, canvas.width, canvas.height, Math.floor(hRadius / 2), maskType);
Filters._boxBlurVertical(data, mask, canvas.width, canvas.height, Math.floor(vRadius / 2), maskType);
}
Filters._unpremultiply(data);
var width = canvas.width;
var height = canvas.height;
var retCanvas = createCanvas(width, height);
var retImg = retCanvas.getContext("2d");
retImg.putImageData(imgData, 0, 0);
return retCanvas;
}
Filters._moveRGB = function (width, height, rgb, deltaX, deltaY, fill) {
var img = createCanvas(width, height);
var ig = img.getContext("2d");
Filters._setRGB(ig, 0, 0, width, height, rgb);
var retImg = createCanvas(width, height);
retImg.width = width;
retImg.heigth = height;
var g = retImg.getContext("2d");
g.fillStyle = fill;
g.globalCompositeOperation = "copy";
g.fillRect(0, 0, width, height);
g.drawImage(img, deltaX, deltaY);
return g.getImageData(0, 0, width, height).data;
};
Filters.FULL = 1;
Filters.INNER = 2;
Filters.OUTER = 3;
Filters._setRGB = function (ctx, x, y, width, height, data) {
var id = ctx.createImageData(width, height);
for (var i = 0; i < data.length; i++) {
id.data[i] = data[i];
}
ctx.putImageData(id, x, y);
};
Filters.gradientGlow = function (srcCanvas, src, blurX, blurY, angle, distance, colors, ratios, type, iterations, strength, knockout) {
var width = canvas.width;
var height = canvas.height;
var retCanvas = createCanvas(width, height);
var retImg = retCanvas.getContext("2d");
var gradCanvas = createCanvas(256, 1);
var gradient = gradCanvas.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 255, 0);
for (var s = 0; s < colors.length; s++) {
var v = "rgba(" + colors[s][0] + "," + colors[s][1] + "," + colors[s][2] + "," + colors[s][3] + ")";
grd.addColorStop(ratios[s], v);
}
gradient.fillStyle = grd;
gradient.fillRect(0, 0, 256, 1);
var gradientPixels = gradient.getImageData(0, 0, gradCanvas.width, gradCanvas.height).data;
var angleRad = angle / 180 * Math.PI;
var moveX = (distance * Math.cos(angleRad));
var moveY = (distance * Math.sin(angleRad));
var srcPixels = src.getImageData(0, 0, width, height).data;
var shadow = [];
for (var i = 0; i < srcPixels.length; i += 4) {
var alpha = srcPixels[i + 3];
shadow[i] = 0;
shadow[i + 1] = 0;
shadow[i + 2] = 0;
shadow[i + 3] = Math.round(alpha * strength);
}
var colorAlpha = "rgba(0,0,0,0)";
shadow = Filters._moveRGB(width, height, shadow, moveX, moveY, colorAlpha);
Filters._setRGB(retImg, 0, 0, width, height, shadow);
var maskType = 0;
if (type == Filters.INNER) {
maskType = 1;
}
if (type == Filters.OUTER) {
maskType = 2;
}
retCanvas = Filters.blur(retCanvas, retCanvas.getContext("2d"), blurX, blurY, iterations, srcPixels, maskType);
retImg = retCanvas.getContext("2d");
shadow = retImg.getImageData(0, 0, width, height).data;
if (maskType != 0) {
for (var i = 0; i < srcPixels.length; i += 4) {
if ((maskType == 1 && srcPixels[i + 3] == 0) || (maskType == 2 && srcPixels[i + 3] == 255)) {
shadow[i] = 0;
shadow[i + 1] = 0;
shadow[i + 2] = 0;
shadow[i + 3] = 0;
}
}
}
for (var i = 0; i < shadow.length; i += 4) {
var a = shadow[i + 3];
shadow[i] = gradientPixels[a * 4];
shadow[i + 1] = gradientPixels[a * 4 + 1];
shadow[i + 2] = gradientPixels[a * 4 + 2];
shadow[i + 3] = gradientPixels[a * 4 + 3];
}
Filters._setRGB(retImg, 0, 0, width, height, shadow);
if (!knockout) {
retImg.globalCompositeOperation = "destination-over";
retImg.drawImage(srcCanvas, 0, 0);
}
return retCanvas;
};
Filters.dropShadow = function (canvas, src, blurX, blurY, angle, distance, color, inner, iterations, strength, knockout) {
var width = canvas.width;
var height = canvas.height;
var srcPixels = src.getImageData(0, 0, width, height).data;
var shadow = [];
for (var i = 0; i < srcPixels.length; i += 4) {
var alpha = srcPixels[i + 3];
if (inner) {
alpha = 255 - alpha;
}
shadow[i] = color[0];
shadow[i + 1] = color[1];
shadow[i + 2] = color[2];
var sa = color[3] * alpha * strength;
if (sa > 255)
sa = 255;
shadow[i + 3] = Math.round(sa);
}
var colorFirst = "#000000";
var colorAlpha = "rgba(0,0,0,0)";
var angleRad = angle / 180 * Math.PI;
var moveX = (distance * Math.cos(angleRad));
var moveY = (distance * Math.sin(angleRad));
shadow = Filters._moveRGB(width, height, shadow, moveX, moveY, inner ? colorFirst : colorAlpha);
var retCanvas = createCanvas(canvas.width, canvas.height);
Filters._setRGB(retCanvas.getContext("2d"), 0, 0, width, height, shadow);
if (blurX > 0 || blurY > 0) {
retCanvas = Filters.blur(retCanvas, retCanvas.getContext("2d"), blurX, blurY, iterations, null, 0);
}
shadow = retCanvas.getContext("2d").getImageData(0, 0, width, height).data;
var srcPixels = src.getImageData(0, 0, width, height).data;
for (var i = 0; i < shadow.length; i += 4) {
var mask = srcPixels[i + 3];
if (!inner) {
mask = 255 - mask;
}
shadow[i + 3] = mask * shadow[i + 3] / 255;
}
Filters._setRGB(retCanvas.getContext("2d"), 0, 0, width, height, shadow);
if (!knockout) {
var g = retCanvas.getContext("2d");
g.globalCompositeOperation = "destination-over";
g.drawImage(canvas, 0, 0);
}
return retCanvas;
};
Filters._cut = function (a, min, max) {
if (a > max)
a = max;
if (a < min)
a = min;
return a;
}
Filters.gradientBevel = function (canvas, src, colors, ratios, blurX, blurY, strength, type, angle, distance, knockout, iterations) {
var width = canvas.width;
var height = canvas.height;
var retImg = createCanvas(width, height);
var srcPixels = src.getImageData(0, 0, width, height).data;
var gradient = createCanvas(512, 1);
var gg = gradient.getContext("2d");
var grd = ctx.createLinearGradient(0, 0, 511, 0);
for (var s = 0; s < colors.length; s++) {
var v = "rgba(" + colors[s][0] + "," + colors[s][1] + "," + colors[s][2] + "," + colors[s][3] + ")";
grd.addColorStop(ratios[s], v);
}
gg.fillStyle = grd;
gg.globalCompositeOperation = "copy";
gg.fillRect(0, 0, gradient.width, gradient.height);
var gradientPixels = gg.getImageData(0, 0, gradient.width, gradient.height).data;
if (type != Filters.OUTER) {
var hilightIm = Filters.dropShadow(canvas, src, 0, 0, angle, distance, [255, 0, 0, 1], true, iterations, strength, true);
var shadowIm = Filters.dropShadow(canvas, src, 0, 0, angle + 180, distance, [0, 0, 255, 1], true, iterations, strength, true);
var h2 = createCanvas(width, height);
var s2 = createCanvas(width, height);
var hc = h2.getContext("2d");
var sc = s2.getContext("2d");
hc.drawImage(hilightIm, 0, 0);
hc.globalCompositeOperation = "destination-out";
hc.drawImage(shadowIm, 0, 0);
sc.drawImage(shadowIm, 0, 0);
sc.globalCompositeOperation = "destination-out";
sc.drawImage(hilightIm, 0, 0);
var shadowInner = s2;
var hilightInner = h2;
}
if (type != Filters.INNER) {
var hilightIm = Filters.dropShadow(canvas, src, 0, 0, angle + 180, distance, [255, 0, 0, 1], false, iterations, strength, true);
var shadowIm = Filters.dropShadow(canvas, src, 0, 0, angle, distance, [0, 0, 255, 1], false, iterations, strength, true);
var h2 = createCanvas(width, height);
var s2 = createCanvas(width, height);
var hc = h2.getContext("2d");
var sc = s2.getContext("2d");
hc.drawImage(hilightIm, 0, 0);
hc.globalCompositeOperation = "destination-out";
hc.drawImage(shadowIm, 0, 0);
sc.drawImage(shadowIm, 0, 0);
sc.globalCompositeOperation = "destination-out";
sc.drawImage(hilightIm, 0, 0);
var shadowOuter = s2;
var hilightOuter = h2;
}
var hilightIm;
var shadowIm;
switch (type)
{
case Filters.OUTER:
hilightIm = hilightOuter;
shadowIm = shadowOuter;
break;
case Filters.INNER:
hilightIm = hilightInner;
shadowIm = shadowInner;
break;
case Filters.FULL:
hilightIm = hilightInner;
shadowIm = shadowInner;
var hc = hilightIm.getContext("2d");
hc.globalCompositeOperation = "source-over";
hc.drawImage(hilightOuter, 0, 0);
var sc = shadowIm.getContext("2d");
sc.globalCompositeOperation = "source-over";
sc.drawImage(shadowOuter, 0, 0);
break;
}
var maskType = 0;
if (type == Filters.INNER) {
maskType = 1;
}
if (type == Filters.OUTER) {
maskType = 2;
}
var retc = retImg.getContext("2d");
retc.fillStyle = "#000000";
retc.fillRect(0, 0, width, height);
retc.drawImage(shadowIm, 0, 0);
retc.drawImage(hilightIm, 0, 0);
retImg = Filters.blur(retImg, retImg.getContext("2d"), blurX, blurY, iterations, srcPixels, maskType);
var ret = retImg.getContext("2d").getImageData(0, 0, width, height).data;
for (var i = 0; i < srcPixels.length; i += 4) {
var ah = ret[i] * strength;
var as = ret[i + 2] * strength;
var ra = Filters._cut(ah - as, -255, 255);
ret[i] = gradientPixels[4 * (255 + ra)];
ret[i + 1] = gradientPixels[4 * (255 + ra) + 1];
ret[i + 2] = gradientPixels[4 * (255 + ra) + 2];
ret[i + 3] = gradientPixels[4 * (255 + ra) + 3];
}
Filters._setRGB(retImg.getContext("2d"), 0, 0, width, height, ret);
if (!knockout) {
var g = retImg.getContext("2d");
g.globalCompositeOperation = "destination-over";
g.drawImage(canvas, 0, 0);
}
return retImg;
}
Filters.bevel = function (canvas, src, blurX, blurY, strength, type, highlightColor, shadowColor, angle, distance, knockout, iterations) {
return Filters.gradientBevel(canvas, src, [
shadowColor,
[shadowColor[0], shadowColor[1], shadowColor[2], 0],
[highlightColor[0], highlightColor[1], highlightColor[2], 0],
highlightColor
], [0, 127 / 255, 128 / 255, 1], blurX, blurY, strength, type, angle, distance, knockout, iterations);
}
//http://www.html5rocks.com/en/tutorials/canvas/imagefilters/
Filters.convolution = function (canvas, ctx, weights, opaque) {
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
var side = Math.round(Math.sqrt(weights.length));
var halfSide = Math.floor(side / 2);
var src = pixels.data;
var sw = pixels.width;
var sh = pixels.height;
// pad output by the convolution matrix
var w = sw;
var h = sh;
var outCanvas = createCanvas(w, h);
var outCtx = outCanvas.getContext("2d");
var output = outCtx.getImageData(0, 0, w, h);
var dst = output.data;
// go through the destination image pixels
var alphaFac = opaque ? 1 : 0;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
var sy = y;
var sx = x;
var dstOff = (y * w + x) * 4;
// calculate the weighed sum of the source image pixels that
// fall under the convolution matrix
var r = 0, g = 0, b = 0, a = 0;
for (var cy = 0; cy < side; cy++) {
for (var cx = 0; cx < side; cx++) {
var scy = sy + cy - halfSide;
var scx = sx + cx - halfSide;
if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) {
var srcOff = (scy * sw + scx) * 4;
var wt = weights[cy * side + cx];
r += src[srcOff] * wt;
g += src[srcOff + 1] * wt;
b += src[srcOff + 2] * wt;
a += src[srcOff + 3] * wt;
}
}
}
dst[dstOff] = r;
dst[dstOff + 1] = g;
dst[dstOff + 2] = b;
dst[dstOff + 3] = a + alphaFac * (255 - a);
}
}
outCtx.putImageData(output, 0, 0);
return outCanvas;
};
Filters.colorMatrix = function (canvas, ctx, m) {
var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
var data = pixels.data;
for (var i = 0; i < data.length; i += 4)
{
var r = i;
var g = i + 1;
var b = i + 2;
var a = i + 3;
var oR = data[r];
var oG = data[g];
var oB = data[b];
var oA = data[a];
data[r] = (m[0] * oR) + (m[1] * oG) + (m[2] * oB) + (m[3] * oA) + m[4];
data[g] = (m[5] * oR) + (m[6] * oG) + (m[7] * oB) + (m[8] * oA) + m[9];
data[b] = (m[10] * oR) + (m[11] * oG) + (m[12] * oB) + (m[13] * oA) + m[14];
data[a] = (m[15] * oR) + (m[16] * oG) + (m[17] * oB) + (m[18] * oA) + m[19];
}
var outCanvas = createCanvas(canvas.width, canvas.height);
var outCtx = outCanvas.getContext("2d");
outCtx.putImageData(pixels, 0, 0);
return outCanvas;
};
Filters.glow = function (canvas, src, blurX, blurY, strength, color, inner, knockout, iterations) {
return Filters.dropShadow(canvas, src, blurX, blurY, 45, 0, color, inner, iterations, strength, knockout);
};
var BlendModes = {};
BlendModes._cut = function (v) {
if (v < 0)
v = 0;
if (v > 255)
v = 255;
return v;
};
BlendModes.normal = function (src, dst, result, pos) {
var am = (255 - src[pos + 3]) / 255;
result[pos] = this._cut(src[pos] * src[pos + 3] / 255 + dst[pos] * dst[pos + 3] / 255 * am);
result[pos + 1] = this._cut(src[pos + 1] * src[pos + 3] / 255 + dst[pos + 1] * dst[pos + 3] / 255 * am);
result[pos + 2] = this._cut(src[pos + 2] * src[pos + 3] / 255 + dst[pos + 2] * dst[pos + 3] / 255 * am);
result[pos + 3] = this._cut(src[pos + 3] + dst[pos + 3] * am);
};
BlendModes.layer = function (src, dst, result, pos) {
BlendModes.normal(src, dst, result, pos);
};
BlendModes.multiply = function (src, dst, result, pos) {
result[pos + 0] = (src[pos + 0] * dst[pos + 0]) >> 8;
result[pos + 1] = (src[pos + 1] * dst[pos + 1]) >> 8;
result[pos + 2] = (src[pos + 2] * dst[pos + 2]) >> 8;
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.screen = function (src, dst, result, pos) {
result[pos + 0] = 255 - ((255 - src[pos + 0]) * (255 - dst[pos + 0]) >> 8);
result[pos + 1] = 255 - ((255 - src[pos + 1]) * (255 - dst[pos + 1]) >> 8);
result[pos + 2] = 255 - ((255 - src[pos + 2]) * (255 - dst[pos + 2]) >> 8);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.lighten = function (src, dst, result, pos) {
result[pos + 0] = Math.max(src[pos + 0], dst[pos + 0]);
result[pos + 1] = Math.max(src[pos + 1], dst[pos + 1]);
result[pos + 2] = Math.max(src[pos + 2], dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.darken = function (src, dst, result, pos) {
result[pos + 0] = Math.min(src[pos + 0], dst[pos + 0]);
result[pos + 1] = Math.min(src[pos + 1], dst[pos + 1]);
result[pos + 2] = Math.min(src[pos + 2], dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.difference = function (src, dst, result, pos) {
result[pos + 0] = Math.abs(dst[pos + 0] - src[pos + 0]);
result[pos + 1] = Math.abs(dst[pos + 1] - src[pos + 1]);
result[pos + 2] = Math.abs(dst[pos + 2] - src[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.add = function (src, dst, result, pos) {
result[pos + 0] = Math.min(255, src[pos + 0] + dst[pos + 0]);
result[pos + 1] = Math.min(255, src[pos + 1] + dst[pos + 1]);
result[pos + 2] = Math.min(255, src[pos + 2] + dst[pos + 2]);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3]);
};
BlendModes.subtract = function (src, dst, result, pos) {
result[pos + 0] = Math.max(0, src[pos + 0] + dst[pos + 0] - 256);
result[pos + 1] = Math.max(0, src[pos + 1] + dst[pos + 1] - 256);
result[pos + 2] = Math.max(0, src[pos + 2] + dst[pos + 2] - 256);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.invert = function (src, dst, result, pos) {
result[pos + 0] = 255 - dst[pos + 0];
result[pos + 1] = 255 - dst[pos + 1];
result[pos + 2] = 255 - dst[pos + 2];
result[pos + 3] = src[pos + 3];
};
BlendModes.alpha = function (src, dst, result, pos) {
result[pos + 0] = src[pos + 0];
result[pos + 1] = src[pos + 1];
result[pos + 2] = src[pos + 2];
result[pos + 3] = dst[pos + 3]; //?
};
BlendModes.erase = function (src, dst, result, pos) {
result[pos + 0] = src[pos + 0];
result[pos + 1] = src[pos + 1];
result[pos + 2] = src[pos + 2];
result[pos + 3] = 255 - dst[pos + 3]; //?
};
BlendModes.overlay = function (src, dst, result, pos) {
result[pos + 0] = dst[pos + 0] < 128 ? dst[pos + 0] * src[pos + 0] >> 7
: 255 - ((255 - dst[pos + 0]) * (255 - src[pos + 0]) >> 7);
result[pos + 1] = dst[pos + 1] < 128 ? dst[pos + 1] * src[pos + 1] >> 7
: 255 - ((255 - dst[pos + 1]) * (255 - src[pos + 1]) >> 7);
result[pos + 2] = dst[pos + 2] < 128 ? dst[pos + 2] * src[pos + 2] >> 7
: 255 - ((255 - dst[pos + 2]) * (255 - src[pos + 2]) >> 7);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes.hardlight = function (src, dst, result, pos) {
result[pos + 0] = src[pos + 0] < 128 ? dst[pos + 0] * src[pos + 0] >> 7
: 255 - ((255 - src[pos + 0]) * (255 - dst[pos + 0]) >> 7);
result[pos + 1] = src[pos + 1] < 128 ? dst[pos + 1] * src[pos + 1] >> 7
: 255 - ((255 - src[pos + 1]) * (255 - dst[pos + 1]) >> 7);
result[pos + 2] = src[pos + 2] < 128 ? dst[pos + 2] * src[pos + 2] >> 7
: 255 - ((255 - src[pos + 2]) * (255 - dst[pos + 2]) >> 7);
result[pos + 3] = Math.min(255, src[pos + 3] + dst[pos + 3] - (src[pos + 3] * dst[pos + 3]) / 255);
};
BlendModes._list = [
BlendModes.normal,
BlendModes.normal,
BlendModes.layer,
BlendModes.multiply,
BlendModes.screen,
BlendModes.lighten,
BlendModes.darken,
BlendModes.difference,
BlendModes.add,
BlendModes.subtract,
BlendModes.invert,
BlendModes.alpha,
BlendModes.erase,
BlendModes.overlay,
BlendModes.hardlight
];
BlendModes.blendData = function (srcPixel, dstPixel, retData, modeIndex) {
var result = [];
var retPixel = [];
var alpha = 1.0;
for (var i = 0; i < retData.length; i += 4) {
this._list[modeIndex](srcPixel, dstPixel, result, i);
retPixel[i + 0] = this._cut(dstPixel[i + 0] + (result[i + 0] - dstPixel[i + 0]) * alpha);
retPixel[i + 1] = this._cut(dstPixel[i + 1] + (result[i + 1] - dstPixel[i + 1]) * alpha);
retPixel[i + 2] = this._cut(dstPixel[i + 2] + (result[i + 2] - dstPixel[i + 2]) * alpha);
retPixel[i + 3] = this._cut(dstPixel[i + 3] + (result[i + 3] - dstPixel[i + 3]) * alpha);
var af = srcPixel[i + 3] / 255;
retData[i + 0] = this._cut((1 - af) * dstPixel[i + 0] + af * retPixel[i + 0]);
retData[i + 1] = this._cut((1 - af) * dstPixel[i + 1] + af * retPixel[i + 1]);
retData[i + 2] = this._cut((1 - af) * dstPixel[i + 2] + af * retPixel[i + 2]);
retData[i + 3] = this._cut((1 - af) * dstPixel[i + 3] + af * retPixel[i + 3]);
}
};
BlendModes.blendCanvas = function (src, dst, result, modeIndex) {
var width = src.width;
var height = src.height;
var rctx = result.getContext("2d");
var sctx = src.getContext("2d");
var dctx = dst.getContext("2d");
var ridata = rctx.getImageData(0, 0, width, height);
var sidata = sctx.getImageData(0, 0, width, height);
var didata = dctx.getImageData(0, 0, width, height);
this.blendData(sidata.data, didata.data, ridata.data, modeIndex);
rctx.putImageData(ridata, 0, 0);
};
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._matrix = m;
//the stack of saved matrices
context._savedMatrices = [m]; //[[m]];
var super_ = context.__proto__;
context.__proto__ = ({
save: function () {
this._savedMatrices.push(this._matrix); //.slice()
super_.save.call(this);
},
//if the stack of matrices we're managing doesn't have a saved matrix,
//we won't even call the context's original `restore` method.
restore: function () {
if (this._savedMatrices.length == 0)
return;
super_.restore.call(this);
this._matrix = this._savedMatrices.pop();
},
scale: function (x, y) {
super_.scale.call(this, x, y);
},
rotate: function (theta) {
super_.rotate.call(this, theta);
},
translate: function (x, y) {
super_.translate.call(this, x, y);
},
transform: function (a, b, c, d, e, f) {
this._matrix = concatMatrix([a, b, c, d, e, f], this._matrix);
super_.transform.call(this, a, b, c, d, e, f);
},
setTransform: function (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(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[2] * p.y + this._matrix[4];
ret.y = this._matrix[1] * p.x + this._matrix[3] * p.y + this._matrix[5];
return ret;
},
__proto__: super_
});
return context;
};
var cxform = function (r_add, g_add, b_add, a_add, r_mult, g_mult, b_mult, a_mult) {
this.r_add = r_add;
this.g_add = g_add;
this.b_add = b_add;
this.a_add = a_add;
this.r_mult = r_mult;
this.g_mult = g_mult;
this.b_mult = b_mult;
this.a_mult = a_mult;
this._cut = function (v, min, max) {
if (v < min)
v = min;
if (v > max)
v = max;
return v;
};
this.apply = function (c) {
var d = c;
d[0] = this._cut(Math.round(d[0] * this.r_mult / 255 + this.r_add), 0, 255);
d[1] = this._cut(Math.round(d[1] * this.g_mult / 255 + this.g_add), 0, 255);
d[2] = this._cut(Math.round(d[2] * this.b_mult / 255 + this.b_add), 0, 255);
d[3] = this._cut(d[3] * this.a_mult / 255 + this.a_add / 255, 0, 1);
return d;
};
this.applyToImage = function (fimg) {
if (this.isEmpty()) {
return fimg
}
;
var icanvas = createCanvas(fimg.width, fimg.height);
var ictx = icanvas.getContext("2d");
ictx.drawImage(fimg, 0, 0);
var imdata = ictx.getImageData(0, 0, icanvas.width, icanvas.height);
var idata = imdata.data;
for (var i = 0; i < idata.length; i += 4) {
var c = this.apply([idata[i], idata[i + 1], idata[i + 2], idata[i + 3] / 255]);
idata[i] = c[0];
idata[i + 1] = c[1];
idata[i + 2] = c[2];
idata[i + 3] = Math.round(c[3] * 255);
}
ictx.putImageData(imdata, 0, 0);
return icanvas;
};
this.merge = function (cx) {
return new cxform(this.r_add + cx.r_add, this.g_add + cx.g_add, this.b_add + cx.b_add, this.a_add + cx.a_add, this.r_mult * cx.r_mult / 255, this.g_mult * cx.g_mult / 255, this.b_mult * cx.b_mult / 255, this.a_mult * cx.a_mult / 255);
};
this.isEmpty = function () {
return this.r_add == 0 && this.g_add == 0 && this.b_add == 0 && this.a_add == 0 && this.r_mult == 255 && this.g_mult == 255 && this.b_mult == 255 && this.a_mult == 255;
};
};
var place = function (obj, canvas, ctx, matrix, ctrans, blendMode, frame, ratio, time) {
ctx.save();
ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]);
if (blendMode > 1) {
var oldctx = ctx;
var ncanvas = createCanvas(canvas.width, canvas.height);
ctx = ncanvas.getContext("2d");
enhanceContext(ctx);
ctx.applyTransforms(oldctx._matrix);
}
if (blendMode > 1) {
eval(obj + "(ctx,new cxform(0,0,0,0,255,255,255,255),frame,ratio,time);");
} else {
eval(obj + "(ctx,ctrans,frame,ratio,time);");
}
if (blendMode > 1) {
BlendModes.blendCanvas(ctrans.applyToImage(ncanvas), canvas, canvas, blendMode);
ctx = oldctx;
}
ctx.restore();
}
var tocolor = function (c) {
var r = "rgba(" + c[0] + "," + c[1] + "," + c[2] + "," + c[3] + ")";
return r;
};
window.addEventListener('load', function () {
var wsize = document.getElementById("width_size");
var hsize = document.getElementById("height_size");
//var bsize = document.getElementById("both_size");
//bsize.addEventListener('mousedown', initDragBoth, false);
wsize.addEventListener('mousedown', initDragWidth, false);
hsize.addEventListener('mousedown', initDragHeight, false);
});
var startWidth = 0;
var startHeight = 0;
var dragWidth = false;
var dragHeight = false;
function initDragWidth(e) {
dragWidth = true;
dragHeight = false;
initDrag(e);
}
function initDragHeight(e) {
dragWidth = false;
dragHeight = true;
initDrag(e);
}
function initDragBoth(e) {
dragWidth = true;
dragHeight = true;
initDrag(e);
}
function initDrag(e) {
startX = e.clientX;
startY = e.clientY;
startWidth = canvas.width;
startHeight = canvas.height;
document.documentElement.addEventListener('mousemove', doDrag, false);
document.documentElement.addEventListener('mouseup', stopDrag, false);
}
function doDrag(e) {
if (dragWidth) {
canvas.width = (startWidth + e.clientX - startX);
canvas.height = canvas.width * originalHeight / originalWidth;
} else if (dragHeight) {
canvas.height = (startHeight + e.clientY - startY);
canvas.width = canvas.height * originalWidth / originalHeight;
}
drawFrame();
}
function stopDrag(e) {
document.documentElement.removeEventListener('mousemove', doDrag, false);
document.documentElement.removeEventListener('mouseup', stopDrag, false);
}
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':
case 'Z':
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]) {
case 'L':
case 'M':
case 'Q':
drawCommand = parts[i];
break;
case 'Z':
ctx.closePath();
break;
default:
switch (drawCommand) {
case 'L':
ctx.lineTo(parts[i], parts[i + 1]);
i++;
break;
case 'M':
ctx.moveTo(parts[i], parts[i + 1]);
i++;
break;
case 'Q':
ctx.quadraticCurveTo(parts[i], parts[i + 1], parts[i + 2], parts[i + 3]);
i += 3;
break;
}
break;
}
}
if (doStroke) {
ctx.stroke();
ctx.restore();
}
}