Merge branch 'develop'
This commit is contained in:
commit
8e8db95498
15
README.md
15
README.md
@ -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".
|
||||||
|
|
||||||
[](http://snorpey.github.io/triangulation/)
|
[](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
|
||||||
---
|
---
|
||||||
|
|||||||
20
index.html
20
index.html
@ -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
38
scripts/aux/canvas.js
Normal 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 };
|
||||||
|
}
|
||||||
|
);
|
||||||
@ -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 )
|
||||||
|
|||||||
@ -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
31
scripts/lib/raf.js
Normal 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);
|
||||||
|
};
|
||||||
|
}());
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
@ -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' ) );
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user