forked from 0x2620/oxjs
simpler text list column head elements, better column drag
This commit is contained in:
parent
7bf42e5b0b
commit
0ba258281f
12 changed files with 461 additions and 330 deletions
|
|
@ -4,6 +4,8 @@ Ox.load.Image = function(options, callback) {
|
|||
|
||||
/*@
|
||||
Ox.Image <f> Generic image object
|
||||
To render the image as an image element, use its <code>src()</code>
|
||||
method, to render it as a canvas, use its <code>canvas</code> property.
|
||||
(src, callback) -> <u> undefined
|
||||
(width, height, callback) -> <u> undefined
|
||||
(width, height, background, callback) -> <u> undefined
|
||||
|
|
@ -26,7 +28,8 @@ Ox.load.Image = function(options, callback) {
|
|||
} else {
|
||||
self.width = arguments[0];
|
||||
self.height = arguments[1];
|
||||
self.background = arguments.length == 4 ? arguments[2] : [0, 0, 0, 0];
|
||||
self.background = arguments.length == 4
|
||||
? arguments[2] : [0, 0, 0, 0];
|
||||
init();
|
||||
}
|
||||
|
||||
|
|
@ -66,19 +69,21 @@ Ox.load.Image = function(options, callback) {
|
|||
self.width = self.image.width;
|
||||
self.height = self.image.height;
|
||||
}
|
||||
self.canvas = Ox.element('<canvas>').attr({
|
||||
that.canvas = Ox.element('<canvas>').attr({
|
||||
width: self.width,
|
||||
height: self.height
|
||||
});
|
||||
self.context = self.canvas[0].getContext('2d');
|
||||
that.context = that.canvas[0].getContext('2d');
|
||||
if (self.image) {
|
||||
self.context.drawImage(self.image, 0, 0);
|
||||
that.context.drawImage(self.image, 0, 0);
|
||||
} else if (Ox.sum(self.background)) {
|
||||
that.fillStyle(self.background);
|
||||
that.fillRect(0, 0, self.width, self.height);
|
||||
that.context.fillStyle(self.background);
|
||||
that.context.fillRect(0, 0, self.width, self.height);
|
||||
}
|
||||
self.imageData = self.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = self.imageData.data;
|
||||
that.imageData = that.context.getImageData(
|
||||
0, 0, self.width, self.height
|
||||
);
|
||||
self.data = that.imageData.data;
|
||||
self.callback(that);
|
||||
}
|
||||
|
||||
|
|
@ -92,6 +97,11 @@ Ox.load.Image = function(options, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
/*@
|
||||
blur <f> Apply blur filter
|
||||
(val) -> <o> The image object
|
||||
val <n> Amount of blur (1 to 5, more is slow)
|
||||
@*/
|
||||
that.blur = function(val) {
|
||||
var filter = [],
|
||||
size = val * 2 + 1;
|
||||
|
|
@ -111,6 +121,13 @@ Ox.load.Image = function(options, callback) {
|
|||
return that.filter(filter);
|
||||
};
|
||||
|
||||
//@ canvas <o> Canvas object
|
||||
|
||||
/*@
|
||||
channel <f> Reduce the image to one channel
|
||||
(channel) -> <o> The image object
|
||||
channel <str> 'r', 'g', 'b', 'a', 'h', 's' or 'l'
|
||||
@*/
|
||||
that.channel = function(str) {
|
||||
str = str[0].toLowerCase();
|
||||
return that.map(function(rgba) {
|
||||
|
|
@ -134,6 +151,12 @@ Ox.load.Image = function(options, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
//@ context <o> 2D drawing context
|
||||
|
||||
/*@
|
||||
contour <f> Apply contour filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.contour = function(val) {
|
||||
return that.filter([
|
||||
+1, +1, +1,
|
||||
|
|
@ -142,15 +165,24 @@ Ox.load.Image = function(options, callback) {
|
|||
]);
|
||||
};
|
||||
|
||||
/*@
|
||||
depth <f> Reduce the bit depth
|
||||
(depth) -> <o> The image object
|
||||
depth <n> Bits per channel (1 to 7)
|
||||
@*/
|
||||
that.depth = function(val) {
|
||||
var pow = Math.pow(2, 8 - val);
|
||||
return that.map(function(rgba) {
|
||||
return rgba.map(function(v, i) {
|
||||
return i < 3 ? Math.floor(v / pow) * pow : v
|
||||
return i < 3 ? Math.floor(v / pow) * pow/* * 255 / val*/ : v;
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/*@
|
||||
edges <f> Apply edges filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.edges = function(val) {
|
||||
return that.filter([
|
||||
-1, -1, -1,
|
||||
|
|
@ -159,6 +191,10 @@ Ox.load.Image = function(options, callback) {
|
|||
]).saturation(-1);
|
||||
};
|
||||
|
||||
/*@
|
||||
emboss <f> Apply emboss filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.emboss = function(val) {
|
||||
return that.filter([
|
||||
-1, -1, +0,
|
||||
|
|
@ -171,8 +207,8 @@ Ox.load.Image = function(options, callback) {
|
|||
encode <f> Encodes a string into the image
|
||||
For most purposes, deflate and mode should be omitted, since the
|
||||
defaults make the existence of the message harder to detect. A valid
|
||||
use case for deflate and mode would be to encode, additionally to
|
||||
the secret string, a more easily detected decoy string: <code>
|
||||
use case for deflate and mode would be to first encode a more easily
|
||||
detected decoy string, and only then the secret string: <code>
|
||||
image.encode(decoy, false, 1, function(image) { image.encode(secret,
|
||||
-1, callback); })</code>.
|
||||
(str, callback) -> <o> The image object (unmodified)
|
||||
|
|
@ -183,7 +219,7 @@ Ox.load.Image = function(options, callback) {
|
|||
str <s> The string to be encoded
|
||||
callback <f> Callback function
|
||||
image <o> The image object (modified)
|
||||
deflate <b|true> If true, compress string with deflate
|
||||
deflate <b|true> If true, encode the string with deflate
|
||||
mode <n|0> Encoding mode
|
||||
If mode is between -7 and 0, the string will be encoded one bit
|
||||
per byte, as the number of bits within that byte set to 1,
|
||||
|
|
@ -199,6 +235,7 @@ Ox.load.Image = function(options, callback) {
|
|||
mode = Ox.isNumber(arguments[1]) ? arguments[1]
|
||||
: Ox.isNumber(arguments[2]) ? arguments[2] : 0,
|
||||
b = 0, bin,
|
||||
// Array of bits per byte to be modified (0 is LSB)
|
||||
bits = mode < 1 ? [-mode] : Ox.map(Ox.range(8), function(bit) {
|
||||
return mode & 1 << bit ? bit : null;
|
||||
}),
|
||||
|
|
@ -226,6 +263,7 @@ Ox.load.Image = function(options, callback) {
|
|||
if (rgba[3] == 255) {
|
||||
var index = getIndex(xy);
|
||||
Ox.loop(3, function(c) {
|
||||
// fixme: use: var data = that.context.imageData.data[i + c]
|
||||
var i = index + c;
|
||||
Ox.forEach(bits, function(bit) {
|
||||
if ((
|
||||
|
|
@ -245,11 +283,23 @@ Ox.load.Image = function(options, callback) {
|
|||
});
|
||||
}
|
||||
});
|
||||
self.context.putImageData(self.imageData, 0, 0);
|
||||
that.context.putImageData(that.imageData, 0, 0);
|
||||
callback(that);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
decode <f> Decode encoded string
|
||||
(callback) -> <o> The image object (unmodified)
|
||||
(deflate, callback) -> <o> The image object (unmodified)
|
||||
(mode, callback) -> <o> The image object (unmodified)
|
||||
(deflate, mode, callback) -> <o> The image object (unmodified)
|
||||
(mode, deflate, callback) -> <o> The image object (unmodified)
|
||||
deflate <b|true> If true, decode the string with deflate
|
||||
mode <n|0> See encode method
|
||||
callback <f> Callback function
|
||||
image <o> The image object (modified)
|
||||
@*/
|
||||
that.decode = function() {
|
||||
var callback = arguments[arguments.length - 1],
|
||||
deflate = Ox.isBoolean(arguments[0]) ? arguments[0]
|
||||
|
|
@ -257,6 +307,7 @@ Ox.load.Image = function(options, callback) {
|
|||
mode = Ox.isNumber(arguments[0]) ? arguments[0]
|
||||
: Ox.isNumber(arguments[1]) ? arguments[1] : 0,
|
||||
bin = '',
|
||||
// Array of bits per byte to be modified (0 is LSB)
|
||||
bits = mode < 1 ? [-mode] : Ox.map(Ox.range(8), function(b) {
|
||||
return mode & 1 << b ? b : null;
|
||||
}),
|
||||
|
|
@ -268,35 +319,41 @@ Ox.load.Image = function(options, callback) {
|
|||
var i = index + c;
|
||||
Ox.forEach(bits, function(bit) {
|
||||
bin += mode < 1
|
||||
// Read the number of bits set to 1, mod 2
|
||||
? Ox.sum(Ox.range(8).map(function(bit) {
|
||||
return +!!(self.data[i] & 1 << bit);
|
||||
})) % 2
|
||||
// or the one bit in question
|
||||
: +!!(self.data[i] & 1 << bit);
|
||||
if (bin.length == 8) {
|
||||
// Every 8 bits, add one byte to the string
|
||||
str += Ox.char(parseInt(bin, 2));
|
||||
bin = '';
|
||||
if (str.length == len) {
|
||||
if (++done == 1) {
|
||||
// After 4 bytes, parse string as length
|
||||
len = Ox.decodeBase256(str);
|
||||
Ox.print("LEN", len)
|
||||
len + 4 > getCapacity(bits.length)
|
||||
&& error('decode');
|
||||
if (
|
||||
len <= 0 ||
|
||||
len > getCapacity(bits.length) - 4
|
||||
) {
|
||||
error('decode');
|
||||
}
|
||||
str = '';
|
||||
} else {
|
||||
// After length more bytes, break
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return done != 2;
|
||||
});
|
||||
if (done == 2) {
|
||||
return false;
|
||||
}
|
||||
return done != 2;
|
||||
}
|
||||
});
|
||||
try {
|
||||
if (deflate) {
|
||||
Ox.print('DEFLATE')
|
||||
Ox.decodeDeflate(str, callback);
|
||||
} else {
|
||||
callback(Ox.decodeUTF8(str));
|
||||
|
|
@ -306,28 +363,22 @@ Ox.load.Image = function(options, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
that.fillRect = function(x, y, w, h) {
|
||||
self.context.fillRect(x, y, w, h);
|
||||
return that;
|
||||
};
|
||||
|
||||
that.fillStyle = function() {
|
||||
if (arguments.length == 0) {
|
||||
return self.context.fillStyle;
|
||||
} else {
|
||||
self.context.fillStyle = arguments[0];
|
||||
return that;
|
||||
}
|
||||
};
|
||||
|
||||
/*@
|
||||
filter <f> Pixel-wise filter function
|
||||
Undocumented, see source code
|
||||
(filter) -> <o> The image object
|
||||
(filter, bias) -> <o> The image object
|
||||
filter <[n]> Filter matrix
|
||||
bias <n> Bias
|
||||
@*/
|
||||
that.filter = function(filter, bias) {
|
||||
bias = bias || 0;
|
||||
var filterSize = Math.sqrt(filter.length),
|
||||
d = (filterSize - 1) / 2,
|
||||
imageData = self.context.createImageData(self.width, self.height),
|
||||
imageData = that.context.createImageData(self.width, self.height),
|
||||
data = [];
|
||||
self.imageData = self.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = self.imageData.data;
|
||||
that.imageData = that.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = that.imageData.data;
|
||||
Ox.loop(0, self.data.length, 4, function(i) {
|
||||
var filterIndex = 0,
|
||||
xy = getXY(i);
|
||||
|
|
@ -351,8 +402,8 @@ Ox.load.Image = function(options, callback) {
|
|||
: self.data[i + c];
|
||||
});
|
||||
});
|
||||
self.context.putImageData(imageData, 0, 0);
|
||||
self.imageData = imageData;
|
||||
that.context.putImageData(imageData, 0, 0);
|
||||
that.imageData = imageData;
|
||||
self.data = data;
|
||||
return that;
|
||||
};
|
||||
|
|
@ -383,12 +434,23 @@ Ox.load.Image = function(options, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
//@ imageData <o> Image data object
|
||||
|
||||
/*@
|
||||
invert <f> Apply invert filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.invert = function() {
|
||||
return that.map(function(rgba) {
|
||||
return [255 - rgba[0], 255 - rgba[1], 255 - rgba[2], rgba[3]];
|
||||
});
|
||||
};
|
||||
|
||||
/*@
|
||||
lightness <f> Apply lightness filter
|
||||
(val) -> <o> The image object
|
||||
val <n> Amount, from -1 (darkest) to 1 (lightest)
|
||||
@*/
|
||||
that.lightness = function(val) {
|
||||
return setSL('l', val);
|
||||
};
|
||||
|
|
@ -401,8 +463,8 @@ Ox.load.Image = function(options, callback) {
|
|||
xy <[n]> XY coordinates
|
||||
@*/
|
||||
that.map = function(fn) {
|
||||
self.imageData = self.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = self.imageData.data;
|
||||
that.imageData = that.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = that.imageData.data;
|
||||
Ox.loop(0, self.data.length, 4, function(i) {
|
||||
fn([
|
||||
self.data[i], self.data[i + 1],
|
||||
|
|
@ -411,10 +473,44 @@ Ox.load.Image = function(options, callback) {
|
|||
self.data[i + c] = val;
|
||||
});
|
||||
})
|
||||
self.context.putImageData(self.imageData, 0, 0);
|
||||
that.context.putImageData(that.imageData, 0, 0);
|
||||
return that;
|
||||
};
|
||||
|
||||
/*@
|
||||
mosaic <f> Apply mosaic filter
|
||||
(size) -> <o> The image object
|
||||
size <n> Mosaic size
|
||||
@*/
|
||||
that.mosaic = function(size) {
|
||||
that.forEach(function(rgba, xy) {
|
||||
if (xy[0] % size == 0 && xy[1] % size == 0) {
|
||||
Ox.loop(size, function(x) {
|
||||
Ox.loop(size, function(y) {
|
||||
var hsl, rgb;
|
||||
if ((x == 0 || y == 0) && !(x == size - 1 || y == size - 1)) {
|
||||
that.pixel(xy[0] + x, xy[1] + y, rgba.map(function(c, i) {
|
||||
return i < 3 ? Math.min(c + 16, 255) : c;
|
||||
}));
|
||||
} else if ((x == size - 1 || y == size - 1) && !(x == 0 || y == 0)) {
|
||||
that.pixel(xy[0] + x, xy[1] + y, rgba.map(function(c, i) {
|
||||
return i < 3 ? Math.max(c - 16, 0) : c;
|
||||
}));
|
||||
} else {
|
||||
that.pixel(xy[0] + x, xy[1] + y, rgba);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
that.context.putImageData(that.imageData, 0, 0);
|
||||
return that;
|
||||
}
|
||||
|
||||
/*@
|
||||
motionBlur <f> Apply motion blur filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.motionBlur = function() {
|
||||
return that.filter([
|
||||
0.2, 0.0, 0.0, 0.0, 0.0,
|
||||
|
|
@ -425,6 +521,22 @@ Ox.load.Image = function(options, callback) {
|
|||
]);
|
||||
};
|
||||
|
||||
/*@
|
||||
photocopy <f> Apply photocopy filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.photocopy = function(val) {
|
||||
return that.saturation(-1).depth(1).blur(1);
|
||||
};
|
||||
|
||||
/*@
|
||||
pixel <f> Get or set pixel values
|
||||
(x, y) -> <[n]> RGBA values
|
||||
(x, y, val) -> <o> The image object
|
||||
x <n> X coordinate
|
||||
y <n> Y coordinate
|
||||
val <[n]> RGBA values
|
||||
@*/
|
||||
that.pixel = function(x, y, val) {
|
||||
var i = getIndex(x, y);
|
||||
if (!val) {
|
||||
|
|
@ -438,6 +550,10 @@ Ox.load.Image = function(options, callback) {
|
|||
}
|
||||
}
|
||||
|
||||
/*@
|
||||
posterize <f> Apply posterize filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.posterize = function() {
|
||||
return that.blur(3).map(function(rgba) {
|
||||
return [
|
||||
|
|
@ -450,17 +566,27 @@ Ox.load.Image = function(options, callback) {
|
|||
};
|
||||
|
||||
that.resize = function(width, height) {
|
||||
self.canvas.attr({
|
||||
// fixme: may not work this way
|
||||
that.canvas.attr({
|
||||
width: width,
|
||||
height: height
|
||||
});
|
||||
return that;
|
||||
}
|
||||
|
||||
/*@
|
||||
saturation <f> Apply saturation filter
|
||||
(val) -> <o> The image object
|
||||
val <n> Amount, from -1 (lowest) to 1 (highest)
|
||||
@*/
|
||||
that.saturation = function(val) {
|
||||
return setSL('s', val);
|
||||
};
|
||||
|
||||
/*@
|
||||
sharpen <f> Apply sharpen filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.sharpen = function(val) {
|
||||
return that.filter([
|
||||
-1, -1, -1,
|
||||
|
|
@ -469,6 +595,10 @@ Ox.load.Image = function(options, callback) {
|
|||
]);
|
||||
};
|
||||
|
||||
/*@
|
||||
solarize <f> Apply solarize filter
|
||||
() -> <o> The image object
|
||||
@*/
|
||||
that.solarize = function() {
|
||||
return that.map(function(rgba) {
|
||||
return [
|
||||
|
|
@ -480,9 +610,15 @@ Ox.load.Image = function(options, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
/*@
|
||||
src <f> Get or set the image source
|
||||
() -> <s> Data URL
|
||||
(src) -> <o> Image object, with new source
|
||||
src <s> Image source (local, remote or data URL)
|
||||
@*/
|
||||
that.src = function() {
|
||||
if (arguments.length == 0) {
|
||||
return self.canvas[0].toDataURL();
|
||||
return that.canvas[0].toDataURL();
|
||||
} else {
|
||||
var callback = arguments[1];
|
||||
self.src = arguments[0];
|
||||
|
|
@ -490,13 +626,13 @@ Ox.load.Image = function(options, callback) {
|
|||
self.image.onload = function() {
|
||||
self.width = self.image.width;
|
||||
self.height = self.image.height;
|
||||
self.canvas.attr({
|
||||
that.canvas.attr({
|
||||
width: self.width,
|
||||
height: self.height
|
||||
});
|
||||
self.context.drawImage(self.image, 0, 0);
|
||||
self.imageData = self.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = self.imageData.data;
|
||||
that.context.drawImage(self.image, 0, 0);
|
||||
that.imageData = that.context.getImageData(0, 0, self.width, self.height);
|
||||
self.data = that.imageData.data;
|
||||
callback && callback(that);
|
||||
}
|
||||
self.image.src = self.src;
|
||||
|
|
@ -504,8 +640,6 @@ Ox.load.Image = function(options, callback) {
|
|||
}
|
||||
};
|
||||
|
||||
that.toDataURL = that.src;
|
||||
|
||||
};
|
||||
|
||||
callback(true);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue