Files
jpexs-decompiler/src/com/jpexs/helpers/resource/canvas.js
T
2014-06-22 09:52:54 +02:00

997 lines
34 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) {
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 ((mask == null) || (mask[index + oldPixel + 3] > 0)) {
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 ((mask == null) || (mask[index + newPixel + 3] > 0)) {
a += pixels[index + newPixel + 3];
r += pixels[index + newPixel];
g += pixels[index + newPixel + 1];
b += pixels[index + newPixel + 2];
hits++;
}
}
if (x >= 0) {
if ((mask == null) || (mask[index + x + 3] > 0)) {
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) {
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 ((mask == null) || (mask[index + oldPixelOffset + 3] > 0)) {
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 ((mask == null) || (mask[index + newPixelOffset + 3] > 0)) {
a += pixels[index + newPixelOffset + 3];
r += pixels[index + newPixelOffset];
g += pixels[index + newPixelOffset + 1];
b += pixels[index + newPixelOffset + 2];
hits++;
}
}
if (y >= 0) {
if ((mask == null) || (mask[y * w * 4 + x + 3] > 0)) {
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) {
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));
Filters._boxBlurVertical(data, mask, canvas.width, canvas.height, Math.floor(vRadius / 2));
}
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 revPixels = [];
for (var i = 0; i < srcPixels.length; i += 4) {
revPixels[i] = srcPixels[i];
revPixels[i + 1] = srcPixels[i + 1];
revPixels[i + 2] = srcPixels[i + 2];
revPixels[i + 3] = 255 - srcPixels[i + 3];
}
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 mask = null;
if (type == Filters.INNER) {
mask = srcPixels;
}
if (type == Filters.OUTER) {
mask = revPixels;
}
retCanvas = Filters.blur(retCanvas, retCanvas.getContext("2d"), blurX, blurY, iterations, mask);
retImg = retCanvas.getContext("2d");
shadow = retImg.getImageData(0, 0, width, height).data;
if (mask != null) {
for (var i = 0; i < mask.length; i += 4) {
if (mask[i + 3] == 0) {
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);
}
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 revPixels = [];
for (var i = 0; i < srcPixels.length; i += 4) {
revPixels[i] = srcPixels[i];
revPixels[i + 1] = srcPixels[i + 1];
revPixels[i + 2] = srcPixels[i + 2];
revPixels[i + 3] = 255 - srcPixels[i + 3];
}
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 mask = null;
if (type == Filters.INNER) {
mask = srcPixels;
}
if (type == Filters.OUTER) {
mask = revPixels;
}
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, mask);
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);
};
var enhanceContext = function(context) {
var m = [1, 0, 0, 1, 0, 0];
context._matrices = [m];
//the stack of saved matrices
context._savedMatrices = [[m]];
var super_ = context.__proto__;
context.__proto__ = ({
save: function() {
this._savedMatrices.push(this._matrices.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._matrices = 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._matrices.push([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]);
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]);
}
},
__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(Math.round(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._matrices);
}
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 drawPath(ctx, p) {
ctx.beginPath();
var parts = p.split(" ");
var len = parts.length;
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(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;
}
}
}