260 lines
7.9 KiB
JavaScript
260 lines
7.9 KiB
JavaScript
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('<canvas>').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);
|
|
|
|
}
|
|
|