add drawing methods to Ox.Image, allow for asynchronous image manipulation

This commit is contained in:
rolux 2012-04-13 23:21:36 +02:00
parent b4dc9e15ba
commit 37f3bf8f51

View file

@ -180,6 +180,16 @@ Ox.load.Image = function(options, callback) {
}); });
}; };
/*@
drawCircle <f> Draws a circle
(point, radius, options) -> <o> The image object
point <[n]> Center (<code>[x, y]</code>)
radius <n> Radius in px
options <o> Options
color <s|'rgb(0, 0, 0)'> CSS color
fill <s|'rgba(0, 0, 0, 0)'> CSS color
width <n|1> Line width in px
@*/
that.drawCircle = function(point, radius, options) { that.drawCircle = function(point, radius, options) {
options = options || {}; options = options || {};
that.context.strokeStyle = options.color || 'rgb(0, 0, 0)'; that.context.strokeStyle = options.color || 'rgb(0, 0, 0)';
@ -192,6 +202,14 @@ Ox.load.Image = function(options, callback) {
return that; return that;
}; };
/*@
drawLine <f> Draws a line
(points, options) -> <o> The image object
points <[a]> End points (<code>[[x1, y1], [x2, y2]]</code>)
options <o> Options
color <s|'rgb(0, 0, 0)'> CSS color
width <n|1> Line width in px
@*/
that.drawLine = function(points, options, isPath) { that.drawLine = function(points, options, isPath) {
options = options || {}; options = options || {};
that.context.strokeStyle = options.color || 'rgb(0, 0, 0)'; that.context.strokeStyle = options.color || 'rgb(0, 0, 0)';
@ -203,6 +221,15 @@ Ox.load.Image = function(options, callback) {
return that; return that;
}; };
/*@
drawPath <f> Draws a path
(points, options) -> <o> The image object
points <[a]> Points (<code>[[x1, y2], [x2, y2], ...]</code>)
options <o> Options
color <s|'rgb(0, 0, 0)'> CSS color
fill <s|'rgba(0, 0, 0, 0)'> CSS color
width <n|1> Line width in px
@*/
that.drawPath = function(points, options) { that.drawPath = function(points, options) {
var n = points.length; var n = points.length;
options = options || {}; options = options || {};
@ -217,6 +244,16 @@ Ox.load.Image = function(options, callback) {
return that; return that;
}; };
/*@
drawRectangle <f> Draws a rectangle
(point, size, options) -> <o> The image object
point <[n]> Top left corner (<code>[x, y]</code>)
size <[n]> Width and height in px (<code>[w, h]</code>)
options <o> Options
color <s|'rgb(0, 0, 0)'> CSS color
fill <s|'rgba(0, 0, 0, 0)'> CSS color
width <n|1> Line width in px
@*/
that.drawRectangle = function(point, size, options) { that.drawRectangle = function(point, size, options) {
options = options || {}; options = options || {};
that.context.strokeStyle = options.color || 'rgb(0, 0, 0)'; that.context.strokeStyle = options.color || 'rgb(0, 0, 0)';
@ -227,6 +264,17 @@ Ox.load.Image = function(options, callback) {
return that; return that;
}; };
/*@
drawText <f> Draws text
(text, point, options) -> <o> The image object
text <s> Text
point <[n]> Top left corner (<code>[x, y]</code>)
options <o> Options
color <s|'rgb(0, 0, 0)'> CSS color
font <s|'10px sans-serif'> CSS font
outline <s|'0px rgba(0, 0, 0, 0)'> CSS border
textAlign <n|'start'> CSS text-align
@*/
that.drawText = function(text, point, options) { that.drawText = function(text, point, options) {
options = options || {}; options = options || {};
var match = ( var match = (
@ -322,10 +370,9 @@ Ox.load.Image = function(options, callback) {
}); });
})); }));
b = 0; b = 0;
that.forEach(function(rgba, xy) { that.forEach(function(rgba, xy, index) {
// If alpha is not 255, the RGB values may not be preserved // If alpha is not 255, the RGB values may not be preserved
if (rgba[3] == 255) { if (rgba[3] == 255) {
var index = getIndex(xy);
Ox.loop(3, function(c) { Ox.loop(3, function(c) {
// fixme: use: var data = that.context.imageData.data[i + c] // fixme: use: var data = that.context.imageData.data[i + c]
var i = index + c; var i = index + c;
@ -346,9 +393,10 @@ Ox.load.Image = function(options, callback) {
}); });
}); });
} }
}, function() {
that.context.putImageData(self.imageData, 0, 0);
callback(that);
}); });
that.context.putImageData(self.imageData, 0, 0);
callback(that);
return that; return that;
}; };
@ -376,9 +424,8 @@ Ox.load.Image = function(options, callback) {
return mode & 1 << b ? b : null; return mode & 1 << b ? b : null;
}), }),
done = 0, len = 4, str = ''; done = 0, len = 4, str = '';
that.forEach(function(rgba, xy) { that.forEach(function(rgba, xy, index) {
if (rgba[3] == 255) { if (rgba[3] == 255) {
var index = getIndex(xy);
Ox.loop(3, function(c) { Ox.loop(3, function(c) {
var i = index + c; var i = index + c;
Ox.forEach(bits, function(bit) { Ox.forEach(bits, function(bit) {
@ -415,16 +462,18 @@ Ox.load.Image = function(options, callback) {
}); });
return done != 2; return done != 2;
} }
}); }, function() {
try { try {
if (deflate) { if (deflate) {
Ox.decodeDeflate(str, callback); Ox.decodeDeflate(str, callback);
} else { } else {
callback(Ox.decodeUTF8(str)); callback(Ox.decodeUTF8(str));
}
} catch (e) {
error('decode');
} }
} catch (e) { });
error('decode'); return that;
}
} }
/*@ /*@
@ -473,26 +522,40 @@ Ox.load.Image = function(options, callback) {
}; };
/*@ /*@
forEach <f> Pixel-wise forEach function forEach <f> Pixel-wise forEach loop
(fn) -> <o> The image object (fn) -> <o> The image object
(fn, callback) -> <o> The image object
fn <f> Iterator function fn <f> Iterator function
rgba <[n]> RGBA values rgba <[n]> RGBA values
xy <[n]> XY coordinates xy <[n]> XY coordinates
i <n> Pixel index
callback <f> Callback function (if present, forEach is async)
@*/ @*/
that.forEach = function(fn) { that.forEach = function(fn, callback) {
Ox.loop(0, self.data.length, 4, function(i) { var data = self.data;
Ox._loop(0, data.length, 4, function(i) {
return fn([ return fn([
self.data[i], self.data[i + 1], data[i], data[i + 1], data[i + 2], data[i + 3]
self.data[i + 2], self.data[i + 3] ], getXY(i), i);
], getXY(i)); }, 10000, callback);
}) return that;
return that;
}; };
/*@
getSize <f> Returns width and height
() -> <o> Image size
width <n> Width in px
height <n> Height in px
@*/
that.getSize = function() { that.getSize = function() {
return {width: self.width, height: self.height}; return {width: self.width, height: self.height};
}; };
/*@
hue <f> Change the hue of the image
(val) -> <o> The image object
val <n> Hue, in degrees
@*/
that.hue = function(val) { that.hue = function(val) {
return that.map(function(rgba) { return that.map(function(rgba) {
var hsl = Ox.hsl([rgba[0], rgba[1], rgba[2]]), rgb; var hsl = Ox.hsl([rgba[0], rgba[1], rgba[2]]), rgb;
@ -511,7 +574,6 @@ Ox.load.Image = function(options, callback) {
(imageData) -> <o> Image object with new image data (imageData) -> <o> Image object with new image data
imageData <o> ImageData object imageData <o> ImageData object
@*/ @*/
that.imageData = function() { that.imageData = function() {
if (arguments.length == 0) { if (arguments.length == 0) {
return self.imageData; return self.imageData;
@ -545,18 +607,16 @@ Ox.load.Image = function(options, callback) {
fn <f> Iterator function fn <f> Iterator function
rgba <[n]> RGBA values rgba <[n]> RGBA values
xy <[n]> XY coordinates xy <[n]> XY coordinates
i <n> Pixel index
@*/ @*/
that.map = function(fn) { that.map = function(fn, callback) {
self.imageData = that.context.getImageData(0, 0, self.width, self.height); self.imageData = that.context.getImageData(0, 0, self.width, self.height);
self.data = self.imageData.data; self.data = self.imageData.data;
Ox.loop(0, self.data.length, 4, function(i) { that.forEach(function(rgba, xy, i) {
fn([ fn(rgba, xy, i).forEach(function(val, c) {
self.data[i], self.data[i + 1],
self.data[i + 2], self.data[i + 3]
], getXY(i)).forEach(function(val, c) {
self.data[i + c] = val; self.data[i + c] = val;
}); });
}) });
that.context.putImageData(self.imageData, 0, 0); that.context.putImageData(self.imageData, 0, 0);
return that; return that;
}; };
@ -650,7 +710,7 @@ Ox.load.Image = function(options, callback) {
}; };
that.resize = function(width, height) { that.resize = function(width, height) {
// fixme: may not work this way // fixme: doesn't work this way
that.canvas.attr({ that.canvas.attr({
width: width, width: width,
height: height height: height