mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-09-25 11:10:56 +00:00
997 lines
34 KiB
JavaScript
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;
|
|
}
|
|
}
|
|
} |