Merge branch 'develop'

This commit is contained in:
Georg Fischer 2013-06-27 19:54:40 +02:00
commit 8e8db95498
8 changed files with 128 additions and 592 deletions

View File

@ -1,24 +1,21 @@
image triangulation experiment image glitch experiment
=== ===
this is an experiment for the web browser. it uses the [delaunay triangulation](https://en.wikipedia.org/wiki/Delaunay_triangulation) algorithm to alter an image. this is an experiment for the web browser. it corrupts jpg images so that they appear "glitched".
[![triangulation experiment screen shot](http://dl.dropboxusercontent.com/u/1098704/Screenshots/github-triangulation.png)](http://snorpey.github.io/triangulation/) [![triangulation experiment screen shot](http://dl.dropboxusercontent.com/u/1098704/Screenshots/github-glitch.png)](http://snorpey.github.io/jpg-glitch/)
[online demo](http://snorpey.github.io/triangulation/) [online demo](http://snorpey.github.io/jpg-glitch/)
this experiment is very much based on the [triangulation image generator](http://jsdo.it/akm2/xoYx) script. it includes several speed enhancements. it is my goal to make it fast enough for use with real time streaming input, e.g. from a [web cam](https://github.com/snorpey/photobooth). this experiment is very much based on the [smack my glitch up js](https://github.com/Hugosslade/smackmyglitchupjs) script.
you can fine another experiment that applies the the triangulation to text input here: [http://snorpey.github.io/text-triangulation/](http://snorpey.github.io/text-triangulation/)
third party code used in this experiment third party code used in this experiment
--- ---
* some parts of the code code from [triangulation image generator](http://jsdo.it/akm2/xoYx) by [akm2](http://codepen.io/akm2), MIT license * some parts of the code code from [triangulation image generator](http://jsdo.it/akm2/xoYx) by [akm2](http://codepen.io/akm2), MIT license
* [delaunay js](https://github.com/ironwallaby/delaunay) by [ironwallaby](https://github.com/ironwallaby), public domain
* [html5slider](http://frankyan.com/labs/html5slider/) by [fryn](https://github.com/fryn), MIT license * [html5slider](http://frankyan.com/labs/html5slider/) by [fryn](https://github.com/fryn), MIT license
* [js signals](http://millermedeiros.github.io/js-signals/) by [millermedeiros](https://github.com/millermedeiros), MIT license * [js signals](http://millermedeiros.github.io/js-signals/) by [millermedeiros](https://github.com/millermedeiros), MIT license
* [superfast boxblur for canvas](http://quasimondo.com/BoxBlurForCanvas/FastBlurDemo.html) by [quasimondo](https://github.com/quasimondo), MIT license
* [require js](http://requirejs.org/), by [jrburke](jrburke), BSD & MIT license * [require js](http://requirejs.org/), by [jrburke](jrburke), BSD & MIT license
* [raf js](https://gist.github.com/paulirish/1579671), by [paulirish](https://github.com/paulirish), MIT license
license license
--- ---

View File

@ -8,24 +8,24 @@
<body> <body>
<article class="content"> <article class="content">
<h1 class="headline">glitch images</h1> <h1 class="headline">glitch images</h1>
<p>drop an image in the browser.</p> <p>drop an image in the browser to modify it. this script corrupts some bytes in a jpg image. because of the way <a href="https://en.wikipedia.org/wiki/JPEG">jpg</a> encoding works, the corripted file still shows something. inspired by <a href="http://github.com/soulwire">soulwire</a>s <a href="http://blog.soulwire.co.uk/laboratory/flash/as3-bitmapdata-glitch-generator">experiment</a> in flash. this experiment was created by <a href="http://fishnation.de/">georg</a>. you can follow him on <a href="https://twitter.com/snorpey">twitter</a> or explore the source code on <a href="https://github.com/snorpey/jpg-glitch">github</a>.</p>
</article> </article>
<div class="content" id="controls"> <div class="content" id="controls">
<div class="control-wrapper">
<label class="control-label" for="amount">glitch amount</label>
<input class="control-input" type="range" id="amount" min="0" max="100" value="50" />
</div>
<div class="control-wrapper"> <div class="control-wrapper">
<label class="control-label" for="seed">seed</label> <label class="control-label" for="seed">seed</label>
<input class="control-input" type="range" id="seed" min="0" max="100" value="50" /> <input class="control-input" type="range" id="seed" min="0" max="100" value="50" />
</div> </div>
<div class="control-wrapper">
<label class="control-label" for="quality">quality</label>
<input class="control-input" type="range" id="quality" min="0" max="100" value="50" />
</div>
<div class="control-wrapper">
<label class="control-label" for="offset">px offset</label>
<input class="control-input" type="range" id="offset" min="0" max="100" value="50" />
</div>
<div class="control-wrapper"> <div class="control-wrapper">
<label class="control-label" for="iterations">iterations</label> <label class="control-label" for="iterations">iterations</label>
<input class="control-input" type="range" id="iterations" min="1" max="20" value="5" /> <input class="control-input" type="range" id="iterations" min="1" max="50" value="5" />
</div>
<div class="control-wrapper">
<label class="control-label" for="quality">jpg quality</label>
<input class="control-input" type="range" id="quality" min="1" max="90" value="50" />
</div> </div>
</div> </div>
<div class="export-wrapper"> <div class="export-wrapper">

38
scripts/aux/canvas.js Normal file
View File

@ -0,0 +1,38 @@
/*global define*/
define(
function()
{
var update = false;
function resize( canvas, size )
{
if ( canvas.width !== size.width )
{
canvas.width = size.width;
update = true;
}
if ( canvas.height !== size.height )
{
canvas.height = size.height;
update = true;
}
if ( update )
{
canvas.width = size.width;
canvas.height = size.height;
}
update = false;
}
function clear( canvas, ctx )
{
ctx.clearRect( ctx, 0, 0, canvas.width, canvas.height );
}
return { resize: resize, clear: clear };
}
);

View File

@ -1,6 +1,7 @@
/*global define*/ /*global define*/
define( define(
function() [ 'aux/canvas' ],
function( canvas_helper )
{ {
var canvas = document.createElement( 'canvas' ); var canvas = document.createElement( 'canvas' );
var ctx = canvas.getContext( '2d' ); var ctx = canvas.getContext( '2d' );
@ -17,7 +18,7 @@ define(
var iterations; var iterations;
var quality; var quality;
var seed; var seed;
var offset; var amount;
var base64; var base64;
var byte_array; var byte_array;
var jpg_header_length; var jpg_header_length;
@ -33,10 +34,11 @@ define(
{ {
seed = input.seed / 100; seed = input.seed / 100;
quality = input.quality / 100; quality = input.quality / 100;
offset = input.offset / 100; amount = input.amount / 100;
iterations = input.iterations; iterations = input.iterations;
updateCanvasSize( image_data.width, image_data.height ); canvas_helper.resize( canvas, image_data );
canvas_helper.resize( tmp_canvas, image_data );
base64 = getBase64FromImageData( image_data, quality ); base64 = getBase64FromImageData( image_data, quality );
byte_array = base64ToByteArray( base64 ); byte_array = base64ToByteArray( base64 );
@ -44,7 +46,7 @@ define(
for ( i = 0; i < iterations; i++ ) for ( i = 0; i < iterations; i++ )
{ {
glitchJpegBytes( byte_array, jpg_header_length, seed, offset, i ); glitchJpegBytes( byte_array, jpg_header_length, seed, amount, i, iterations );
} }
img = new Image(); img = new Image();
@ -57,39 +59,23 @@ define(
img.src = byteArrayToBase64( byte_array ); img.src = byteArrayToBase64( byte_array );
} }
function updateCanvasSize( width, height ) function glitchJpegBytes( byte_array, jpg_header_length, seed, amount, i, len )
{ {
var updated = false;
if ( canvas_size.width !== width ) { canvas_size.width = width; updated = true; }
if ( canvas_size.height !== height ) { canvas_size.height = height; updated = true; }
if ( updated )
{
resizeCanvas( tmp_canvas, canvas_size );
resizeCanvas( canvas, canvas_size );
}
}
function resizeCanvas( canvas, img )
{
canvas.width = img.width;
canvas.height = img.height;
}
function glitchJpegBytes( byte_array, jpg_header_length, seed, offset, iteration )
{
var it = ( iteration + 1 ) / 10;
var max_index = byte_array.length - jpg_header_length - 4; var max_index = byte_array.length - jpg_header_length - 4;
var px_index = it * max_index + offset * 10; var px_min = parseInt( max_index / len * i, 10 );
var px_max = parseInt( max_index / len * ( i + 1 ), 10 );
if ( px_index > max_index ) var delta = px_max - px_min;
var px_i = parseInt( px_min + delta * seed, 10 );
if ( px_i > max_index )
{ {
px_index = px_index; px_i = max_index;
} }
var index = Math.floor( jpg_header_length + px_index ); var index = Math.floor( jpg_header_length + px_i );
byte_array[index] = Math.floor( seed * 256 );
byte_array[index] = Math.floor( amount * 256 );
} }
function getBase64FromImageData( image_data, quality ) function getBase64FromImageData( image_data, quality )

View File

@ -1,182 +0,0 @@
// https://github.com/ironwallaby/delaunay/blob/master/delaunay.js
function Triangle(a, b, c) {
this.a = a
this.b = b
this.c = c
var A = b.x - a.x,
B = b.y - a.y,
C = c.x - a.x,
D = c.y - a.y,
E = A * (a.x + b.x) + B * (a.y + b.y),
F = C * (a.x + c.x) + D * (a.y + c.y),
G = 2 * (A * (c.y - b.y) - B * (c.x - b.x)),
minx, miny, dx, dy
/* If the points of the triangle are collinear, then just find the
* extremes and use the midpoint as the center of the circumcircle. */
if(Math.abs(G) < 0.000001) {
minx = Math.min(a.x, b.x, c.x)
miny = Math.min(a.y, b.y, c.y)
dx = (Math.max(a.x, b.x, c.x) - minx) * 0.5
dy = (Math.max(a.y, b.y, c.y) - miny) * 0.5
this.x = minx + dx
this.y = miny + dy
this.r = dx * dx + dy * dy
}
else {
this.x = (D*E - B*F) / G
this.y = (A*F - C*E) / G
dx = this.x - a.x
dy = this.y - a.y
this.r = dx * dx + dy * dy
}
}
Triangle.prototype.draw = function(ctx) {
ctx.beginPath()
ctx.moveTo(this.a.x, this.a.y)
ctx.lineTo(this.b.x, this.b.y)
ctx.lineTo(this.c.x, this.c.y)
ctx.closePath()
ctx.stroke()
}
function byX(a, b) {
return b.x - a.x
}
function dedup(edges) {
var j = edges.length,
a, b, i, m, n
outer: while(j) {
b = edges[--j]
a = edges[--j]
i = j
while(i) {
n = edges[--i]
m = edges[--i]
if((a === m && b === n) || (a === n && b === m)) {
edges.splice(j, 2)
edges.splice(i, 2)
j -= 2
continue outer
}
}
}
}
function triangulate(vertices) {
/* Bail if there aren't enough vertices to form any triangles. */
if(vertices.length < 3)
return []
/* Ensure the vertex array is in order of descending X coordinate
* (which is needed to ensure a subquadratic runtime), and then find
* the bounding box around the points. */
vertices.sort(byX)
var i = vertices.length - 1,
xmin = vertices[i].x,
xmax = vertices[0].x,
ymin = vertices[i].y,
ymax = ymin
while(i--) {
if(vertices[i].y < ymin) ymin = vertices[i].y
if(vertices[i].y > ymax) ymax = vertices[i].y
}
/* Find a supertriangle, which is a triangle that surrounds all the
* vertices. This is used like something of a sentinel value to remove
* cases in the main algorithm, and is removed before we return any
* results.
*
* Once found, put it in the "open" list. (The "open" list is for
* triangles who may still need to be considered; the "closed" list is
* for triangles which do not.) */
var dx = xmax - xmin,
dy = ymax - ymin,
dmax = (dx > dy) ? dx : dy,
xmid = (xmax + xmin) * 0.5,
ymid = (ymax + ymin) * 0.5,
open = [
new Triangle(
{x: xmid - 20 * dmax, y: ymid - dmax, __sentinel: true},
{x: xmid , y: ymid + 20 * dmax, __sentinel: true},
{x: xmid + 20 * dmax, y: ymid - dmax, __sentinel: true}
)
],
closed = [],
edges = [],
j, a, b
/* Incrementally add each vertex to the mesh. */
i = vertices.length
while(i--) {
/* For each open triangle, check to see if the current point is
* inside it's circumcircle. If it is, remove the triangle and add
* it's edges to an edge list. */
edges.length = 0
j = open.length
while(j--) {
/* If this point is to the right of this triangle's circumcircle,
* then this triangle should never get checked again. Remove it
* from the open list, add it to the closed list, and skip. */
dx = vertices[i].x - open[j].x
if(dx > 0 && dx * dx > open[j].r) {
closed.push(open[j])
open.splice(j, 1)
continue
}
/* If not, skip this triangle. */
dy = vertices[i].y - open[j].y
if(dx * dx + dy * dy > open[j].r)
continue
/* Remove the triangle and add it's edges to the edge list. */
edges.push(
open[j].a, open[j].b,
open[j].b, open[j].c,
open[j].c, open[j].a
)
open.splice(j, 1)
}
/* Remove any doubled edges. */
dedup(edges)
/* Add a new triangle for each edge. */
j = edges.length
while(j) {
b = edges[--j]
a = edges[--j]
open.push(new Triangle(a, b, vertices[i]))
}
}
/* Copy any remaining open triangles to the closed list, and then
* remove any triangles that share a vertex with the supertriangle. */
Array.prototype.push.apply(closed, open)
i = closed.length
while(i--)
if(closed[i].a.__sentinel ||
closed[i].b.__sentinel ||
closed[i].c.__sentinel)
closed.splice(i, 1)
/* Yay, we're done! */
return closed
}
if (typeof module !== 'undefined') {
module.exports = {
Triangle: Triangle,
triangulate: triangulate
}
}

31
scripts/lib/raf.js Normal file
View File

@ -0,0 +1,31 @@
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
(function() {
var lastTime = 0;
var vendors = ['ms', 'moz', 'webkit', 'o'];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame']
|| window[vendors[x]+'CancelRequestAnimationFrame'];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());

View File

@ -1,338 +0,0 @@
/*global define*/
/*
Superfast Blur - a fast Box Blur For Canvas
Version: 0.5
Author: Mario Klingemann
Contact: mario@quasimondo.com
Website: http://www.quasimondo.com/BoxBlurForCanvas
Twitter: @quasimondo
In case you find this class useful - especially in commercial projects -
I am not totally unhappy for a small donation to my PayPal account
mario@quasimondo.de
Or support me on flattr:
https://flattr.com/thing/140066/Superfast-Blur-a-pretty-fast-Box-Blur-Effect-for-CanvasJavascript
Copyright (c) 2011 Mario Klingemann
Note by Georg Fischer (snorpey@gmail.com / @snorpey):
While much of the original algorithm is still the same,
I modified some parts of the script to fit my needs:
- removed the iterations argument
- modified the functions to accept an imageData object
instead of element ids to remove dependency on the
document object.
- added AMD / requirejs wrapper
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
define(
function()
{
var mul_table = [
1,57,41,21,203,34,97,73,227,91,149,62,105,45,39,137,241,107,3,173,39,71,65,238,219,101,
187,87,81,151,141,133,249,117,221,209,197,187,177,169,5,153,73,139,133,127,243,233,223,
107,103,99,191,23,177,171,165,159,77,149,9,139,135,131,253,245,119,231,224,109,211,103,
25,195,189,23,45,175,171,83,81,79,155,151,147,9,141,137,67,131,129,251,123,30,235,115,
113,221,217,53,13,51,50,49,193,189,185,91,179,175,43,169,83,163,5,79,155,19,75,147,145,
143,35,69,17,67,33,65,255,251,247,243,239,59,29,229,113,111,219,27,213,105,207,51,201,
199,49,193,191,47,93,183,181,179,11,87,43,85,167,165,163,161,159,157,155,77,19,75,37,
73,145,143,141,35,138,137,135,67,33,131,129,255,63,250,247,61,121,239,237,117,29,229,
227,225,111,55,109,216,213,211,209,207,205,203,201,199,197,195,193,48,190,47,93,185,
183,181,179,178,176,175,173,171,85,21,167,165,41,163,161,5,79,157,78,154,153,19,75,
149,74,147,73,144,143,71,141,140,139,137,17,135,134,133,66,131,65,129,1
];
var shg_table = [
0,9,10,10,14,12,14,14,16,15,16,15,16,15,15,17,18,17,12,18,16,17,17,19,19,18,19,18,18,
19,19,19,20,19,20,20,20,20,20,20,15,20,19,20,20,20,21,21,21,20,20,20,21,18,21,21,21,
21,20,21,17,21,21,21,22,22,21,22,22,21,22,21,19,22,22,19,20,22,22,21,21,21,22,22,22,
18,22,22,21,22,22,23,22,20,23,22,22,23,23,21,19,21,21,21,23,23,23,22,23,23,21,23,22,
23,18,22,23,20,22,23,23,23,21,22,20,22,21,22,24,24,24,24,24,22,21,24,23,23,24,21,24,
23,24,22,24,24,22,24,24,22,23,24,24,24,20,23,22,23,24,24,24,24,24,24,24,23,21,23,22,
23,24,24,24,22,24,24,24,23,22,24,24,25,23,25,25,23,24,25,25,24,22,25,25,25,24,23,24,
25,25,25,25,25,25,25,25,25,25,25,25,23,25,23,24,25,25,25,25,25,25,25,25,25,24,22,25,
25,23,25,25,20,24,25,24,25,25,22,24,25,24,25,24,25,25,24,25,25,25,25,22,25,25,25,24,
25,24,25,18
];
function boxBlurCanvas( image_data, radius, blur_alpha_channel )
{
var result = image_data;
if ( ! ( isNaN( radius ) || radius < 1 ) )
{
if ( blur_alpha_channel )
{
result = boxBlurCanvasRGBA( image_data, radius );
}
else
{
result = boxBlurCanvasRGB( image_data, radius );
}
}
return result;
}
function boxBlurCanvasRGBA( image_data, radius )
{
radius |= 0;
var pixels = image_data.data;
var width = image_data.width;
var height = image_data.height;
var rsum, gsum, bsum, asum, x, y, i, p, p1, p2, yp, yi, yw, idx, pa;
var wm = width - 1;
var hm = height - 1;
var wh = width * height;
var rad1 = radius + 1;
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
var r = [ ];
var g = [ ];
var b = [ ];
var a = [ ];
var vmin = [ ];
var vmax = [ ];
yw = yi = 0;
for ( y = 0; y < height; y++ )
{
rsum = pixels[yw] * rad1;
gsum = pixels[yw + 1] * rad1;
bsum = pixels[yw + 2] * rad1;
asum = pixels[yw + 3] * rad1;
for ( i = 1; i <= radius; i++ )
{
p = yw + ( ( ( i > wm ? wm : i ) ) << 2 );
rsum += pixels[p++];
gsum += pixels[p++];
bsum += pixels[p++];
asum += pixels[p];
}
for ( x = 0; x < width; x++ )
{
r[yi] = rsum;
g[yi] = gsum;
b[yi] = bsum;
a[yi] = asum;
if ( y === 0 )
{
vmin[x] = ( ( p = x + rad1) < wm ? p : wm ) << 2;
vmax[x] = ( ( p = x - radius) > 0 ? p << 2 : 0 );
}
p1 = yw + vmin[x];
p2 = yw + vmax[x];
rsum += pixels[p1++] - pixels[p2++];
gsum += pixels[p1++] - pixels[p2++];
bsum += pixels[p1++] - pixels[p2++];
asum += pixels[p1] - pixels[p2];
yi++;
}
yw += ( width << 2 );
}
for ( x = 0; x < width; x++ )
{
yp = x;
rsum = r[yp] * rad1;
gsum = g[yp] * rad1;
bsum = b[yp] * rad1;
asum = a[yp] * rad1;
for ( i = 1; i <= radius; i++ )
{
yp += ( i > hm ? 0 : width );
rsum += r[yp];
gsum += g[yp];
bsum += b[yp];
asum += a[yp];
}
yi = x << 2;
for ( y = 0; y < height; y++ )
{
pixels[yi + 3] = pa = ( asum * mul_sum ) >>> shg_sum;
if ( pa > 0 )
{
pa = 255 / pa;
pixels[yi] = ( ( rsum * mul_sum ) >>> shg_sum ) * pa;
pixels[yi+1] = ( ( gsum * mul_sum ) >>> shg_sum ) * pa;
pixels[yi+2] = ( ( bsum * mul_sum ) >>> shg_sum ) * pa;
}
else
{
pixels[yi] = pixels[yi + 1] = pixels[yi + 2] = 0;
}
if ( x === 0 )
{
vmin[y] = ( ( p = y + rad1) < hm ? p : hm ) * width;
vmax[y] = ( ( p = y - radius) > 0 ? p * width : 0 );
}
p1 = x + vmin[y];
p2 = x + vmax[y];
rsum += r[p1] - r[p2];
gsum += g[p1] - g[p2];
bsum += b[p1] - b[p2];
asum += a[p1] - a[p2];
yi += width << 2;
}
}
return image_data;
}
function boxBlurCanvasRGB( image_data, radius )
{
radius |= 0;
var pixels = image_data.data;
var width = image_data.width;
var height = image_data.height;
var rsum, gsum, bsum, asum, x, y, i, p, p1, p2, yp, yi, yw, idx;
var wm = width - 1;
var hm = height - 1;
var wh = width * height;
var rad1 = radius + 1;
var r = [ ];
var g = [ ];
var b = [ ];
var mul_sum = mul_table[radius];
var shg_sum = shg_table[radius];
var vmin = [ ];
var vmax = [ ];
yw = yi = 0;
for ( y = 0; y < height; y++ )
{
rsum = pixels[yw] * rad1;
gsum = pixels[yw + 1] * rad1;
bsum = pixels[yw + 2] * rad1;
for ( i = 1; i <= radius; i++ )
{
p = yw + ( ( ( i > wm ? wm : i ) ) << 2 );
rsum += pixels[p++];
gsum += pixels[p++];
bsum += pixels[p++];
}
for ( x = 0; x < width; x++ )
{
r[yi] = rsum;
g[yi] = gsum;
b[yi] = bsum;
if ( y === 0 )
{
vmin[x] = ( ( p = x + rad1) < wm ? p : wm ) << 2;
vmax[x] = ( ( p = x - radius) > 0 ? p << 2 : 0 );
}
p1 = yw + vmin[x];
p2 = yw + vmax[x];
rsum += pixels[p1++] - pixels[p2++];
gsum += pixels[p1++] - pixels[p2++];
bsum += pixels[p1++] - pixels[p2++];
yi++;
}
yw += ( width << 2 );
}
for ( x = 0; x < width; x++ )
{
yp = x;
rsum = r[yp] * rad1;
gsum = g[yp] * rad1;
bsum = b[yp] * rad1;
for ( i = 1; i <= radius; i++ )
{
yp += ( i > hm ? 0 : width );
rsum += r[yp];
gsum += g[yp];
bsum += b[yp];
}
yi = x << 2;
for ( y = 0; y < height; y++ )
{
pixels[yi] = (rsum * mul_sum) >>> shg_sum;
pixels[yi+1] = (gsum * mul_sum) >>> shg_sum;
pixels[yi+2] = (bsum * mul_sum) >>> shg_sum;
if ( x === 0 )
{
vmin[y] = ( ( p = y + rad1) < hm ? p : hm ) * width;
vmax[y] = ( ( p = y - radius) > 0 ? p * width : 0 );
}
p1 = x + vmin[y];
p2 = x + vmax[y];
rsum += r[p1] - r[p2];
gsum += g[p1] - g[p2];
bsum += b[p1] - b[p2];
yi += width << 2;
}
}
return image_data;
}
return boxBlurCanvas;
}
);

View File

@ -1,7 +1,7 @@
/*global define*/ /*global define, requestAnimationFrame*/
define( define(
[ 'aux/glitch' ], [ 'aux/glitch', 'aux/canvas', 'lib/raf' ],
function( glitch ) function( glitch, canvas_helper )
{ {
var tmp_canvas = document.createElement( 'canvas' ); var tmp_canvas = document.createElement( 'canvas' );
var tmp_ctx = tmp_canvas.getContext( '2d' ); var tmp_ctx = tmp_canvas.getContext( '2d' );
@ -14,6 +14,7 @@ define(
var image; var image;
var signals; var signals;
var image_data; var image_data;
var canvas_size;
function init( shared ) function init( shared )
{ {
@ -40,23 +41,37 @@ define(
} }
} }
function requestTick()
{
if ( ! is_processing )
{
requestAnimationFrame( update );
}
is_processing = true;
}
function update() function update()
{ {
if ( ! is_processing && image ) if ( image )
{ {
processImage( image ); processImage( image );
} }
else
{
is_processing = false;
}
} }
function processImage( img ) function processImage( img )
{ {
is_processing = true; is_processing = true;
clearCanvas( tmp_canvas, tmp_ctx ); canvas_helper.clear( tmp_canvas, tmp_ctx );
clearCanvas( canvas, ctx ); canvas_helper.clear( canvas, ctx );
canvas_helper.resize( tmp_canvas, img );
resizeCanvas( tmp_canvas, img ); canvas_helper.resize( canvas, img );
resizeCanvas( canvas, img );
tmp_ctx.drawImage( img, 0, 0 ); tmp_ctx.drawImage( img, 0, 0 );
@ -67,24 +82,13 @@ define(
function draw( image_data ) function draw( image_data )
{ {
resizeCanvas( canvas, image_data ); canvas_helper.resize( canvas, image_data );
ctx.putImageData( image_data, 0, 0 ); ctx.putImageData( image_data, 0, 0 );
is_processing = false; is_processing = false;
image_data = null; image_data = null;
} }
function resizeCanvas( canvas, img )
{
canvas.width = img.width;
canvas.height = img.height;
}
function clearCanvas( canvas, ctx )
{
ctx.clearRect( ctx, 0, 0, canvas.width, canvas.height );
}
function exportData() function exportData()
{ {
signals['export-png'].dispatch( canvas.toDataURL( 'image/png' ) ); signals['export-png'].dispatch( canvas.toDataURL( 'image/png' ) );