var ImageFilters = {};
// Filter
ImageFilters.utils = {
initSampleCanvas: function() {
// wx.createCanvasContext(canvasid, this)
var _canvas = {} //document.createElement('canvas'),
var _context = {} //_canvas.getContext('2d');
_canvas.width = 0;
_canvas.height = 0;
this.getSampleCanvas = function() {
return _canvas;
};
this.getSampleContext = function() {
return _context;
};
this.createImageData = (_context.createImageData) ? function(w, h) {
return {
data: new Uint8ClampedArray(4 * w * h),
width: w,
height: h
}
// return _context.createImageData(w, h);
} : function(w, h) {
return {
data: new Uint8ClampedArray(4 * w * h),
width: w,
height: h
}
// return new ImageData(w, h);
};
},
getSampleCanvas: function() {
this.initSampleCanvas();
return this.getSampleCanvas();
},
getSampleContext: function() {
this.initSampleCanvas();
return this.getSampleContext();
},
createImageData: function(w, h) {
this.initSampleCanvas();
return this.createImageData(w, h);
},
createImageDataFromData: function(data, w, h) {
return {
data: new Uint8ClampedArray(data),
width: w,
height: h,
}
},
clamp: function(value) {
return value > 255 ? 255 : value < 0 ? 0 : value;
},
buildMap: function(f) {
for (var m = [], k = 0, v; k < 256; k += 1) {
m[k] = (v = f(k)) > 255 ? 255 : v < 0 ? 0 : v | 0;
}
return m;
},
applyMap: function(src, dst, map) {
for (var i = 0, l = src.length; i < l; i += 4) {
dst[i] = map[src[i]];
dst[i + 1] = map[src[i + 1]];
dst[i + 2] = map[src[i + 2]];
dst[i + 3] = src[i + 3];
}
},
mapRGB: function(src, dst, func) {
this.applyMap(src, dst, this.buildMap(func));
},
getPixelIndex: function(x, y, width, height, edge) {
if (x < 0 || x >= width || y < 0 || y >= height) {
switch (edge) {
case 1: // clamp
x = x < 0 ? 0 : x >= width ? width - 1 : x;
y = y < 0 ? 0 : y >= height ? height - 1 : y;
break;
case 2: // wrap
x = (x %= width) < 0 ? x + width : x;
y = (y %= height) < 0 ? y + height : y;
break;
default: // transparent
return null;
}
}
return (y * width + x) << 2;
},
getPixel: function(src, x, y, width, height, edge) {
if (x < 0 || x >= width || y < 0 || y >= height) {
switch (edge) {
case 1: // clamp
x = x < 0 ? 0 : x >= width ? width - 1 : x;
y = y < 0 ? 0 : y >= height ? height - 1 : y;
break;
case 2: // wrap
x = (x %= width) < 0 ? x + width : x;
y = (y %= height) < 0 ? y + height : y;
break;
default: // transparent
return 0;
}
}
var i = (y * width + x) << 2;
// ARGB
return src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
},
getPixelByIndex: function(src, i) {
return src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
},
/**
* one of the most important functions in this library.
* I want to make this as fast as possible.
*/
copyBilinear: function(src, x, y, width, height, dst, dstIndex, edge) {
var fx = x < 0 ? x - 1 | 0 : x | 0, // Math.floor(x)
fy = y < 0 ? y - 1 | 0 : y | 0, // Math.floor(y)
wx = x - fx,
wy = y - fy,
i,
nw = 0,
ne = 0,
sw = 0,
se = 0,
cx, cy,
r, g, b, a;
if (fx >= 0 && fx < (width - 1) && fy >= 0 && fy < (height - 1)) {
// in bounds, no edge actions required
i = (fy * width + fx) << 2;
if (wx || wy) {
nw = src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
i += 4;
ne = src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
i = (i - 8) + (width << 2);
sw = src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
i += 4;
se = src[i + 3] << 24 | src[i] << 16 | src[i + 1] << 8 | src[i + 2];
} else {
// no interpolation required
dst[dstIndex] = src[i];
dst[dstIndex + 1] = src[i + 1];
dst[dstIndex + 2] = src[i + 2];
dst[dstIndex + 3] = src[i + 3];
return;
}
} else {
// edge actions required
nw = this.getPixel(src, fx, fy, width, height, edge);
if (wx || wy) {
ne = this.getPixel(src, fx + 1, fy, width, height, edge);
sw = this.getPixel(src, fx, fy + 1, width, height, edge);
se = this.getPixel(src, fx + 1, fy + 1, width, height, edge);
} else {
// no interpolation required
dst[dstIndex] = nw >> 16 & 0xFF;
dst[dstIndex + 1] = nw >> 8 & 0xFF;
dst[dstIndex + 2] = nw & 0xFF;
dst[dstIndex + 3] = nw >> 24 & 0xFF;
return;
}
}
cx = 1 - wx;
cy = 1 - wy;
r = ((nw >> 16 & 0xFF) * cx + (ne >> 16 & 0xFF) * wx) * cy + ((sw >> 16 & 0xFF) * cx + (se >> 16 & 0xFF) * wx) * wy;
g = ((nw >> 8 & 0xFF) * cx + (ne >> 8 & 0xFF) * wx) * cy + ((sw >> 8 & 0xFF) * cx + (se >> 8 & 0xFF) * wx) * wy;
b = ((nw & 0xFF) * cx + (ne & 0xFF) * wx) * cy + ((sw & 0xFF) * cx + (se & 0xFF) * wx) * wy;
a = ((nw >> 24 & 0xFF) * cx + (ne >> 24 & 0xFF) * wx) * cy + ((sw >> 24 & 0xFF) * cx + (se >> 24 & 0xFF) * wx) * wy;
dst[dstIndex] = r > 255 ? 255 : r < 0 ? 0 : r | 0;
dst[dstIndex + 1] = g > 255 ? 255 : g < 0 ? 0 : g | 0;
dst[dstIndex + 2] = b > 255 ? 255 : b < 0 ? 0 : b | 0;
dst[dstIndex + 3] = a > 255 ? 255 : a < 0 ? 0 : a | 0;
},
/**
* @param r 0 <= n <= 255
* @param g 0 <= n <= 255
* @param b 0 <= n <= 255
* @return Array(h, s, l)
*/
rgbToHsl: function(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
// var max = Math.max(r, g, b),
// min = Math.min(r, g, b),
var max = (r > g) ? (r > b) ? r : b : (g > b) ? g : b,
min = (r < g) ? (r < b) ? r : b : (g < b) ? g : b,
chroma = max - min,
h = 0,
s = 0,
// Lightness
l = (min + max) / 2;
if (chroma !== 0) {
// Hue
if (r === max) {
h = (g - b) / chroma + ((g < b) ? 6 : 0);
} else if (g === max) {
h = (b - r) / chroma + 2;
} else {
h = (r - g) / chroma + 4;
}
h /= 6;
// Saturation
s = (l > 0.5) ? chroma / (2 - max - min) : chroma / (max + min);
}
return [h, s, l];
},
/**
* @param h 0.0 <= n <= 1.0
* @param s 0.0 <= n <= 1.0
* @param l 0.0 <= n <= 1.0
* @return Array(r, g, b)
*/
hslToRgb: function(h, s, l) {
var m1, m2, hue,
r, g, b,
rgb = [];
if (s === 0) {
r = g = b = l * 255 + 0.5 | 0;
rgb = [r, g, b];
} else {
if (l <= 0.5) {