Ox.load.Image = function(options, callback) { Ox.Image = function() { var self = {}, that = {}; if (arguments.length == 2) { self.src = arguments[0]; self.callback = arguments[1]; } else { self.width = arguments[0]; self.height = arguments[1]; self.callback = arguments[2]; } function getIndex(x, y) { return (Ox.mod(x, self.width) + Ox.mod(y * self.width, self.width * self.height)) * 4; } function getXY(index) { index /= 4; return [index % self.width, Math.floor(index / self.width)]; } self.filter = function(filter, bias) { bias = bias || 0; var filterSize = Math.sqrt(filter.length), d = (filterSize - 1) / 2, imageData = self.context.getImageData(0, 0, self.width, self.height), imageDataNew = self.context.createImageData(self.width, self.height), data = [], n = imageData.data.length, xy, filterIndex, pixelIndex; for (var i = 0; i < n; i += 4) { for (var c = 0; c < 3; c++) { data[i + c] = 0; } filterIndex = 0; xy = getXY(i); for (var x = -d; x <= d; x++) { for (var y = -d; y <= d; y++) { pixelIndex = getIndex(xy[0] + x, xy[1] + y); for (var c = 0; c < 3; c++) { data[i + c] += imageData.data[pixelIndex + c] * filter[filterIndex]; } filterIndex++; } } } for (var i = 0; i < n; i += 4) { for (var c = 0; c < 3; c++) { imageDataNew.data[i + c] = Ox.limit(Math.round(data[i + c] + bias), 0, 255) } imageDataNew.data[i + 3] = 255; } self.context.putImageData(imageDataNew, 0, 0); }; self.map = function(fn) { var imageData = self.context.getImageData(0, 0, self.width, self.height), i, n = imageData.data.length, c; for (i = 0; i < n; i += 4) { var data = fn([ imageData.data[i], imageData.data[i + 1], imageData.data[i + 2], imageData.data[i + 3] ], getXY(i)); for (c = 0; c < 4; c++) { imageData.data[i + c] = data[c]; }; } self.context.putImageData(imageData, 0, 0); }; self.setSL = function(sl, d) { var c = sl == 'saturation' ? 1 : 2; self.map(function(rgba) { var hsl = Ox.hsl([rgba[0], rgba[1], rgba[2]]), rgb; hsl[c] = d < 0 ? hsl[c] * (d + 1) : hsl[c] + (1 - hsl[c]) * d; rgb = Ox.rgb(hsl); return [rgb[0], rgb[1], rgb[2], rgba[3]]; }); } that.blur = function(val) { self.filter(val == 1 ? [ 0.0, 0.2, 0.0, 0.2, 0.2, 0.2, 0.0, 0.2, 0.0 ] : val == 2 ? [ 0.00, 1/21, 1/21, 1/21, 0.00, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 1/21, 0.00, 1/21, 1/21, 1/21, 0.00 ] : [ 0.00, 0.00, 1/37, 1/37, 1/37, 0.00, 0.00, 0.00, 1/37, 1/37, 1/37, 1/37, 1/37, 0.00, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 1/37, 0.00, 1/37, 1/37, 1/37, 1/37, 1/37, 0.00, 0.00, 0.00, 1/37, 1/37, 1/37, 0.00, 0.00 ]); return that; }; that.brightness = function(val) { self.setSL('brightness', val); return that; }; that.channel = function(channel) { self.map(function(rgba) { var hue = Ox.hsl([rgba[0], rgba[1], rgba[2]])[0], rgb = Ox.rgb([hue, 1, 0.5]); return [rgb[0], rgb[1], rgb[2], rgba[3]]; }); return that; } that.contour = function(val) { self.filter([ +1, +1, +1, +1, -7, +1, +1, +1, +1 ]); return that; }; that.edges = function(val) { self.filter([ -1, -1, -1, -1, +8, -1, -1, -1, -1 ]); that.saturation(-1); return that; }; that.emboss = function(val) { self.filter([ -1, -1, +0, -1, +0, +1, +0, +1, +1 ], 128); that.saturation(-1); return that; }; that.hue = function(val) { self.map(function(rgba) { var hsl = Ox.hsl([rgba[0], rgba[1], rgba[2]]), rgb; hsl[0] = (hsl[0] + val) % 360; rgb = Ox.rgb(hsl); return [rgb[0], rgb[1], rgb[2], rgba[3]]; }); return that; }; that.invert = function() { self.map(function(rgba) { return [255 - rgba[0], 255 - rgba[1], 255 - rgba[2], rgba[3]]; }); return that; }; that.motionBlur = function() { self.filter([ 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.2 ]); return that; }; that.posterize = function() { that.blur(3); self.map(function(rgba) { return [ Math.floor(rgba[0] / 64) * 64, Math.floor(rgba[1] / 64) * 64, Math.floor(rgba[2] / 64) * 64, rgba[3] ]; }); return that; }; that.saturation = function(val) { self.setSL('saturation', val); return that; }; that.sharpen = function(val) { self.filter([ -1, -1, -1, -1, +9, -1, -1, -1, -1 ]); return that; }; that.solarize = function() { self.map(function(rgba) { return [ rgba[0] < 128 ? rgba[0] : 255 - rgba[0], rgba[1] < 128 ? rgba[1] : 255 - rgba[1], rgba[2] < 128 ? rgba[2] : 255 - rgba[2], rgba[3] ]; }); return that; } that.resize = function(width, height) { self.canvas.attr({ width: width, height: height }); return that; } that.url = function() { return self.canvas[0].toDataURL(); return that; }; if (self.src) { self.image = new Image(); self.image.onload = init; self.image.src = self.src; } else { init(); } function init() { if (self.image) { self.width = self.image.width; self.height = self.image.height; } self.canvas = Ox.element('').attr({ width: self.width, height: self.height }); self.context = self.canvas[0].getContext('2d'); if (self.image) { self.context.drawImage(self.image, 0, 0); } self.callback(that); } }; callback(true); }