Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
snorpey committed Jul 13, 2013
0 parents commit 5194c16
Show file tree
Hide file tree
Showing 20 changed files with 3,762 additions and 0 deletions.
25 changes: 25 additions & 0 deletions .gitignore
@@ -0,0 +1,25 @@
#Mac OS files
.DS_Store
.AppleDouble
.LSOverride
Icon

# Thumbnails
._*

# Files that might appear on external disk
.Spotlight-V100
.Trashes

# Windows image file caches
Thumbs.db
ehthumbs.db

# Folder config file
Desktop.ini

# Recycle Bin used on file shares
$RECYCLE.BIN/

# SublimeText project files
*.sublime-workspace
21 changes: 21 additions & 0 deletions README.md
@@ -0,0 +1,21 @@
image distortion experiment
===

this is an experiment for the web browser. it distorts images by dividing the image into a grid and then distorting it by calculating the contrast in every cell of the grid.

[![distortion experiment screen shot](https://dl.dropboxusercontent.com/u/1098704/Screenshots/github-contrast-distort.png)](http://snorpey.github.io/contrast-distort/)

[online demo](http://snorpey.github.io/contrast-distort/)

some parts of the warping code are taken from [@migurski](https://github.com/migurski)s [canvas warp demo](https://github.com/migurski/canvas-warp/blob/master/index.html) and [@canvastag](https://twitter.com/canvastag)s [implementation](http://jsdo.it/canvastag/y56M).

third party code used in this experiment
---
* [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
* [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
---
[MIT License](http://www.opensource.org/licenses/mit-license.php)
45 changes: 45 additions & 0 deletions index.html
@@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>image experiment</title>
<link rel="stylesheet" href="styles/global.css" />
</head>
<body>
<article class="content">
<h1 class="headline">distort images</h1>
<p>drag an image into the browser window to modify it.</p>
<p>i oringinally set out to recreate <a href="http://www.bendehaanphotography.com">ben dehaan</a>s <a href="http://www.bendehaanphotography.com/uncured-timelapse/">uncured inkjet prints</a> in javascript. what i ended up with looks completely different, but is still kind of fun to play with.</p>
<p>the script divides the image into a grid and uses the contrast of each cell to distort it.</p>
<p>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/contrast-distort">github</a>.
</article>
<div class="content" id="controls">
<div class="control-wrapper">
<label class="control-label" for="amount">distortion amount</label>
<input class="control-input" type="range" id="amount" min="0" max="100" value="50" />
</div>
<div class="control-wrapper">
<label class="control-label" for="horizontal">horizontal distortion</label>
<input class="control-input" type="range" id="horizontal" min="-1" max="1" value="0" step="0.1" />
</div>
<div class="control-wrapper">
<label class="control-label" for="vertical">vertical distortion</label>
<input class="control-input" type="range" id="vertical" min="-1" max="1" value="1" step="0.1" />
</div>
<div class="control-wrapper">
<label class="control-label" for="grid_size">grid size</label>
<input class="control-input" type="range" id="grid_size" min="15" max="100" value="40" />
</div>
<div class="control-wrapper">
<label class="control-label" for="detail">accuracy</label>
<input class="control-input" type="range" id="detail" min="5" max="100" value="50" />
</div>
</div>
<div class="export-wrapper">
<button id="save-button" class="button">export image</button>
<a id="png-button" download="glitched-image.png" target="_blank" class="download-link">download bitmap file<span> (.png)</span></a>
</div>
<canvas id="canvas"></canvas>
<script src="scripts/lib/require-2.1.4.js" data-main="scripts/src/main"></script>
</body>
</html>
Binary file added lincoln.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions scripts/aux/canvas.js
@@ -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 };
}
);
247 changes: 247 additions & 0 deletions scripts/aux/distort.js
@@ -0,0 +1,247 @@
/*global define*/
define(
[ 'aux/canvas', 'aux/imagedata-contrast' ],
function( canvas_helper, getImageDataContrast )
{
var canvas = document.createElement( 'canvas' );
var ctx = canvas.getContext( '2d' );

var tmp_canvas = document.createElement( 'canvas' );
var tmp_ctx = tmp_canvas.getContext( '2d' );

var res_canvas = document.createElement( 'canvas' );
var res_ctx = res_canvas.getContext( '2d' );

var amount;
var grid_size;
var detail;

var direction = { x: 0, y: 1 };

var i, j;
var len, len_2;

var cell_count = 0;
var cells_created = 0;

var done;


function applyFilter( image_data, input, callback )
{
amount = input.amount;
grid_size = input.grid_size;
detail = 100 - input.detail;
direction.x = input.horizontal;
direction.y = input.vertical;
done = callback;

res_ctx.clearRect( 0, 0, res_canvas.width, res_canvas.height );
tmp_ctx.clearRect( 0, 0, tmp_canvas.width, tmp_canvas.height );
ctx.clearRect( 0, 0, canvas.width, canvas.height );

canvas_helper.resize( canvas, image_data );
canvas_helper.resize( tmp_canvas, image_data );
canvas_helper.resize( res_canvas, image_data );

ctx.putImageData( image_data, 0, 0 );

process( image_data, amount );
}

function process( image_data, amount )
{
var width = image_data.width;
var height = image_data.height;
var grid_points = getGridPoints( image_data, grid_size, grid_size );
var distorted_points = getDistortedPoints( grid_points, grid_size, grid_size );

canvas_helper.resize( tmp_canvas, { width: grid_size, height: grid_size } );

distorted_points.forEach( processPoint );
}

function processPoint( p1, index, distorted_points )
{
var p2 = getItemByValue( distorted_points, 'row', p1.row + 1, 'column', p1.column );
var p3 = getItemByValue( distorted_points, 'row', p1.row, 'column', p1.column + 1 );
var p4 = getItemByValue( distorted_points, 'row', p1.row + 1, 'column', p1.column + 1 );

if ( p1 && p2 && p3 && p4 )
{
tmp_ctx.putImageData( p1.image_data, 0, 0 );

var img = new Image();

img.onload = function()
{
drawCell( res_ctx, img, p1, p2, p3, p4 );

cells_created++;

if ( cell_count === cells_created )
{
done( res_ctx.getImageData( 0, 0, canvas.width, canvas.height ) );
}
};

img.src = tmp_canvas.toDataURL( 'image/png' );

cell_count++;
}
}

// by @migurski
// http://mike.teczno.com/notes/canvas-warp.html
function drawCell( ctx, image, p1, p2, p3, p4 )
{
var xm = getLinearSolution( 0, 0, p1.end_x, image.width, 0, p2.end_x, 0, image.height, p3.end_x );
var ym = getLinearSolution( 0, 0, p1.end_y, image.width, 0, p2.end_y, 0, image.height, p3.end_y );
var xn = getLinearSolution( image.width, image.height, p4.end_x, image.width, 0, p2.end_x, 0, image.height, p3.end_x );
var yn = getLinearSolution( image.width, image.height, p4.end_y, image.width, 0, p2.end_y, 0, image.height, p3.end_y );

ctx.save();
ctx.setTransform( xm[0], ym[0], xm[1], ym[1], xm[2], ym[2] );
ctx.beginPath();
ctx.moveTo( 0, 0 );
ctx.lineTo( image.width, 0 );
ctx.lineTo( 0, image.height );
ctx.lineTo( 0, 0 );
ctx.closePath();
ctx.fill();
ctx.clip();
ctx.drawImage( image, 0, 0, image.width, image.height );
ctx.restore();

ctx.save();
ctx.setTransform( xn[0], yn[0], xn[1], yn[1], xn[2], yn[2] );
ctx.beginPath();
ctx.moveTo( image.width, image.height );
ctx.lineTo( image.width, 0 );
ctx.lineTo( 0, image.height );
ctx.lineTo( image.width, image.height );
ctx.closePath();
ctx.fill();
ctx.clip();
ctx.drawImage( image, 0, 0, image.width, image.height );
ctx.restore();
}

function getLinearSolution( r1, s1, t1, r2, s2, t2, r3, s3, t3 )
{
r1 = parseFloat( r1 );
s1 = parseFloat( s1 );
t1 = parseFloat( t1 );
r2 = parseFloat( r2 );
s2 = parseFloat( s2 );
t2 = parseFloat( t2 );
r3 = parseFloat( r3 );
s3 = parseFloat( s3 );
t3 = parseFloat( t3 );

var a = (((t2 - t3) * (s1 - s2)) - ((t1 - t2) * (s2 - s3))) / (((r2 - r3) * (s1 - s2)) - ((r1 - r2) * (s2 - s3)));
var b = (((t2 - t3) * (r1 - r2)) - ((t1 - t2) * (r2 - r3))) / (((s2 - s3) * (r1 - r2)) - ((s1 - s2) * (r2 - r3)));
var c = t1 - ( r1 * a ) - ( s1 * b );

return [ a, b, c ];
}

function getGridPoints( image_data, tile_width, tile_height )
{
var grid_points = [ ];
var index = 0;
var x = 0;
var y = 0;
var width = image_data.width;
var height = image_data.height;
var column = 0;
var row = 0;

for ( x = 0; x < height; x += tile_height )
{
column = 0;

for ( y = 0; y < width; y += tile_width )
{
if (
x + tile_width < width &&
y + tile_height < height
)
{
grid_points[index] = {
x : x,
y : y,
column : column,
row : row,
data_index : ( x * width + y ) * 4
};

index++;
}

column++;
}

row++;
}

grid_points.rows = row;
grid_points.columns = column;

return grid_points;
}

function getDistortedPoints( grid_points, tile_width, tile_height )
{
var tile_image_data;
var cell_contrast;
var key;
var distortion;
var tile_points = [ ];

len = grid_points.length;

for ( i = 0; i < len; i++ )
{
tile_image_data = ctx.getImageData( grid_points[i].x, grid_points[i].y, tile_width, tile_height );
cell_contrast = getImageDataContrast( tile_image_data, detail );
distortion = amount * cell_contrast;

grid_points[i].image_data = tile_image_data;
grid_points[i].end_x = parseInt( grid_points[i].x + ( direction.x * distortion ), 10 );
grid_points[i].end_y = parseInt( grid_points[i].y + ( direction.y * distortion ), 10 );
}

return grid_points;
}

function drawBackground( canvas, ctx, color )
{
ctx.fillStyle = color;
ctx.fillRect( 0, 0, canvas.width, canvas.height );
}

function getItemByValue( items, key, value, key_2, value_2 )
{
var result;

len_2 = items.length;

for ( j = 0; j < len_2; j++ )
{
if (
items[j][key] === value &&
items[j][key_2] === value_2
)
{
result = items[j];
break;
}
}

return result;
}

return applyFilter;
}
);

0 comments on commit 5194c16

Please sign in to comment.