77 lines
2.2 KiB
JavaScript
77 lines
2.2 KiB
JavaScript
// Image imageIn, Array kernel, function (Error error, Image imageOut)
|
|
// precondition: Image is loaded
|
|
// returns loaded Image to asynchronous callback function
|
|
function convolve(imageIn, kernel, callback) {
|
|
var dim = Math.sqrt(kernel.length),
|
|
pad = Math.floor(dim / 2);
|
|
|
|
if (dim % 2 !== 1) {
|
|
return callback(new RangeError("Invalid kernel dimension"), null);
|
|
}
|
|
|
|
var w = imageIn.width,
|
|
h = imageIn.height,
|
|
can = document.createElement('canvas'),
|
|
cw,
|
|
ch,
|
|
ctx,
|
|
imgIn, imgOut,
|
|
datIn, datOut;
|
|
|
|
can.width = cw = w + pad * 2; // add padding
|
|
can.height = ch = h + pad * 2; // add padding
|
|
|
|
ctx = can.getContext('2d');
|
|
ctx.fillStyle = '#000'; // fill with opaque black
|
|
ctx.fillRect(0, 0, cw, ch);
|
|
ctx.drawImage(imageIn, pad, pad);
|
|
|
|
imgIn = ctx.getImageData(0, 0, cw, ch);
|
|
datIn = imgIn.data;
|
|
|
|
imgOut = ctx.createImageData(w, h);
|
|
datOut = imgOut.data;
|
|
|
|
var row, col, pix, i, dx, dy, r, g, b;
|
|
|
|
for (row = pad; row <= h; row++) {
|
|
for (col = pad; col <= w; col++) {
|
|
r = g = b = 0;
|
|
|
|
for (dx = -pad; dx <= pad; dx++) {
|
|
for (dy = -pad; dy <= pad; dy++) {
|
|
i = (dy + pad) * dim + (dx + pad); // kernel index
|
|
pix = 4 * ((row + dy) * cw + (col + dx)); // image index
|
|
r += datIn[pix++] * kernel[i];
|
|
g += datIn[pix++] * kernel[i];
|
|
b += datIn[pix ] * kernel[i];
|
|
}
|
|
}
|
|
|
|
pix = 4 * ((row - pad) * w + (col - pad)); // destination index
|
|
datOut[pix++] = (r + .5) ^ 0;
|
|
datOut[pix++] = (g + .5) ^ 0;
|
|
datOut[pix++] = (b + .5) ^ 0;
|
|
datOut[pix ] = 255; // we want opaque image
|
|
}
|
|
}
|
|
|
|
// reuse canvas
|
|
can.width = w;
|
|
can.height = h;
|
|
|
|
ctx.putImageData(imgOut, 0, 0);
|
|
|
|
var imageOut = new Image();
|
|
|
|
imageOut.addEventListener('load', function () {
|
|
callback(null, imageOut);
|
|
});
|
|
|
|
imageOut.addEventListener('error', function (error) {
|
|
callback(error, null);
|
|
});
|
|
|
|
imageOut.src = can.toDataURL('image/png');
|
|
}
|