From 346f3a9817b1e0812565396b9811a1ce5adc97b8 Mon Sep 17 00:00:00 2001 From: jules Date: Fri, 13 Dec 2013 15:28:31 -0500 Subject: reorganize --- ...6658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png | Bin 163827 -> 0 bytes FileSaver.js | 232 --- abyss.png | Bin 193659 -> 0 bytes bin/proxy.py | 22 + bower.json | 2 +- building.png | Bin 408192 -> 0 bytes canvasquery.dither.js | 217 --- canvasquery.js | 1767 -------------------- dataUriToBlob.js | 47 - gif-animate.html | 6 +- gif-dither.html | 16 +- gif-encode/GIFEncoder.js | 513 ------ gif-encode/LZWEncoder.js | 328 ---- gif-encode/NeuQuant.js | 538 ------ gif-encode/client.js | 260 --- gif-encode/tube.js | 323 ---- gif-encode/util.js | 15 - gif-encode/worker.js | 88 - gif.html | 14 +- gif.js | 1690 ------------------- gradient.jpg | Bin 19198 -> 0 bytes halftone.html | 6 +- ...6658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png | Bin 0 -> 163827 bytes img/abyss.png | Bin 0 -> 193659 bytes img/building.png | Bin 0 -> 408192 bytes img/gradient.jpg | Bin 0 -> 19198 bytes index.html | 6 +- js/canvasquery.dither.js | 228 +++ js/util.js | 3 + js/vendor/FileSaver/.bower.json | 15 + js/vendor/FileSaver/FileSaver.js | 232 +++ js/vendor/FileSaver/LICENSE.md | 30 + js/vendor/FileSaver/README.md | 78 + js/vendor/FileSaver/bower.json | 7 + js/vendor/FileSaver/demo/demo.css | 55 + js/vendor/FileSaver/demo/demo.js | 213 +++ js/vendor/FileSaver/demo/demo.min.js | 2 + js/vendor/FileSaver/demo/index.xhtml | 57 + js/vendor/FileSaver/package.json | 23 + js/vendor/canvasquery.js | 1767 ++++++++++++++++++++ js/vendor/dataUriToBlob.js | 47 + js/vendor/gif-encode/GIFEncoder.js | 513 ++++++ js/vendor/gif-encode/LZWEncoder.js | 328 ++++ js/vendor/gif-encode/NeuQuant.js | 538 ++++++ js/vendor/gif-encode/client.js | 260 +++ js/vendor/gif-encode/tube.js | 323 ++++ js/vendor/gif-encode/util.js | 15 + js/vendor/gif-encode/worker.js | 88 + js/vendor/gif.js | 1690 +++++++++++++++++++ pattern.html | 6 +- proxy.py | 22 - shader-demo.html | 13 +- shader.html | 6 +- threshold.html | 6 +- vendor/FileSaver/.bower.json | 15 - vendor/FileSaver/FileSaver.js | 232 --- vendor/FileSaver/LICENSE.md | 30 - vendor/FileSaver/README.md | 78 - vendor/FileSaver/bower.json | 7 - vendor/FileSaver/demo/demo.css | 55 - vendor/FileSaver/demo/demo.js | 213 --- vendor/FileSaver/demo/demo.min.js | 2 - vendor/FileSaver/demo/index.xhtml | 57 - vendor/FileSaver/package.json | 23 - 64 files changed, 6574 insertions(+), 6793 deletions(-) delete mode 100644 1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png delete mode 100644 FileSaver.js delete mode 100644 abyss.png create mode 100755 bin/proxy.py delete mode 100644 building.png delete mode 100644 canvasquery.dither.js delete mode 100644 canvasquery.js delete mode 100644 dataUriToBlob.js delete mode 100755 gif-encode/GIFEncoder.js delete mode 100644 gif-encode/LZWEncoder.js delete mode 100644 gif-encode/NeuQuant.js delete mode 100644 gif-encode/client.js delete mode 100644 gif-encode/tube.js delete mode 100644 gif-encode/util.js delete mode 100644 gif-encode/worker.js delete mode 100644 gif.js delete mode 100644 gradient.jpg create mode 100644 img/1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png create mode 100644 img/abyss.png create mode 100644 img/building.png create mode 100644 img/gradient.jpg create mode 100644 js/canvasquery.dither.js create mode 100644 js/util.js create mode 100644 js/vendor/FileSaver/.bower.json create mode 100644 js/vendor/FileSaver/FileSaver.js create mode 100644 js/vendor/FileSaver/LICENSE.md create mode 100644 js/vendor/FileSaver/README.md create mode 100644 js/vendor/FileSaver/bower.json create mode 100644 js/vendor/FileSaver/demo/demo.css create mode 100644 js/vendor/FileSaver/demo/demo.js create mode 100644 js/vendor/FileSaver/demo/demo.min.js create mode 100644 js/vendor/FileSaver/demo/index.xhtml create mode 100644 js/vendor/FileSaver/package.json create mode 100644 js/vendor/canvasquery.js create mode 100644 js/vendor/dataUriToBlob.js create mode 100755 js/vendor/gif-encode/GIFEncoder.js create mode 100644 js/vendor/gif-encode/LZWEncoder.js create mode 100644 js/vendor/gif-encode/NeuQuant.js create mode 100644 js/vendor/gif-encode/client.js create mode 100644 js/vendor/gif-encode/tube.js create mode 100644 js/vendor/gif-encode/util.js create mode 100644 js/vendor/gif-encode/worker.js create mode 100644 js/vendor/gif.js delete mode 100644 proxy.py delete mode 100644 vendor/FileSaver/.bower.json delete mode 100644 vendor/FileSaver/FileSaver.js delete mode 100644 vendor/FileSaver/LICENSE.md delete mode 100644 vendor/FileSaver/README.md delete mode 100644 vendor/FileSaver/bower.json delete mode 100644 vendor/FileSaver/demo/demo.css delete mode 100644 vendor/FileSaver/demo/demo.js delete mode 100644 vendor/FileSaver/demo/demo.min.js delete mode 100644 vendor/FileSaver/demo/index.xhtml delete mode 100644 vendor/FileSaver/package.json diff --git a/1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png b/1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png deleted file mode 100644 index 019c209..0000000 Binary files a/1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png and /dev/null differ diff --git a/FileSaver.js b/FileSaver.js deleted file mode 100644 index 378a9dc..0000000 --- a/FileSaver.js +++ /dev/null @@ -1,232 +0,0 @@ -/* FileSaver.js - * A saveAs() FileSaver implementation. - * 2013-10-21 - * - * By Eli Grey, http://eligrey.com - * License: X11/MIT - * See LICENSE.md - */ - -/*global self */ -/*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, - plusplus: true */ - -/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ - -var saveAs = saveAs - || (typeof navigator !== 'undefined' && navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator)) - || (function(view) { - "use strict"; - var - doc = view.document - // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet - , get_URL = function() { - return view.URL || view.webkitURL || view; - } - , URL = view.URL || view.webkitURL || view - , save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a") - , can_use_save_link = !view.externalHost && "download" in save_link - , click = function(node) { - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - node.dispatchEvent(event); - } - , webkit_req_fs = view.webkitRequestFileSystem - , req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem - , throw_outside = function (ex) { - (view.setImmediate || view.setTimeout)(function() { - throw ex; - }, 0); - } - , force_saveable_type = "application/octet-stream" - , fs_min_size = 0 - , deletion_queue = [] - , process_deletion_queue = function() { - var i = deletion_queue.length; - while (i--) { - var file = deletion_queue[i]; - if (typeof file === "string") { // file is an object URL - URL.revokeObjectURL(file); - } else { // file is a File - file.remove(); - } - } - deletion_queue.length = 0; // clear queue - } - , dispatch = function(filesaver, event_types, event) { - event_types = [].concat(event_types); - var i = event_types.length; - while (i--) { - var listener = filesaver["on" + event_types[i]]; - if (typeof listener === "function") { - try { - listener.call(filesaver, event || filesaver); - } catch (ex) { - throw_outside(ex); - } - } - } - } - , FileSaver = function(blob, name) { - // First try a.download, then web filesystem, then object URLs - var - filesaver = this - , type = blob.type - , blob_changed = false - , object_url - , target_view - , get_object_url = function() { - var object_url = get_URL().createObjectURL(blob); - deletion_queue.push(object_url); - return object_url; - } - , dispatch_all = function() { - dispatch(filesaver, "writestart progress write writeend".split(" ")); - } - // on any filesys errors revert to saving with object URLs - , fs_error = function() { - // don't create more object URLs than needed - if (blob_changed || !object_url) { - object_url = get_object_url(blob); - } - if (target_view) { - target_view.location.href = object_url; - } else { - window.open(object_url, "_blank"); - } - filesaver.readyState = filesaver.DONE; - dispatch_all(); - } - , abortable = function(func) { - return function() { - if (filesaver.readyState !== filesaver.DONE) { - return func.apply(this, arguments); - } - }; - } - , create_if_not_found = {create: true, exclusive: false} - , slice - ; - filesaver.readyState = filesaver.INIT; - if (!name) { - name = "download"; - } - if (can_use_save_link) { - object_url = get_object_url(blob); - // FF for Android has a nasty garbage collection mechanism - // that turns all objects that are not pure javascript into 'deadObject' - // this means `doc` and `save_link` are unusable and need to be recreated - // `view` is usable though: - doc = view.document; - save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a"); - save_link.href = object_url; - save_link.download = name; - var event = doc.createEvent("MouseEvents"); - event.initMouseEvent( - "click", true, false, view, 0, 0, 0, 0, 0 - , false, false, false, false, 0, null - ); - save_link.dispatchEvent(event); - filesaver.readyState = filesaver.DONE; - dispatch_all(); - return; - } - // Object and web filesystem URLs have a problem saving in Google Chrome when - // viewed in a tab, so I force save with application/octet-stream - // http://code.google.com/p/chromium/issues/detail?id=91158 - if (view.chrome && type && type !== force_saveable_type) { - slice = blob.slice || blob.webkitSlice; - blob = slice.call(blob, 0, blob.size, force_saveable_type); - blob_changed = true; - } - // Since I can't be sure that the guessed media type will trigger a download - // in WebKit, I append .download to the filename. - // https://bugs.webkit.org/show_bug.cgi?id=65440 - if (webkit_req_fs && name !== "download") { - name += ".download"; - } - if (type === force_saveable_type || webkit_req_fs) { - target_view = view; - } - if (!req_fs) { - fs_error(); - return; - } - fs_min_size += blob.size; - req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) { - fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) { - var save = function() { - dir.getFile(name, create_if_not_found, abortable(function(file) { - file.createWriter(abortable(function(writer) { - writer.onwriteend = function(event) { - target_view.location.href = file.toURL(); - deletion_queue.push(file); - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "writeend", event); - }; - writer.onerror = function() { - var error = writer.error; - if (error.code !== error.ABORT_ERR) { - fs_error(); - } - }; - "writestart progress write abort".split(" ").forEach(function(event) { - writer["on" + event] = filesaver["on" + event]; - }); - writer.write(blob); - filesaver.abort = function() { - writer.abort(); - filesaver.readyState = filesaver.DONE; - }; - filesaver.readyState = filesaver.WRITING; - }), fs_error); - }), fs_error); - }; - dir.getFile(name, {create: false}, abortable(function(file) { - // delete file if it already exists - file.remove(); - save(); - }), abortable(function(ex) { - if (ex.code === ex.NOT_FOUND_ERR) { - save(); - } else { - fs_error(); - } - })); - }), fs_error); - }), fs_error); - } - , FS_proto = FileSaver.prototype - , saveAs = function(blob, name) { - return new FileSaver(blob, name); - } - ; - FS_proto.abort = function() { - var filesaver = this; - filesaver.readyState = filesaver.DONE; - dispatch(filesaver, "abort"); - }; - FS_proto.readyState = FS_proto.INIT = 0; - FS_proto.WRITING = 1; - FS_proto.DONE = 2; - - FS_proto.error = - FS_proto.onwritestart = - FS_proto.onprogress = - FS_proto.onwrite = - FS_proto.onabort = - FS_proto.onerror = - FS_proto.onwriteend = - null; - - view.addEventListener("unload", process_deletion_queue, false); - return saveAs; -}(this.self || this.window || this.content)); -// `self` is undefined in Firefox for Android content script context -// while `this` is nsIContentFrameMessageManager -// with an attribute `content` that corresponds to the window - -if (typeof module !== 'undefined') module.exports = saveAs; diff --git a/abyss.png b/abyss.png deleted file mode 100644 index 4ce8d1d..0000000 Binary files a/abyss.png and /dev/null differ diff --git a/bin/proxy.py b/bin/proxy.py new file mode 100755 index 0000000..6171dab --- /dev/null +++ b/bin/proxy.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +import http.server +import urllib.request + +class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler): + def end_headers(self): + self.send_my_headers() + + http.server.SimpleHTTPRequestHandler.end_headers(self) + + def send_my_headers(self): + self.send_header("Access-Control-Allow-Origin", "*") + + def do_GET(self): + if self.path[0:14] == "/cgi-bin/proxy": + self.copyfile(urllib.request.urlopen(self.path[15:]), self.wfile) + else: + super().do_GET() + +if __name__ == '__main__': + http.server.test(HandlerClass=MyHTTPRequestHandler) + diff --git a/bower.json b/bower.json index 31aa3d2..32f4913 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "dither", "version": "0.0.4", - "homepage": "http://asdf.us", + "homepage": "http://asdf.us/dither/", "authors": [ "julie" ], diff --git a/building.png b/building.png deleted file mode 100644 index 4032700..0000000 Binary files a/building.png and /dev/null differ diff --git a/canvasquery.dither.js b/canvasquery.dither.js deleted file mode 100644 index a76ad12..0000000 --- a/canvasquery.dither.js +++ /dev/null @@ -1,217 +0,0 @@ -var patterns = {} -patterns[2] = [ 0, 2, - 3, 1 ] - -patterns[3] = [ 0, 5, 3, - 8, 1, 6, - 4, 7, 2, ] - -patterns[4] = [ 0, 8, 2, 10, - 6, 14, 4, 12, - 3, 11, 1, 9, - 5, 13, 7, 15 ] - -CanvasQuery.Wrapper.prototype.threshold = function(factor) { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var width = this.canvas.width - var height = this.canvas.height - - if (factor < 1) factor *= 255 - - for (var i = 0; i < height; i++) { - for (var j = 0; j < width; j++) { - var a = 4 * (i*width + j) - var val = (bitmapData[a] + bitmapData[a+1] + bitmapData[a+2]) / 3 - var lum = val > factor ? 255 : 0 - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.randomDither = function() { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var width = this.canvas.width - var height = this.canvas.height - - for (var i = 0; i < height; i++) { - for (var j = 0; j < width; j++) { - var a = 4 * (i*width + j) - var val = (bitmapData[a] + bitmapData[a+1] + bitmapData[a+2]) / (3*255) - var lum = val > Math.random() ? 255 : 0 - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.pattern2Dither = function() { - this.patternDither(2) -} -CanvasQuery.Wrapper.prototype.pattern3Dither = function() { - this.patternDither(3) -} -CanvasQuery.Wrapper.prototype.pattern4Dither = function() { - this.patternDither(4) -} -CanvasQuery.Wrapper.prototype.patternDither = function(n) { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var width = this.canvas.width - var height = this.canvas.height - - var pat = patterns[n] - var len = pat.length - 1 - - for (var i = 0; i < height; i++) { - for (var j = 0; j < width; j++) { - var p = ((i % n) * n) + (j % n) - var a = 4 * (i*width + j) - var val = (bitmapData[a] + bitmapData[a+1] + bitmapData[a+2]) / (3*255) - var lum = val > pat[p]/len ? 255 : 0 - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.pattern2LiteDither = function() { - this.patternLiteDither(2) -} -CanvasQuery.Wrapper.prototype.pattern3LiteDither = function() { - this.patternLiteDither(3) -} -CanvasQuery.Wrapper.prototype.pattern4LiteDither = function() { - this.patternLiteDither(4) -} -CanvasQuery.Wrapper.prototype.patternLiteDither = function(n) { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var width = this.canvas.width - var height = this.canvas.height - - var pat = patterns[n] - var len = pat.length - - for (var i = 0; i < height; i++) { - for (var j = 0; j < width; j++) { - var p = ((i % n) * n) + (j % n) - var a = 4 * (i*width + j) - var val = (bitmapData[a] + bitmapData[a+1] + bitmapData[a+2]) / (3*255) - var lum = val > pat[p]/len ? 255 : 0 - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.floydSteinbergDither = function(n) { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var mask = this.grayscaleToMask() - - var width = this.canvas.width - var height = this.canvas.height - - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var p = (y*width + x) - var a = 4 * p - var val = mask[p] - var lum = val > 127 ? 255 : 0 - var error = val - lum - if (x < width-1) - mask[ (y*width) + x+1 ] += 7/16 * error - if (y < height-1 && x > 0) - mask[ ((y+1)*width) + x-1 ] += 5/16 * error - if (y < height-1) - mask[ ((y+1)*width) + x ] += 3/16 * error - if (y < height-1 && x < width-1) - mask[ ((y+1)*width) + x+1 ] += 1/16 * error - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.rightDither = function(n) { - var bitmap = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height) - var bitmapData = bitmap.data - - var mask = this.grayscaleToMask() - - var width = this.canvas.width - var height = this.canvas.height - - for (var y = 0; y < height; y++) { - for (var x = 0; x < width; x++) { - var p = (y*width + x) - var a = 4 * p - var val = mask[p] - var lum = val > 127 ? 255 : 0 - var error = val - lum - if (x < width-1) - mask[ (y*width) + x+1 ] += 7/16 * error - bitmapData[a] = bitmapData[a+1] = bitmapData[a+2] = lum - } - } - this.context.putImageData(bitmap, 0, 0); - return this; -} - -CanvasQuery.Wrapper.prototype.halftone = function(radius, angle) { - var mask = this.grayscaleToMask() - - this.fillStyle("#fff") - this.fillRect(0, 0, this.canvas.width, this.canvas.height) - - var diameter = radius*2 - var TWO_PI = Math.PI*2 - - var angle = angle / 180 * Math.PI - - var cos = Math.cos(angle) - var sin = Math.sin(angle) - - var xstep = cos * radius - var ystep = sin * radius - - var w = this.canvas.width - var h = this.canvas.height - - this.fillStyle("#000") - - for (var i = -w; i < w; i++) { - for (var j = -h; j < h; j++) { - var x = i * ystep - j * xstep - var y = i * xstep + j * ystep - if (x > -diameter && y > -diameter && x < w+diameter && y < h+diameter) { - circle(this,x,y) - } - } - } - - function circle(cq,x,y) { - var xx = x < 0 ? 0 : x > w ? w - 1 : x; - var yy = y < 0 ? 0 : y > h ? h - 1 : y; - var r = (1 - Math.pow( mask[ ~~(~~yy*w+(xx)) ] / 255, Math.E/4 )) * radius - cq.beginPath() - .arc(x,y,r,0,TWO_PI) - .closePath() - .fill(); - } - return this; -} - diff --git a/canvasquery.js b/canvasquery.js deleted file mode 100644 index a5b36f3..0000000 --- a/canvasquery.js +++ /dev/null @@ -1,1767 +0,0 @@ -/* - Canvas Query 0.8.4 - http://canvasquery.org - (c) 2012-2013 http://rezoner.net - Canvas Query may be freely distributed under the MIT license. -*/ - -(function(window, undefined) { - - var MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); - - - window.requestAnimationFrame = (function() { - return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) { - window.setTimeout(callback, 1000 / 60); - }; - })(); - - - var $ = function(selector) { - if (arguments.length === 0) { - var canvas = $.createCanvas(window.innerWidth, window.innerHeight); - window.addEventListener("resize", function() { - // canvas.width = window.innerWidth; - // canvas.height = window.innerHeight; - }); - } else if (typeof selector === "string") { - var canvas = document.querySelector(selector); - } else if (typeof selector === "number") { - var canvas = $.createCanvas(arguments[0], arguments[1]); - } else if (selector instanceof Image || selector instanceof HTMLImageElement) { - var canvas = $.createCanvas(selector); - } else if (selector instanceof $.Wrapper) { - return selector; - } else { - var canvas = selector; - } - - return new $.Wrapper(canvas); - } - - $.extend = function() { - for (var i = 1; i < arguments.length; i++) { - for (var j in arguments[i]) { - arguments[0][j] = arguments[i][j]; - } - } - - return arguments[0]; - }; - - $.augment = function() { - for (var i = 1; i < arguments.length; i++) { - _.extend(arguments[0], arguments[i]); - arguments[i](arguments[0]); - } - }; - - $.distance = function(x1, y1, x2, y2) { - if (arguments.length > 2) { - var dx = x1 - x2; - var dy = y1 - y2; - - return Math.sqrt(dx * dx + dy * dy); - } else { - return Math.abs(x1 - y1); - } - }; - - $.extend($, { - - keycodes: { - 37: "left", - 38: "up", - 39: "right", - 40: "down", - 45: "insert", - 46: "delete", - 8: "backspace", - 9: "tab", - 13: "enter", - 16: "shift", - 17: "ctrl", - 18: "alt", - 19: "pause", - 20: "capslock", - 27: "escape", - 32: "space", - 33: "pageup", - 34: "pagedown", - 35: "end", - 112: "f1", - 113: "f2", - 114: "f3", - 115: "f4", - 116: "f5", - 117: "f6", - 118: "f7", - 119: "f8", - 120: "f9", - 121: "f10", - 122: "f11", - 123: "f12", - 144: "numlock", - 145: "scrolllock", - 186: "semicolon", - 187: "equal", - 188: "comma", - 189: "dash", - 190: "period", - 191: "slash", - 192: "graveaccent", - 219: "openbracket", - 220: "backslash", - 221: "closebraket", - 222: "singlequote" - }, - - cleanArray: function(array, property) { - - var lastArgument = arguments[arguments.length - 1]; - var isLastArgumentFunction = typeof lastArgument === "function"; - - for (var i = 0, len = array.length; i < len; i++) { - if (array[i] === null || (property && array[i][property])) { - if (isLastArgumentFunction) { - lastArgument(array[i]); - } - array.splice(i--, 1); - len--; - } - } - }, - - specialBlendFunctions: ["color", "value", "hue", "saturation"], - - blendFunctions: { - normal: function(a, b) { - return b; - }, - - overlay: function(a, b) { - a /= 255; - b /= 255; - var result = 0; - - if (a < 0.5) result = 2 * a * b; - else result = 1 - 2 * (1 - a) * (1 - b); - - return Math.min(255, Math.max(0, result * 255 | 0)); - }, - - hardLight: function(a, b) { - return $.blendFunctions.overlay(b, a); - }, - - softLight: function(a, b) { - a /= 255; - b /= 255; - - var v = (1 - 2 * b) * (a * a) + 2 * b * a; - return $.limitValue(v * 255, 0, 255); - }, - - dodge: function(a, b) { - return Math.min(256 * a / (255 - b + 1), 255); - }, - - burn: function(a, b) { - return 255 - Math.min(256 * (255 - a) / (b + 1), 255); - }, - - multiply: function(a, b) { - return b * a / 255; - }, - - divide: function(a, b) { - return Math.min(256 * a / (b + 1), 255); - }, - - screen: function(a, b) { - return 255 - (255 - b) * (255 - a) / 255; - }, - - grainExtract: function(a, b) { - return $.limitValue(a - b + 128, 0, 255); - }, - - grainMerge: function(a, b) { - return $.limitValue(a + b - 128, 0, 255); - }, - - difference: function(a, b) { - return Math.abs(a - b); - }, - - addition: function(a, b) { - return Math.min(a + b, 255); - }, - - substract: function(a, b) { - return Math.max(a - b, 0); - }, - - darkenOnly: function(a, b) { - return Math.min(a, b); - }, - - lightenOnly: function(a, b) { - return Math.max(a, b); - }, - - color: function(a, b) { - var aHSL = $.rgbToHsl(a); - var bHSL = $.rgbToHsl(b); - - return $.hslToRgb(bHSL[0], bHSL[1], aHSL[2]); - }, - - hue: function(a, b) { - var aHSV = $.rgbToHsv(a); - var bHSV = $.rgbToHsv(b); - - if (!bHSV[1]) return $.hsvToRgb(aHSV[0], aHSV[1], aHSV[2]); - else return $.hsvToRgb(bHSV[0], aHSV[1], aHSV[2]); - }, - - value: function(a, b) { - var aHSV = $.rgbToHsv(a); - var bHSV = $.rgbToHsv(b); - - return $.hsvToRgb(aHSV[0], aHSV[1], bHSV[2]); - }, - - saturation: function(a, b) { - var aHSV = $.rgbToHsv(a); - var bHSV = $.rgbToHsv(b); - - return $.hsvToRgb(aHSV[0], bHSV[1], aHSV[2]); - } - }, - - blend: function(below, above, mode, mix) { - if (typeof mix === "undefined") mix = 1; - - var below = $(below); - var above = $(above); - - var belowCtx = below.context; - var aboveCtx = above.context; - - var belowData = belowCtx.getImageData(0, 0, below.canvas.width, below.canvas.height); - var aboveData = aboveCtx.getImageData(0, 0, above.canvas.width, above.canvas.height); - - var belowPixels = belowData.data; - var abovePixels = aboveData.data; - - var imageData = this.createImageData(below.canvas.width, below.canvas.height); - var pixels = imageData.data; - - var blendingFunction = $.blendFunctions[mode]; - - if ($.specialBlendFunctions.indexOf(mode) !== -1) { - for (var i = 0, len = belowPixels.length; i < len; i += 4) { - var rgb = blendingFunction([belowPixels[i + 0], belowPixels[i + 1], belowPixels[i + 2]], [abovePixels[i + 0], abovePixels[i + 1], abovePixels[i + 2]]); - - pixels[i + 0] = belowPixels[i + 0] + (rgb[0] - belowPixels[i + 0]) * mix; - pixels[i + 1] = belowPixels[i + 1] + (rgb[1] - belowPixels[i + 1]) * mix; - pixels[i + 2] = belowPixels[i + 2] + (rgb[2] - belowPixels[i + 2]) * mix; - - pixels[i + 3] = belowPixels[i + 3]; - } - } else { - - for (var i = 0, len = belowPixels.length; i < len; i += 4) { - var r = blendingFunction(belowPixels[i + 0], abovePixels[i + 0]); - var g = blendingFunction(belowPixels[i + 1], abovePixels[i + 1]); - var b = blendingFunction(belowPixels[i + 2], abovePixels[i + 2]); - - pixels[i + 0] = belowPixels[i + 0] + (r - belowPixels[i + 0]) * mix; - pixels[i + 1] = belowPixels[i + 1] + (g - belowPixels[i + 1]) * mix; - pixels[i + 2] = belowPixels[i + 2] + (b - belowPixels[i + 2]) * mix; - - pixels[i + 3] = belowPixels[i + 3]; - } - } - - below.context.putImageData(imageData, 0, 0); - - return below; - }, - - wrapValue: function(value, min, max) { - var d = Math.abs(max - min); - return min + (value - min) % d; - }, - - limitValue: function(value, min, max) { - return value < min ? min : value > max ? max : value; - }, - - mix: function(a, b, ammount) { - return a + (b - a) * ammount; - }, - - hexToRgb: function(hex) { - if (hex.length === 7) return ['0x' + hex[1] + hex[2] | 0, '0x' + hex[3] + hex[4] | 0, '0x' + hex[5] + hex[6] | 0]; - else return ['0x' + hex[1] | 0, '0x' + hex[2], '0x' + hex[3] | 0]; - }, - - rgbToHex: function(r, g, b) { - return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1, 7); - }, - - /* author: http://mjijackson.com/ */ - - rgbToHsl: function(r, g, b) { - - if (r instanceof Array) { - b = r[2]; - g = r[1]; - r = r[0]; - } - - r /= 255, g /= 255, b /= 255; - var max = Math.max(r, g, b), - min = Math.min(r, g, b); - var h, s, l = (max + min) / 2; - - if (max == min) { - h = s = 0; // achromatic - } else { - var d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - - return [h, s, l]; - }, - - /* author: http://mjijackson.com/ */ - - hslToRgb: function(h, s, l) { - var r, g, b; - - if (s == 0) { - r = g = b = l; // achromatic - } else { - function hue2rgb(p, q, t) { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6) return p + (q - p) * 6 * t; - if (t < 1 / 2) return q; - if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; - return p; - } - - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - - return [r * 255 | 0, g * 255 | 0, b * 255 | 0]; - }, - - rgbToHsv: function(r, g, b) { - if (r instanceof Array) { - b = r[2]; - g = r[1]; - r = r[0]; - } - - r = r / 255, g = g / 255, b = b / 255; - var max = Math.max(r, g, b), - min = Math.min(r, g, b); - var h, s, v = max; - - var d = max - min; - s = max == 0 ? 0 : d / max; - - if (max == min) { - h = 0; // achromatic - } else { - switch (max) { - case r: - h = (g - b) / d + (g < b ? 6 : 0); - break; - case g: - h = (b - r) / d + 2; - break; - case b: - h = (r - g) / d + 4; - break; - } - h /= 6; - } - - return [h, s, v]; - }, - - hsvToRgb: function(h, s, v) { - var r, g, b; - - var i = Math.floor(h * 6); - var f = h * 6 - i; - var p = v * (1 - s); - var q = v * (1 - f * s); - var t = v * (1 - (1 - f) * s); - - switch (i % 6) { - case 0: - r = v, g = t, b = p; - break; - case 1: - r = q, g = v, b = p; - break; - case 2: - r = p, g = v, b = t; - break; - case 3: - r = p, g = q, b = v; - break; - case 4: - r = t, g = p, b = v; - break; - case 5: - r = v, g = p, b = q; - break; - } - - return [r * 255 | 0, g * 255 | 0, b * 255 | 0]; - }, - - color: function() { - var result = new $.Color(); - result.parse(arguments[0], arguments[1]); - return result; - }, - - createCanvas: function(width, height) { - var result = document.createElement("canvas"); - - if (arguments[0] instanceof Image || arguments[0] instanceof HTMLImageElement) { - var image = arguments[0]; - result.width = image.width; - result.height = image.height; - result.getContext("2d").drawImage(image, 0, 0); - } else { - result.width = width; - result.height = height; - } - - return result; - }, - - createImageData: function(width, height) { - return document.createElement("Canvas").getContext("2d").createImageData(width, height); - }, - - - /* https://gist.github.com/3781251 */ - - mousePosition: function(event) { - var totalOffsetX = 0, - totalOffsetY = 0, - coordX = 0, - coordY = 0, - currentElement = event.target || event.srcElement, - mouseX = 0, - mouseY = 0; - - // Traversing the parents to get the total offset - do { - totalOffsetX += currentElement.offsetLeft; - totalOffsetY += currentElement.offsetTop; - } - while ((currentElement = currentElement.offsetParent)); - // Set the event to first touch if using touch-input - if (event.changedTouches && event.changedTouches[0] !== undefined) { - event = event.changedTouches[0]; - } - // Use pageX to get the mouse coordinates - if (event.pageX || event.pageY) { - mouseX = event.pageX; - mouseY = event.pageY; - } - // IE8 and below doesn't support event.pageX - else if (event.clientX || event.clientY) { - mouseX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; - mouseY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; - } - // Subtract the offset from the mouse coordinates - coordX = mouseX - totalOffsetX; - coordY = mouseY - totalOffsetY; - - return { - x: coordX, - y: coordY - }; - } - }); - - $.Wrapper = function(canvas) { - this.context = canvas.getContext("2d"); - this.canvas = canvas; - } - - $.Wrapper.prototype = { - appendTo: function(selector) { - if (typeof selector === "object") { - var element = selector; - } else { - var element = document.querySelector(selector); - } - - element.appendChild(this.canvas); - - return this; - }, - - blendOn: function(what, mode, mix) { - $.blend(what, this, mode, mix); - - return this; - }, - - blend: function(what, mode, mix) { - if (typeof what === "string") { - var color = what; - what = $($.createCanvas(this.canvas.width, this.canvas.height)); - what.fillStyle(color).fillRect(0, 0, this.canvas.width, this.canvas.height); - } - - $.blend(this, what, mode, mix); - - return this; - }, - - circle: function(x, y, r) { - this.context.arc(x, y, r, 0, Math.PI * 2); - return this; - }, - - crop: function(x, y, w, h) { - - var canvas = $.createCanvas(w, h); - var context = canvas.getContext("2d"); - - context.drawImage(this.canvas, x, y, w, h, 0, 0, w, h); - this.canvas.width = w; - this.canvas.height = h; - this.clear(); - this.context.drawImage(canvas, 0, 0); - - return this; - }, - - set: function(properties) { - $.extend(this.context, properties); - }, - - resize: function(width, height) { - var w = width, - h = height; - - if (arguments.length === 1) { - w = arguments[0] * this.canvas.width | 0; - h = arguments[0] * this.canvas.height | 0; - } else { - - if (height === null) { - if (this.canvas.width > width) { - h = this.canvas.height * (width / this.canvas.width) | 0; - w = width; - } else { - w = this.canvas.width; - h = this.canvas.height; - } - } else if (width === null) { - if (this.canvas.width > width) { - w = this.canvas.width * (height / this.canvas.height) | 0; - h = height; - } else { - w = this.canvas.width; - h = this.canvas.height; - } - } - } - - var $resized = $(w, h).drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, w, h); - this.canvas = $resized.canvas; - this.context = $resized.context; - - return this; - }, - - - trim: function(color, changes) { - var transparent; - - if (color) { - color = $.color(color).toArray(); - transparent = !color[3]; - } else transparent = true; - - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var bound = [this.canvas.width, this.canvas.height, 0, 0]; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - if (transparent) { - if (!sourcePixels[i + 3]) continue; - } else if (sourcePixels[i + 0] === color[0] && sourcePixels[i + 1] === color[1] && sourcePixels[i + 2] === color[2]) continue; - var x = (i / 4 | 0) % this.canvas.width | 0; - var y = (i / 4 | 0) / this.canvas.width | 0; - - if (x < bound[0]) bound[0] = x; - if (x > bound[2]) bound[2] = x; - - if (y < bound[1]) bound[1] = y; - if (y > bound[3]) bound[3] = y; - } - - if (bound[2] === 0 || bound[3] === 0) { - - } else { - if (changes) { - changes.left = bound[0]; - changes.top = bound[1]; - changes.width = bound[2] - bound[0]; - changes.height = bound[3] - bound[1]; - } - - this.crop(bound[0], bound[1], bound[2] - bound[0] + 1, bound[3] - bound[1] + 1); - } - - return this; - }, - - resizePixel: function(pixelSize) { - - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - var canvas = document.createElement("canvas"); - var context = canvas.context = canvas.getContext("2d"); - - canvas.width = this.canvas.width * pixelSize | 0; - canvas.height = this.canvas.height * pixelSize | 0; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - if (!sourcePixels[i + 3]) continue; - context.fillStyle = $.rgbToHex(sourcePixels[i + 0], sourcePixels[i + 1], sourcePixels[i + 2]); - - var x = (i / 4) % this.canvas.width; - var y = (i / 4) / this.canvas.width | 0; - - context.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize); - } - - this.canvas.width = canvas.width; - this.canvas.height = canvas.height; - this.clear().drawImage(canvas, 0, 0); - - return this; - - /* this very clever method is working only under Chrome */ - - var x = 0, - y = 0; - - var canvas = document.createElement("canvas"); - var context = canvas.context = canvas.getContext("2d"); - - canvas.width = this.canvas.width * pixelSize | 0; - canvas.height = this.canvas.height * pixelSize | 0; - - while (x < this.canvas.width) { - y = 0; - while (y < this.canvas.height) { - context.drawImage(this.canvas, x, y, 1, 1, x * pixelSize, y * pixelSize, pixelSize, pixelSize); - y++; - } - x++; - } - - this.canvas = canvas; - this.context = context; - - return this; - }, - - - matchPalette: function(palette) { - var imgData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - - var rgbPalette = []; - for (var i = 0; i < palette.length; i++) { - rgbPalette.push($.color(palette[i])); - } - - - for (var i = 0; i < imgData.data.length; i += 4) { - var difList = []; - for (var j = 0; j < rgbPalette.length; j++) { - var rgbVal = rgbPalette[j]; - var rDif = Math.abs(imgData.data[i] - rgbVal[0]), - gDif = Math.abs(imgData.data[i + 1] - rgbVal[1]), - bDif = Math.abs(imgData.data[i + 2] - rgbVal[2]); - difList.push(rDif + gDif + bDif); - } - - var closestMatch = 0; - for (var j = 0; j < palette.length; j++) { - if (difList[j] < difList[closestMatch]) { - closestMatch = j; - } - } - - var paletteRgb = cq.hexToRgb(palette[closestMatch]); - imgData.data[i] = paletteRgb[0]; - imgData.data[i + 1] = paletteRgb[1]; - imgData.data[i + 2] = paletteRgb[2]; - } - - this.context.putImageData(imgData, 0, 0); - - return this; - }, - - getPalette: function() { - var palette = []; - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - if (sourcePixels[i + 3]) { - var hex = $.rgbToHex(sourcePixels[i + 0], sourcePixels[i + 1], sourcePixels[i + 2]); - if (palette.indexOf(hex) === -1) palette.push(hex); - } - } - - return palette; - }, - - pixelize: function(size) { - if (!size) return this; - size = size || 4; - - var mozImageSmoothingEnabled = this.context.mozImageSmoothingEnabled; - var webkitImageSmoothingEnabled = this.context.webkitImageSmoothingEnabled; - - this.context.mozImageSmoothingEnabled = false; - this.context.webkitImageSmoothingEnabled = false; - - var scale = (this.canvas.width / size) / this.canvas.width; - - var temp = cq(this.canvas.width, this.canvas.height); - - temp.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, this.canvas.width * scale | 0, this.canvas.height * scale | 0); - this.clear().drawImage(temp.canvas, 0, 0, this.canvas.width * scale | 0, this.canvas.height * scale | 0, 0, 0, this.canvas.width, this.canvas.height); - - this.context.mozImageSmoothingEnabled = mozImageSmoothingEnabled; - this.context.webkitImageSmoothingEnabled = webkitImageSmoothingEnabled; - - return this; - }, - - colorToMask: function(color, inverted) { - color = $.color(color).toArray(); - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var mask = []; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - if (sourcePixels[i + 0] == color[0] && sourcePixels[i + 1] == color[1] && sourcePixels[i + 2] == color[2]) mask.push(inverted || false); - else mask.push(!inverted); - } - - return mask; - }, - - grayscaleToMask: function(color) { - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var mask = []; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - mask.push((sourcePixels[i + 0] + sourcePixels[i + 1] + sourcePixels[i + 2]) / 3 | 0); - } - - return mask; - }, - - grayscaleToAlpha: function() { - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var mask = []; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - sourcePixels[i + 3] = (sourcePixels[i + 0] + sourcePixels[i + 1] + sourcePixels[i + 2]) / 3 | 0; - - sourcePixels[i + 0] = sourcePixels[i + 1] = sourcePixels[i + 2] = 255; - } - - this.context.putImageData(sourceData, 0, 0); - - return this; - }, - - applyMask: function(mask) { - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var mode = typeof mask[0] === "boolean" ? "bool" : "byte"; - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - var value = mask[i / 4]; - - if (mode === "bool") sourcePixels[i + 3] = 255 * value | 0; - else { - sourcePixels[i + 3] = value | 0; - } - } - - - this.context.putImageData(sourceData, 0, 0); - return this; - }, - - fillMask: function(mask) { - - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var sourcePixels = sourceData.data; - - var maskType = typeof mask[0] === "boolean" ? "bool" : "byte"; - var colorMode = arguments.length === 2 ? "normal" : "gradient"; - - var color = $.color(arguments[1]); - if (colorMode === "gradient") colorB = $.color(arguments[2]); - - for (var i = 0, len = sourcePixels.length; i < len; i += 4) { - var value = mask[i / 4]; - - if (maskType === "byte") value /= 255; - - if (colorMode === "normal") { - if (value) { - sourcePixels[i + 0] = color[0] | 0; - sourcePixels[i + 1] = color[1] | 0; - sourcePixels[i + 2] = color[2] | 0; - sourcePixels[i + 3] = value * 255 | 0; - } - } else { - sourcePixels[i + 0] = color[0] + (colorB[0] - color[0]) * value | 0; - sourcePixels[i + 1] = color[1] + (colorB[1] - color[1]) * value | 0; - sourcePixels[i + 2] = color[2] + (colorB[2] - color[2]) * value | 0; - sourcePixels[i + 3] = 255; - } - } - - this.context.putImageData(sourceData, 0, 0); - return this; - }, - - clear: function(color) { - if (color) { - this.context.fillStyle = color; - this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); - } else { - this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); - } - - return this; - }, - - clone: function() { - var result = $.createCanvas(this.canvas.width, this.canvas.height); - result.getContext("2d").drawImage(this.canvas, 0, 0); - return $(result); - }, - - fillStyle: function(fillStyle) { - this.context.fillStyle = fillStyle; - return this; - }, - - strokeStyle: function(strokeStyle) { - this.context.strokeStyle = strokeStyle; - return this; - }, - - gradientText: function(text, x, y, maxWidth, gradient) { - - var words = text.split(" "); - - var h = this.font().match(/\d+/g)[0] * 2; - - var ox = 0; - var oy = 0; - - if (maxWidth) { - var line = 0; - var lines = [""]; - - for (var i = 0; i < words.length; i++) { - var word = words[i] + " "; - var wordWidth = this.context.measureText(word).width; - - if (ox + wordWidth > maxWidth) { - lines[++line] = ""; - ox = 0; - } - - lines[line] += word; - - ox += wordWidth; - } - } else var lines = [text]; - - for (var i = 0; i < lines.length; i++) { - var oy = y + i * h * 0.6 | 0; - var lingrad = this.context.createLinearGradient(0, oy, 0, oy + h * 0.6 | 0); - - for (var j = 0; j < gradient.length; j += 2) { - lingrad.addColorStop(gradient[j], gradient[j + 1]); - } - - var text = lines[i]; - - this.fillStyle(lingrad).fillText(text, x, oy); - } - - return this; - }, - - setHsl: function() { - - if (arguments.length === 1) { - var args = arguments[0]; - } else { - var args = arguments; - } - - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b, a, h, s, l, hsl = [], - newPixel = []; - - for (var i = 0, len = pixels.length; i < len; i += 4) { - hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); - - h = args[0] === null ? hsl[0] : $.limitValue(args[0], 0, 1); - s = args[1] === null ? hsl[1] : $.limitValue(args[1], 0, 1); - l = args[2] === null ? hsl[2] : $.limitValue(args[2], 0, 1); - - newPixel = $.hslToRgb(h, s, l); - - pixels[i + 0] = newPixel[0]; - pixels[i + 1] = newPixel[1]; - pixels[i + 2] = newPixel[2]; - } - - this.context.putImageData(data, 0, 0); - - return this; - }, - - shiftHsl: function() { - - if (arguments.length === 1) { - var args = arguments[0]; - } else { - var args = arguments; - } - - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b, a, h, s, l, hsl = [], - newPixel = []; - - for (var i = 0, len = pixels.length; i < len; i += 4) { - hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); - - h = args[0] === null ? hsl[0] : $.wrapValue(hsl[0] + args[0], 0, 1); - s = args[1] === null ? hsl[1] : $.limitValue(hsl[1] + args[1], 0, 1); - l = args[2] === null ? hsl[2] : $.limitValue(hsl[2] + args[2], 0, 1); - - newPixel = $.hslToRgb(h, s, l); - - pixels[i + 0] = newPixel[0]; - pixels[i + 1] = newPixel[1]; - pixels[i + 2] = newPixel[2]; - } - - - this.context.putImageData(data, 0, 0); - - return this; - }, - - replaceHue: function(src, dst) { - - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b, a, h, s, l, hsl = [], - newPixel = []; - - for (var i = 0, len = pixels.length; i < len; i += 4) { - hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); - - if (Math.abs(hsl[0] - src) < 0.05) h = $.wrapValue(dst, 0, 1); - else h = hsl[0]; - - newPixel = $.hslToRgb(h, hsl[1], hsl[2]); - - pixels[i + 0] = newPixel[0]; - pixels[i + 1] = newPixel[1]; - pixels[i + 2] = newPixel[2]; - } - - this.context.putImageData(data, 0, 0); - - return this; - }, - - invert: function(src, dst) { - - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b, a, h, s, l, hsl = [], - newPixel = []; - - for (var i = 0, len = pixels.length; i < len; i += 4) { - pixels[i + 0] = 255 - pixels[i + 0]; - pixels[i + 1] = 255 - pixels[i + 1]; - pixels[i + 2] = 255 - pixels[i + 2]; - } - - this.context.putImageData(data, 0, 0); - - return this; - }, - - roundRect: function(x, y, width, height, radius) { - - this.beginPath(); - this.moveTo(x + radius, y); - this.lineTo(x + width - radius, y); - this.quadraticCurveTo(x + width, y, x + width, y + radius); - this.lineTo(x + width, y + height - radius); - this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); - this.lineTo(x + radius, y + height); - this.quadraticCurveTo(x, y + height, x, y + height - radius); - this.lineTo(x, y + radius); - this.quadraticCurveTo(x, y, x + radius, y); - this.closePath(); - - return this; - }, - - wrappedText: function(text, x, y, maxWidth, newlineCallback) { - - var lines = text instanceof Array ? text : this.flowText(text, maxWidth); - var h = this.font().match(/\d+/g)[0] * 2; - - var ox = 0; - var oy = 0; - - if (maxWidth) { - var line = 0; - var lines = [""]; - - for (var i = 0; i < words.length; i++) { - var word = words[i] + " "; - var wordWidth = this.context.measureText(word).width; - - if (ox + wordWidth > maxWidth) { - lines[++line] = ""; - ox = 0; - } - - lines[line] += word; - - ox += wordWidth; - } - } else { - var lines = [text]; - } - - for (var i = 0; i < lines.length; i++) { - var oy = y + i * h * 0.6 | 0; - - var text = lines[i]; - - if (newlineCallback) newlineCallback.call(this, x, y + oy); - - this.fillText(text, x, oy); - } - - return this; - - }, - - flowText: function(text, maxWidth) { - var words = text.split(/(\s)/); - - var ox = 0; - var oy = 0; - - if (maxWidth) { - var line = 0; - var lines = [""]; - - var spaceWidth = this.context.measureText(" ").width; - - for(var i = 0; i < words.length; i++) { - - var word = words[i]; - - if (word == "\n") { - lines[line] = lines[line].replace(/\s+$/,""); - lines[++line] = ""; - ox = 0; - continue; - } - - else if (word == " ") { - ox += spaceWidth; - if (ox > maxWidth) { - lines[line] = lines[line].replace(/\s+$/,""); - lines[++line] = ""; - ox = 0; - } - else { - lines[line] += " "; - } - } - - else { - var wordWidth = this.context.measureText(word).width; - - ox += wordWidth; - - if(ox > maxWidth && lines[line].length) { - lines[line] = lines[line].replace(/\s+$/,""); - lines[++line] = ""; - ox = wordWidth; - } - - lines[line] += word; - } - } - } else { - var lines = [text]; - } - - return lines; - - }, - - textBoundaries: function(text, maxWidth) { - - var lines = this.flowText(text, maxWidth || Infinity); - - var h = this.font().match(/\d+/g)[0] * 2; - - var w = 0; - for (var i = 0; i < lines.length; i++) { - w = Math.max( w, this.measureText(lines[i]).width ); - } - - return { - height: lines.length * h * 0.6 | 0, - width: w, - lines: lines - } - }, - - paperBag: function(x, y, width, height, blowX, blowY) { - var lx, ly; - this.beginPath(); - this.moveTo(x, y); - this.quadraticCurveTo(x + width / 2 | 0, y + height * blowY | 0, x + width, y); - this.quadraticCurveTo(x + width - width * blowX | 0, y + height / 2 | 0, x + width, y + height); - this.quadraticCurveTo(x + width / 2 | 0, y + height - height * blowY | 0, x, y + height); - this.quadraticCurveTo(x + width * blowX | 0, y + height / 2 | 0, x, y); - }, - - borderImage: function(image, x, y, w, h, t, r, b, l, fill) { - - /* top */ - this.drawImage(image, l, 0, image.width - l - r, t, x + l, y, w - l - r, t); - - /* bottom */ - this.drawImage(image, l, image.height - b, image.width - l - r, b, x + l, y + h - b, w - l - r, b); - - /* left */ - this.drawImage(image, 0, t, l, image.height - b - t, x, y + t, l, h - b - t); - - /* right */ - this.drawImage(image, image.width - r, t, r, image.height - b - t, x + w - r, y + t, r, h - b - t); - - /* top-left */ - this.drawImage(image, 0, 0, l, t, x, y, l, t); - - /* top-right */ - this.drawImage(image, image.width - r, 0, r, t, x + w - r, y, r, t); - - /* bottom-right */ - this.drawImage(image, image.width - r, image.height - b, r, b, x + w - r, y + h - b, r, b); - - /* bottom-left */ - this.drawImage(image, 0, image.height - b, l, b, x, y + h - b, l, b); - - if (fill) { - if (typeof fill === "string") { - this.fillStyle(fill).fillRect(x + l, y + t, w - l - r, h - t - b); - } else { - this.drawImage(image, l, t, image.width - r - l, image.height - b - t, x + l, y + t, w - l - r, h - t - b); - } - } - }, - - /* www.html5rocks.com/en/tutorials/canvas/imagefilters/ */ - - convolve: function(matrix, mix, divide) { - - if (typeof divide === "undefined") divide = 1; - if (typeof mix === "undefined") mix = 1; - - var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var matrixSize = Math.sqrt(matrix.length) + 0.5 | 0; - var halfMatrixSize = matrixSize / 2 | 0; - var src = sourceData.data; - var sw = sourceData.width; - var sh = sourceData.height; - var w = sw; - var h = sh; - var output = $.createImageData(this.canvas.width, this.canvas.height); - var dst = output.data; - - for (var y = 1; y < h - 1; y++) { - for (var x = 1; x < w - 1; x++) { - - var dstOff = (y * w + x) * 4; - var r = 0, - g = 0, - b = 0, - a = 0; - - for (var cy = 0; cy < matrixSize; cy++) { - for (var cx = 0; cx < matrixSize; cx++) { - var scy = y + cy - halfMatrixSize; - var scx = x + cx - halfMatrixSize; - if (scy >= 0 && scy < sh && scx >= 0 && scx < sw) { - var srcOff = (scy * sw + scx) * 4; - - var wt = matrix[cy * matrixSize + cx] / divide; - - r += src[srcOff + 0] * wt; - g += src[srcOff + 1] * wt; - b += src[srcOff + 2] * wt; - a += src[srcOff + 3] * wt; - } - } - } - - dst[dstOff + 0] = $.mix(src[dstOff + 0], r, mix); - dst[dstOff + 1] = $.mix(src[dstOff + 1], g, mix); - dst[dstOff + 2] = $.mix(src[dstOff + 2], b, mix); - dst[dstOff + 3] = a; - // src[dstOff + 3]; - } - } - }, - - blur: function(mix) { - return this.convolve([1, 1, 1, 1, 1, 1, 1, 1, 1], mix, 9); - }, - - gaussianBlur: function(mix) { - return this.convolve([0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067, 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292, 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117, 0.00038771, 0.01330373, 0.11098164, 0.22508352, 0.11098164, 0.01330373, 0.00038771, 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117, 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292, 0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067], mix, 1); - }, - - sharpen: function(mix) { - return this.convolve([0, -1, 0, -1, 5, -1, 0, -1, 0], mix); - }, - - threshold: function(threshold) { - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b; - - for (var i = 0; i < pixels.length; i += 4) { - var r = pixels[i]; - var g = pixels[i + 1]; - var b = pixels[i + 2]; - var v = (0.2126 * r + 0.7152 * g + 0.0722 * b >= threshold) ? 255 : 0; - pixels[i] = pixels[i + 1] = pixels[i + 2] = v - } - - this.context.putImageData(data, 0, 0); - - return this; - }, - - sepia: function() { - var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); - var pixels = data.data; - var r, g, b; - - for (var i = 0; i < pixels.length; i += 4) { - pixels[i + 0] = $.limitValue((pixels[i + 0] * .393) + (pixels[i + 1] * .769) + (pixels[i + 2] * .189), 0, 255); - pixels[i + 1] = $.limitValue((pixels[i + 0] * .349) + (pixels[i + 1] * .686) + (pixels[i + 2] * .168), 0, 255); - pixels[i + 2] = $.limitValue((pixels[i + 0] * .272) + (pixels[i + 1] * .534) + (pixels[i + 2] * .131), 0, 255); - } - - this.context.putImageData(data, 0, 0); - - return this; - }, - - measureText: function() { - return this.context.measureText.apply(this.context, arguments); - }, - - createRadialGradient: function() { - return this.context.createRadialGradient.apply(this.context, arguments); - }, - - createLinearGradient: function() { - return this.context.createLinearGradient.apply(this.context, arguments); - }, - - getImageData: function() { - return this.context.getImageData.apply(this.context, arguments); - }, - - /* framework */ - - framework: function(args, context) { - if (context) { - this.tempContext = context === true ? args : context; - } - - for (var name in args) { - if (this[name]) this[name](args[name], undefined, undefined); - } - - this.tempContext = null; - - return this; - }, - - onStep: function(callback, interval) { - var self = this.tempContext || this; - var lastTick = Date.now(); - interval = interval || 25; - - this.timer = setInterval(function() { - var delta = Date.now() - lastTick; - lastTick = Date.now(); - callback.call(self, delta, lastTick); - }, interval); - - return this; - }, - - onRender: function(callback) { - var self = this.tempContext || this; - - var lastTick = Date.now(); - - function step() { - var delta = Date.now() - lastTick; - lastTick = Date.now(); - requestAnimationFrame(step) - callback.call(self, delta, lastTick); - }; - - requestAnimationFrame(step); - - return this; - }, - - onMouseMove: function(callback) { - var self = this.tempContext || this; - - if (!MOBILE) this.canvas.addEventListener("mousemove", function(e) { - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y); - }); - - else this.canvas.addEventListener("touchmove", function(e) { - e.preventDefault(); - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y); - }); - - return this; - }, - - onMouseDown: function(callback) { - var self = this.tempContext || this; - - if (!MOBILE) { - this.canvas.addEventListener("mousedown", function(e) { - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y, e.button); - }); - } else { - this.canvas.addEventListener("touchstart", function(e) { - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y, e.button); - }); - } - - return this; - }, - - onMouseUp: function(callback) { - var self = this.tempContext || this; - - if (!MOBILE) { - this.canvas.addEventListener("mouseup", function(e) { - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y, e.button); - }); - } else { - this.canvas.addEventListener("touchend", function(e) { - var pos = $.mousePosition(e); - callback.call(self, pos.x, pos.y, e.button); - }); - } - - return this; - }, - - - onSwipe: function(callback, threshold, timeout) { - var self = this.tempContext || this; - - var swipeThr = threshold || 35; - var swipeTim = timeout || 350; - - var swipeSP = 0; - var swipeST = 0; - var swipeEP = 0; - var swipeET = 0; - - function swipeStart(e) { - e.preventDefault(); - swipeSP = $.mousePosition(e); - swipeST = Date.now(); - } - - function swipeUpdate(e) { - e.preventDefault(); - swipeEP = $.mousePosition(e); - swipeET = Date.now(); - } - - function swipeEnd(e) { - e.preventDefault(); - - var xDif = (swipeSP.x - swipeEP.x); - var yDif = (swipeSP.y - swipeEP.y); - var x = (xDif * xDif); - var y = (yDif * yDif); - var swipeDist = Math.sqrt(x + y); - var swipeTime = (swipeET - swipeST); - var swipeDir = undefined; - - if (swipeDist > swipeThr && swipeTime < swipeTim) { - if (Math.abs(xDif) > Math.abs(yDif)) { - if (xDif > 0) { - swipeDir = "left"; - } else { - swipeDir = "right"; - } - } else { - if (yDif > 0) { - swipeDir = "up"; - } else { - swipeDir = "down"; - } - } - callback.call(self, swipeDir); - } - } - - this.canvas.addEventListener("touchstart", function(e) { - swipeStart(e); - }); - this.canvas.addEventListener("touchmove", function(e) { - swipeUpdate(e); - }); - this.canvas.addEventListener("touchend", function(e) { - swipeEnd(e); - }); - this.canvas.addEventListener("mousedown", function(e) { - swipeStart(e); - }); - this.canvas.addEventListener("mousemove", function(e) { - swipeUpdate(e); - }); - this.canvas.addEventListener("mouseup", function(e) { - swipeEnd(e); - }); - - return this; - }, - - onKeyDown: function(callback) { - var self = this.tempContext || this; - - document.addEventListener("keydown", function(e) { - if (e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); - else var keyName = $.keycodes[e.which]; - callback.call(self, keyName); - }); - return this; - }, - - onKeyUp: function(callback) { - var self = this.tempContext || this; - - document.addEventListener("keyup", function(e) { - if (e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); - else var keyName = $.keycodes[e.which]; - callback.call(self, keyName); - }); - return this; - }, - - - onResize: function(callback) { - var self = this.tempContext || this; - - window.addEventListener("resize", function() { - callback.call(self, window.innerWidth, window.innerHeight); - }); - - callback.call(self, window.innerWidth, window.innerHeight); - - return this; - }, - - onDropImage: function(callback) { - var self = this.tempContext || this; - - document.addEventListener('drop', function(e) { - e.stopPropagation(); - e.preventDefault(); - - var file = e.dataTransfer.files[0]; - - if (!(/image/i).test(file.type)) return false; - var reader = new FileReader(); - - reader.onload = function(e) { - var image = new Image; - - image.onload = function() { - callback.call(self, this); - }; - - image.src = e.target.result; - }; - - reader.readAsDataURL(file); - - }); - - document.addEventListener("dragover", function(e) { - e.preventDefault(); - }); - - return this; - } - - }; - - /* extend wrapper with drawing context methods */ - - var methods = ["arc", "arcTo", "beginPath", "bezierCurveTo", "clearRect", "clip", "closePath", "createImageData", "createLinearGradient", "createRadialGradient", "createPattern", "drawFocusRing", "drawImage", "fill", "fillRect", "fillText", "getImageData", "isPointInPath", "lineTo", "measureText", "moveTo", "putImageData", "quadraticCurveTo", "rect", "restore", "rotate", "save", "scale", "setTransform", "stroke", "strokeRect", "strokeText", "transform", "translate"]; - for (var i = 0; i < methods.length; i++) { - var name = methods[i]; - if (!$.Wrapper.prototype[name]) $.Wrapper.prototype[name] = Function("this.context." + name + ".apply(this.context, arguments); return this;"); - }; - - /* create setters and getters */ - - var properties = ["canvas", "fillStyle", "font", "globalAlpha", "globalCompositeOperation", "lineCap", "lineJoin", "lineWidth", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "strokeStyle", "textAlign", "textBaseline"]; - for (var i = 0; i < properties.length; i++) { - var name = properties[i]; - if (!$.Wrapper.prototype[name]) $.Wrapper.prototype[name] = Function("if(arguments.length) { this.context." + name + " = arguments[0]; return this; } else { return this.context." + name + "; }"); - }; - - /* color */ - - $.Color = function(data, type) { - if (arguments.length) this.parse(data); - } - - $.Color.prototype = { - parse: function(args, type) { - if (args[0] instanceof $.Color) { - this[0] = args[0][0]; - this[1] = args[0][1]; - this[2] = args[0][2]; - this[3] = args[0][3]; - return; - } - - if (typeof args === "string") { - var match = null; - - if (args[0] === "#") { - var rgb = $.hexToRgb(args); - this[0] = rgb[0]; - this[1] = rgb[1]; - this[2] = rgb[2]; - this[3] = 1.0; - } else if (match = args.match(/rgb\((.*),(.*),(.*)\)/)) { - this[0] = match[1] | 0; - this[1] = match[2] | 0; - this[2] = match[3] | 0; - this[3] = 1.0; - } else if (match = args.match(/rgba\((.*),(.*),(.*)\)/)) { - this[0] = match[1] | 0; - this[1] = match[2] | 0; - this[2] = match[3] | 0; - this[3] = match[4] | 0; - } else if (match = args.match(/hsl\((.*),(.*),(.*)\)/)) { - this.fromHsl(match[1], match[2], match[3]); - } else if (match = args.match(/hsv\((.*),(.*),(.*)\)/)) { - this.fromHsv(match[1], match[2], match[3]); - } - } else { - switch (type) { - case "hsl": - case "hsla": - - this.fromHsl(args[0], args[1], args[2], args[3]); - break; - - case "hsv": - case "hsva": - - this.fromHsv(args[0], args[1], args[2], args[3]); - break; - - default: - this[0] = args[0]; - this[1] = args[1]; - this[2] = args[2]; - this[3] = typeof args[3] === "undefined" ? 1.0 : args[3]; - break; - } - } - }, - - fromHsl: function() { - var components = arguments[0] instanceof Array ? arguments[0] : arguments; - var color = $.hslToRgb(components[0], components[1], components[2]); - - this[0] = color[0]; - this[1] = color[1]; - this[2] = color[2]; - this[3] = typeof arguments[3] === "undefined" ? 1.0 : arguments[3]; - }, - - fromHsv: function() { - var components = arguments[0] instanceof Array ? arguments[0] : arguments; - var color = $.hsvToRgb(components[0], components[1], components[2]); - - this[0] = color[0]; - this[1] = color[1]; - this[2] = color[2]; - this[3] = typeof arguments[3] === "undefined" ? 1.0 : arguments[3]; - }, - - toArray: function() { - return [this[0], this[1], this[2], this[3]]; - }, - - toRgb: function() { - return "rgb(" + this[0] + ", " + this[1] + ", " + this[2] + ")"; - }, - - toRgba: function() { - return "rgba(" + this[0] + ", " + this[1] + ", " + this[2] + ", " + this[3] + ")"; - }, - - toHex: function() { - return $.rgbToHex(this[0], this[1], this[2]); - }, - - toHsl: function() { - var c = $.rgbToHsl(this[0], this[1], this[2]); - c[3] = this[3]; - return c; - }, - - toHsv: function() { - var c = $.rgbToHsv(this[0], this[1], this[2]); - c[3] = this[3]; - return c; - }, - - gradient: function(target, steps) { - var targetColor = $.color(target); - }, - - shiftHsl: function() { - var hsl = this.toHsl(); - - var h = arguments[0] === null ? hsl[0] : $.wrapValue(hsl[0] + arguments[0], 0, 1); - var s = arguments[1] === null ? hsl[1] : $.limitValue(hsl[1] + arguments[1], 0, 1); - var l = arguments[2] === null ? hsl[2] : $.limitValue(hsl[2] + arguments[2], 0, 1); - - this.fromHsl(h, s, l); - - return this; - }, - - setHsl: function() { - var hsl = this.toHsl(); - - var h = arguments[0] === null ? hsl[0] : $.limitValue(arguments[0], 0, 1); - var s = arguments[1] === null ? hsl[1] : $.limitValue(arguments[1], 0, 1); - var l = arguments[2] === null ? hsl[2] : $.limitValue(arguments[2], 0, 1); - - this.fromHsl(h, s, l); - - return this; - } - - }; - - window["cq"] = window["CanvasQuery"] = $; - - if (typeof define === "function" && define.amd) { - define([], function() { - return $; - }); - } - -})(window); diff --git a/dataUriToBlob.js b/dataUriToBlob.js deleted file mode 100644 index 582aecb..0000000 --- a/dataUriToBlob.js +++ /dev/null @@ -1,47 +0,0 @@ -window.dataUriToBlob = (function(){ -/** - * Blob constructor. - */ - -var Blob = window.Blob; - -/** - * ArrayBufferView support. - */ - -var hasArrayBufferView = new Blob([new Uint8Array(100)]).size == 100; - -/** - * Return a `Blob` for the given data `uri`. - * - * @param {String} uri - * @return {Blob} - * @api public - */ - -var dataUriToBlob = function(uri){ - var data = uri.split(',')[1]; - var bytes = atob(data); - var buf = new ArrayBuffer(bytes.length); - var arr = new Uint8Array(buf); - for (var i = 0; i < bytes.length; i++) { - arr[i] = bytes.charCodeAt(i); - } - - if (!hasArrayBufferView) arr = buf; - var blob = new Blob([arr], { type: mime(uri) }); - blob.slice = blob.slice || blob.webkitSlice; - return blob; -}; - -/** - * Return data uri mime type. - */ - -function mime(uri) { - return uri.split(';')[0].slice(5); -} - -return dataUriToBlob; - -})() diff --git a/gif-animate.html b/gif-animate.html index 6681aff..55396cd 100644 --- a/gif-animate.html +++ b/gif-animate.html @@ -19,9 +19,9 @@
- - - + + + - - - - - - - + + + + + + + + - - - - - - + + + + + + + - + + - + + - + + - - + + + + - - + + + - + +