// Generated by CoffeeScript 1.12.7
(function() {
var $, Analyze, Blender, Calculate, Caman, CamanParser, Canvas, Convert, Event, Fiber, Filter, IO, Image, Layer, Log, Module, Pixel, Plugin, Renderer, Root, Store, Util, fs, http, moduleKeywords, slice,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
slice1 = [].slice,
hasProp = {}.hasOwnProperty,
bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
moduleKeywords = ['extended', 'included'];
Module = (function() {
function Module() {}
Module["extends"] = function(obj) {
var key, ref, value;
for (key in obj) {
value = obj[key];
if (indexOf.call(moduleKeywords, key) < 0) {
this[key] = value;
}
}
if ((ref = obj.extended) != null) {
ref.apply(this);
}
return this;
};
Module.includes = function(obj) {
var key, ref, value;
for (key in obj) {
value = obj[key];
if (indexOf.call(moduleKeywords, key) < 0) {
this.prototype[key] = value;
}
}
if ((ref = obj.included) != null) {
ref.apply(this);
}
return this;
};
Module.delegate = function() {
var args, len, o, results, source, target;
args = 1 <= arguments.length ? slice1.call(arguments, 0) : [];
target = args.pop();
results = [];
for (o = 0, len = args.length; o < len; o++) {
source = args[o];
results.push(this.prototype[source] = target.prototype[source]);
}
return results;
};
Module.aliasFunction = function(to, from) {
return this.prototype[to] = (function(_this) {
return function() {
var args;
args = 1 <= arguments.length ? slice1.call(arguments, 0) : [];
return _this.prototype[from].apply(_this, args);
};
})(this);
};
Module.aliasProperty = function(to, from) {
return Object.defineProperty(this.prototype, to, {
get: function() {
return this[from];
},
set: function(val) {
return this[from] = val;
}
});
};
Module.included = function(func) {
return func.call(this, this.prototype);
};
return Module;
})();
slice = Array.prototype.slice;
$ = function(sel, root) {
if (root == null) {
root = document;
}
if (typeof sel === "object" || (typeof exports !== "undefined" && exports !== null)) {
return sel;
}
return root.querySelector(sel);
};
Util = (function() {
function Util() {}
Util.uniqid = (function() {
var id;
id = 0;
return {
get: function() {
return id++;
}
};
})();
Util.extend = function() {
var copy, dest, len, o, obj, prop, src;
obj = arguments[0], src = 2 <= arguments.length ? slice1.call(arguments, 1) : [];
dest = obj;
for (o = 0, len = src.length; o < len; o++) {
copy = src[o];
for (prop in copy) {
if (!hasProp.call(copy, prop)) continue;
dest[prop] = copy[prop];
}
}
return dest;
};
Util.clampRGB = function(val) {
if (val < 0) {
return 0;
}
if (val > 255) {
return 255;
}
return val;
};
Util.copyAttributes = function(from, to, opts) {
var attr, len, o, ref, ref1, results;
if (opts == null) {
opts = {};
}
ref = from.attributes;
results = [];
for (o = 0, len = ref.length; o < len; o++) {
attr = ref[o];
if ((opts.except != null) && (ref1 = attr.nodeName, indexOf.call(opts.except, ref1) >= 0)) {
continue;
}
results.push(to.setAttribute(attr.nodeName, attr.nodeValue));
}
return results;
};
Util.dataArray = function(length) {
if (length == null) {
length = 0;
}
if (Caman.NodeJS || (window.Uint8Array != null)) {
return new Uint8Array(length);
}
return new Array(length);
};
return Util;
})();
if (typeof exports !== "undefined" && exports !== null) {
Root = exports;
Canvas = require('canvas');
Image = Canvas.Image;
Fiber = require('fibers');
fs = require('fs');
http = require('http');
} else {
Root = window;
}
Caman = (function(superClass) {
extend(Caman, superClass);
Caman.version = {
release: "4.1.2",
date: "7/27/2013"
};
Caman.DEBUG = false;
Caman.allowRevert = true;
Caman.crossOrigin = "anonymous";
Caman.remoteProxy = "";
Caman.proxyParam = "camanProxyUrl";
Caman.NodeJS = typeof exports !== "undefined" && exports !== null;
Caman.autoload = !Caman.NodeJS;
Caman.toString = function() {
return "Version " + Caman.version.release + ", Released " + Caman.version.date;
};
Caman.getAttrId = function(canvas) {
if (Caman.NodeJS) {
return true;
}
if (typeof canvas === "string") {
canvas = $(canvas);
}
if (!((canvas != null) && (canvas.getAttribute != null))) {
return null;
}
return canvas.getAttribute('data-caman-id');
};
function Caman() {
this.nodeFileReady = bind(this.nodeFileReady, this);
var args, callback, id;
if (arguments.length === 0) {
throw "Invalid arguments";
}
if (this instanceof Caman) {
this.finishInit = this.finishInit.bind(this);
this.imageLoaded = this.imageLoaded.bind(this);
args = arguments[0];
if (!Caman.NodeJS) {
id = parseInt(Caman.getAttrId(args[0]), 10);
callback = typeof args[1] === "function" ? args[1] : typeof args[2] === "function" ? args[2] : function() {};
if (!isNaN(id) && Store.has(id)) {
return Store.execute(id, callback);
}
}
this.id = Util.uniqid.get();
this.initializedPixelData = this.originalPixelData = null;
this.cropCoordinates = {
x: 0,
y: 0
};
this.cropped = false;
this.resized = false;
this.rotated = false;
this.rotationAngle = 0;
this.pixelStack = [];
this.layerStack = [];
this.canvasQueue = [];
this.currentLayer = null;
this.scaled = false;
this.analyze = new Analyze(this);
this.renderer = new Renderer(this);
this.domIsLoaded((function(_this) {
return function() {
_this.parseArguments(args);
return _this.setup();
};
})(this));
return this;
} else {
return new Caman(arguments);
}
}
Caman.prototype.domIsLoaded = function(cb) {
var listener;
if (Caman.NodeJS) {
return setTimeout((function(_this) {
return function() {
return cb.call(_this);
};
})(this), 0);
} else {
if (document.readyState === "complete") {
Log.debug("DOM initialized");
return setTimeout((function(_this) {
return function() {
return cb.call(_this);
};
})(this), 0);
} else {
listener = (function(_this) {
return function() {
if (document.readyState === "complete") {
Log.debug("DOM initialized");
return cb.call(_this);
}
};
})(this);
return document.addEventListener("readystatechange", listener, false);
}
}
};
Caman.prototype.parseArguments = function(args) {
var key, ref, results, val;
if (args.length === 0) {
throw "Invalid arguments given";
}
this.initObj = null;
this.initType = null;
this.imageUrl = null;
this.callback = function() {};
this.setInitObject(args[0]);
if (args.length === 1) {
return;
}
switch (typeof args[1]) {
case "string":
this.imageUrl = args[1];
break;
case "function":
this.callback = args[1];
}
if (args.length === 2) {
return;
}
this.callback = args[2];
if (args.length === 4) {
ref = args[4];
results = [];
for (key in ref) {
if (!hasProp.call(ref, key)) continue;
val = ref[key];
results.push(this.options[key] = val);
}
return results;
}
};
Caman.prototype.setInitObject = function(obj) {
if (Caman.NodeJS) {
this.initObj = obj;
this.initType = 'node';
return;
}
if (typeof obj === "object") {
this.initObj = obj;
} else {
this.initObj = $(obj);
}
if (this.initObj == null) {
throw "Could not find image or canvas for initialization.";
}
return this.initType = this.initObj.nodeName.toLowerCase();
};
Caman.prototype.setup = function() {
switch (this.initType) {
case "node":
return this.initNode();
case "img":
return this.initImage();
case "canvas":
return this.initCanvas();
}
};
Caman.prototype.initNode = function() {
Log.debug("Initializing for NodeJS");
if (typeof this.initObj === "string" && this.initObj.match(/^https?:\/\//)) {
return this.readFromHttp(this.initObj, this.nodeFileReady);
} else if (typeof this.initObj === "string") {
return fs.readFile(this.initObj, this.nodeFileReady);
} else {
return this.nodeFileReady(null, this.initObj);
}
};
Caman.prototype.readFromHttp = function(url, callback) {
var req;
Log.debug("Fetching image from " + url);
req = http.get(url, function(res) {
var buf;
buf = '';
res.setEncoding('binary');
res.on('data', function(chunk) {
return buf += chunk;
});
return res.on('end', function() {
return callback(null, new Buffer(buf, 'binary'));
});
});
return req.on('error', callback);
};
Caman.prototype.nodeFileReady = function(err, data) {
if (err) {
throw err;
}
this.image = new Image();
this.image.src = data;
Log.debug("Image loaded. Width = " + (this.imageWidth()) + ", Height = " + (this.imageHeight()));
this.canvas = new Canvas(this.imageWidth(), this.imageHeight());
this.renderingCanvas = new Canvas(this.imageWidth(), this.imageHeight());
return this.finishInit();
};
Caman.prototype.initImage = function() {
this.image = this.initObj;
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
this.renderingCanvas = document.createElement('canvas');
this.renderingContext = this.renderingCanvas.getContext('2d');
Util.copyAttributes(this.image, this.canvas, {
except: ['src']
});
Util.copyAttributes(this.image, this.renderingCanvas, {
except: ['src']
});
if (this.image.parentNode != null) {
this.image.parentNode.replaceChild(this.renderingCanvas, this.image);
}
this.imageAdjustments();
return this.waitForImageLoaded();
};
Caman.prototype.initCanvas = function() {
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext('2d');
this.renderingCanvas = this.initObj;
this.renderingContext = this.renderingCanvas.getContext('2d');
this.canvas.width = this.renderingCanvas.width;
this.canvas.height = this.renderingCanvas.height;
if (this.imageUrl != null) {
this.image = document.createElement('img');
this.image.crossOrigin = 'anonymous';
this.image.src = this.imageUrl;
this.imageAdjustments();
return this.waitForImageLoaded();
} else {
return this.finishInit();
}
};
Caman.prototype.imageAdjustments = function() {
if (this.needsHiDPISwap()) {
Log.debug(this.image.src, "->", this.hiDPIReplacement());
this.swapped = true;
this.image.src = this.hiDPIReplacement();
}
if (IO.isRemote(this.image)) {
this.image.src = IO.proxyUrl(this.image.src);
return Log.debug("Remote image detected, using URL = " + this.image.src);
}
};
Caman.prototype.waitForImageLoaded = function() {
if (this.isImageLoaded()) {
return this.imageLoaded();
} else {
return this.image.onload = this.imageLoaded;
}
};
Caman.prototype.isImageLoaded = function() {
if (!this.image.complete) {
return false;
}
if ((this.image.naturalWidth != null) && this.image.naturalWidth === 0) {
return false;
}
return true;
};
Caman.prototype.imageWidth = function() {
return this.image.width || this.image.naturalWidth;
};
Caman.prototype.imageHeight = function() {
return this.image.height || this.image.naturalHeight;
};
Caman.prototype.imageLoaded = function() {
Log.debug("Image loaded. Width = " + (this.imageWidth()) + ", Height = " + (this.imageHeight()));
if (this.swapped) {
this.canvas.width = this.imageWidth() / this.hiDPIRatio();
this.canvas.height = this.imageHeight() / this.hiDPIRatio();
this.renderingCanvas.width = this.imageWidth() / this.hiDPIRatio();
this.renderingCanvas.height = this.imageHeight() / this.hiDPIRatio();
} else {
this.canvas.width = this.imageWidth();
this.canvas.height = this.imageHeight();
this.renderingCanvas.width = this.imageWidth();
this.renderingCanvas.height = this.imageHeight();
}
return this.finishInit();
};
Caman.prototype.finishInit = function() {
var i, len, o, pixel, ref;
if (this.context == null) {
this.context = this.canvas.getContext('2d');
}
if (this.renderingContext == null) {
this.renderingContext = this.renderingCanvas.getContext('2d');
}
this.originalWidth = this.preScaledWidth = this.width = this.canvas.width;
this.originalHeight = this.preScaledHeight = this.height = this.canvas.height;
this.hiDPIAdjustments();
if (!this.hasId()) {
this.assignId();
}
if (this.image != null) {
this.context.drawImage(this.image, 0, 0, this.imageWidth(), this.imageHeight(), 0, 0, this.preScaledWidth, this.preScaledHeight);
this.renderingContext.drawImage(this.image, 0, 0, this.imageWidth(), this.imageHeight(), 0, 0, this.preScaledWidth, this.preScaledHeight);
}
this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.pixelData = this.imageData.data;
if (Caman.allowRevert) {
this.initializedPixelData = Util.dataArray(this.pixelData.length);
this.originalPixelData = Util.dataArray(this.pixelData.length);
ref = this.pixelData;
for (i = o = 0, len = ref.length; o < len; i = ++o) {
pixel = ref[i];
this.initializedPixelData[i] = pixel;
this.originalPixelData[i] = pixel;
}
}
this.dimensions = {
width: this.canvas.width,
height: this.canvas.height
};
if (!Caman.NodeJS) {
Store.put(this.id, this);
}
this.callback.call(this, this);
return this.callback = function() {};
};
Caman.prototype.reloadCanvasData = function() {
this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
return this.pixelData = this.imageData.data;
};
Caman.prototype.resetOriginalPixelData = function() {
var i, len, o, pixel, ref, results;
if (!Caman.allowRevert) {
throw "Revert disabled";
}
this.originalPixelData = Util.dataArray(this.pixelData.length);
ref = this.pixelData;
results = [];
for (i = o = 0, len = ref.length; o < len; i = ++o) {
pixel = ref[i];
results.push(this.originalPixelData[i] = pixel);
}
return results;
};
Caman.prototype.hasId = function() {
return Caman.getAttrId(this.canvas) != null;
};
Caman.prototype.assignId = function() {
if (Caman.NodeJS || this.canvas.getAttribute('data-caman-id')) {
return;
}
return this.canvas.setAttribute('data-caman-id', this.id);
};
Caman.prototype.hiDPIDisabled = function() {
return this.canvas.getAttribute('data-caman-hidpi-disabled') !== null;
};
Caman.prototype.hiDPIAdjustments = function() {
var ratio;
if (Caman.NodeJS || !this.needsHiDPISwap()) {
return;
}
ratio = this.hiDPIRatio();
if (ratio !== 1) {
Log.debug("HiDPI ratio = " + ratio);
this.scaled = true;
this.preScaledWidth = this.canvas.width;
this.preScaledHeight = this.canvas.height;
this.canvas.width = this.preScaledWidth * ratio;
this.canvas.height = this.preScaledHeight * ratio;
this.canvas.style.width = this.preScaledWidth + "px";
this.canvas.style.height = this.preScaledHeight + "px";
this.context.scale(ratio, ratio);
this.width = this.originalWidth = this.canvas.width;
return this.height = this.originalHeight = this.canvas.height;
}
};
Caman.prototype.hiDPIRatio = function() {
var backingStoreRatio, devicePixelRatio;
devicePixelRatio = window.devicePixelRatio || 1;
backingStoreRatio = this.context.webkitBackingStorePixelRatio || this.context.mozBackingStorePixelRatio || this.context.msBackingStorePixelRatio || this.context.oBackingStorePixelRatio || this.context.backingStorePixelRatio || 1;
return devicePixelRatio / backingStoreRatio;
};
Caman.prototype.hiDPICapable = function() {
return (window.devicePixelRatio != null) && window.devicePixelRatio !== 1;
};
Caman.prototype.needsHiDPISwap = function() {
if (this.hiDPIDisabled() || !this.hiDPICapable()) {
return false;
}
return this.hiDPIReplacement() !== null;
};
Caman.prototype.hiDPIReplacement = function() {
if (this.image == null) {
return null;
}
return this.image.getAttribute('data-caman-hidpi');
};
Caman.prototype.replaceCanvas = function(newCanvas) {
var i, len, o, pixel, ref;
this.canvas = newCanvas;
this.context = this.canvas.getContext('2d');
this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.pixelData = this.imageData.data;
if (Caman.allowRevert) {
this.originalPixelData = Util.dataArray(this.pixelData.length);
ref = this.pixelData;
for (i = o = 0, len = ref.length; o < len; i = ++o) {
pixel = ref[i];
this.originalPixelData[i] = pixel;
}
}
this.width = this.canvas.width;
this.height = this.canvas.height;
this.reloadCanvasData();
return this.dimensions = {
width: this.canvas.width,
height: this.canvas.height
};
};
Caman.prototype.render = function(callback) {
if (callback == null) {
callback = function() {};
}
Event.trigger(this, "renderStart");
return this.renderer.execute((function(_this) {
return function() {
_this.renderingCanvas.width = _this.canvas.width;
_this.renderingCanvas.height = _this.canvas.height;
_this.renderingContext.putImageData(_this.imageData, 0, 0);
return callback.call(_this);
};
})(this));
};
Caman.prototype.revert = function(updateContext) {
var i, len, o, pixel, ref;
if (updateContext == null) {
updateContext = true;
}
if (!Caman.allowRevert) {
throw "Revert disabled";
}
ref = this.originalVisiblePixels();
for (i = o = 0, len = ref.length; o < len; i = ++o) {
pixel = ref[i];
this.pixelData[i] = pixel;
}
if (updateContext) {
return this.renderingContext.putImageData(this.imageData, 0, 0);
}
};
Caman.prototype.reset = function() {
var canvas, ctx, i, imageData, len, o, pixel, pixelData, ref;
canvas = document.createElement('canvas');
Util.copyAttributes(this.canvas, canvas);
canvas.width = this.originalWidth;
canvas.height = this.originalHeight;
ctx = canvas.getContext('2d');
imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
pixelData = imageData.data;
ref = this.initializedPixelData;
for (i = o = 0, len = ref.length; o < len; i = ++o) {
pixel = ref[i];
pixelData[i] = pixel;
}
ctx.putImageData(imageData, 0, 0);
this.cropCoordinates = {
x: 0,
y: 0
};
this.resized = false;
return this.replaceCanvas(canvas);
};
Caman.prototype.originalVisiblePixels = function() {
var coord, endX, endY, i, o, pixelData, pixels, ref, ref1, ref2, startX, startY, width;
if (!Caman.allowRevert) {
throw "Revert disabled";
}
pixels = [];
startX = 0;
endX = startX + this.width;
startY = 0;
endY = startY + this.height;
pixelData = this.originalPixelData;
width = this.canvas.width;
for (i = o = 0, ref = pixelData.length; o < ref; i = o += 4) {
coord = Pixel.locationToCoordinates(i, width);
if (((startX <= (ref1 = coord.x) && ref1 < endX)) && ((startY <= (ref2 = coord.y) && ref2 < endY))) {
pixels.push(pixelData[i], pixelData[i + 1], pixelData[i + 2], pixelData[i + 3]);
}
}
return pixels;
};
Caman.prototype.process = function(name, processFn) {
this.renderer.add({
type: Filter.Type.Single,
name: name,
processFn: processFn
});
return this;
};
Caman.prototype.processKernel = function(name, adjust, divisor, bias) {
var i, o, ref;
if (divisor == null) {
divisor = null;
}
if (bias == null) {
bias = 0;
}
if (divisor == null) {
divisor = 0;
for (i = o = 0, ref = adjust.length; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
divisor += adjust[i];
}
}
this.renderer.add({
type: Filter.Type.Kernel,
name: name,
adjust: adjust,
divisor: divisor,
bias: bias
});
return this;
};
Caman.prototype.processPlugin = function(plugin, args) {
this.renderer.add({
type: Filter.Type.Plugin,
plugin: plugin,
args: args
});
return this;
};
Caman.prototype.newLayer = function(callback) {
var layer;
layer = new Layer(this);
this.canvasQueue.push(layer);
this.renderer.add({
type: Filter.Type.LayerDequeue
});
callback.call(layer);
this.renderer.add({
type: Filter.Type.LayerFinished
});
return this;
};
Caman.prototype.executeLayer = function(layer) {
return this.pushContext(layer);
};
Caman.prototype.pushContext = function(layer) {
this.layerStack.push(this.currentLayer);
this.pixelStack.push(this.pixelData);
this.currentLayer = layer;
return this.pixelData = layer.pixelData;
};
Caman.prototype.popContext = function() {
this.pixelData = this.pixelStack.pop();
return this.currentLayer = this.layerStack.pop();
};
Caman.prototype.applyCurrentLayer = function() {
return this.currentLayer.applyToParent();
};
return Caman;
})(Module);
Root.Caman = Caman;
Caman.Analyze = (function() {
function Analyze(c1) {
this.c = c1;
}
Analyze.prototype.calculateLevels = function() {
var i, levels, numPixels, o, ref, u, w;
levels = {
r: {},
g: {},
b: {}
};
for (i = o = 0; o <= 255; i = ++o) {
levels.r[i] = 0;
levels.g[i] = 0;
levels.b[i] = 0;
}
for (i = u = 0, ref = this.c.pixelData.length; u < ref; i = u += 4) {
levels.r[this.c.pixelData[i]]++;
levels.g[this.c.pixelData[i + 1]]++;
levels.b[this.c.pixelData[i + 2]]++;
}
numPixels = this.c.pixelData.length / 4;
for (i = w = 0; w <= 255; i = ++w) {
levels.r[i] /= numPixels;
levels.g[i] /= numPixels;
levels.b[i] /= numPixels;
}
return levels;
};
return Analyze;
})();
Analyze = Caman.Analyze;
Caman.DOMUpdated = function() {
var img, imgs, len, o, parser, results;
imgs = document.querySelectorAll("img[data-caman]");
if (!(imgs.length > 0)) {
return;
}
results = [];
for (o = 0, len = imgs.length; o < len; o++) {
img = imgs[o];
results.push(parser = new CamanParser(img, function() {
this.parse();
return this.execute();
}));
}
return results;
};
if (Caman.autoload) {
(function() {
if (document.readyState === "complete") {
return Caman.DOMUpdated();
} else {
return document.addEventListener("DOMContentLoaded", Caman.DOMUpdated, false);
}
})();
}
CamanParser = (function() {
var INST_REGEX;
INST_REGEX = "(\\w+)\\((.*?)\\)";
function CamanParser(ele, ready) {
this.dataStr = ele.getAttribute('data-caman');
this.caman = Caman(ele, ready.bind(this));
}
CamanParser.prototype.parse = function() {
var args, e, filter, func, inst, instFunc, len, m, o, r, ref, results, unparsedInstructions;
this.ele = this.caman.canvas;
r = new RegExp(INST_REGEX, 'g');
unparsedInstructions = this.dataStr.match(r);
if (!(unparsedInstructions.length > 0)) {
return;
}
r = new RegExp(INST_REGEX);
results = [];
for (o = 0, len = unparsedInstructions.length; o < len; o++) {
inst = unparsedInstructions[o];
ref = inst.match(r), m = ref[0], filter = ref[1], args = ref[2];
instFunc = new Function("return function() { this." + filter + "(" + args + "); };");
try {
func = instFunc();
results.push(func.call(this.caman));
} catch (error) {
e = error;
results.push(Log.debug(e));
}
}
return results;
};
CamanParser.prototype.execute = function() {
var ele;
ele = this.ele;
return this.caman.render(function() {
return ele.parentNode.replaceChild(this.toImage(), ele);
});
};
return CamanParser;
})();
Caman.Blender = (function() {
function Blender() {}
Blender.blenders = {};
Blender.register = function(name, func) {
return this.blenders[name] = func;
};
Blender.execute = function(name, rgbaLayer, rgbaParent) {
return this.blenders[name](rgbaLayer, rgbaParent);
};
return Blender;
})();
Blender = Caman.Blender;
Caman.Calculate = (function() {
function Calculate() {}
Calculate.distance = function(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
};
Calculate.randomRange = function(min, max, getFloat) {
var rand;
if (getFloat == null) {
getFloat = false;
}
rand = min + (Math.random() * (max - min));
if (getFloat) {
return rand.toFixed(getFloat);
} else {
return Math.round(rand);
}
};
Calculate.luminance = function(rgba) {
return (0.299 * rgba.r) + (0.587 * rgba.g) + (0.114 * rgba.b);
};
Calculate.bezier = function(start, ctrl1, ctrl2, end, lowBound, highBound) {
var bezier, clamp, controlPoints, endX, i, j, lerp, next, o, prev, ref, t, u;
if (lowBound == null) {
lowBound = 0;
}
if (highBound == null) {
highBound = 255;
}
if (start[0] instanceof Array) {
controlPoints = start;
lowBound = ctrl1;
highBound = ctrl2;
} else {
controlPoints = [start, ctrl1, ctrl2, end];
}
if (controlPoints.length < 2) {
throw "Invalid number of arguments to bezier";
}
bezier = {};
lerp = function(a, b, t) {
return a * (1 - t) + b * t;
};
clamp = function(a, min, max) {
return Math.min(Math.max(a, min), max);
};
for (i = o = 0; o < 1000; i = ++o) {
t = i / 1000;
prev = controlPoints;
while (prev.length > 1) {
next = [];
for (j = u = 0, ref = prev.length - 2; 0 <= ref ? u <= ref : u >= ref; j = 0 <= ref ? ++u : --u) {
next.push([lerp(prev[j][0], prev[j + 1][0], t), lerp(prev[j][1], prev[j + 1][1], t)]);
}
prev = next;
}
bezier[Math.round(prev[0][0])] = Math.round(clamp(prev[0][1], lowBound, highBound));
}
endX = controlPoints[controlPoints.length - 1][0];
bezier = Caman.Calculate.missingValues(bezier, endX);
if (bezier[endX] == null) {
bezier[endX] = bezier[endX - 1];
}
return bezier;
};
Calculate.hermite = function(controlPoints, lowBound, highBound) {
var add, clamp, count, endX, fac0, fac1, fac2, fac3, i, j, lerp, m0, m1, mul, o, p, p0, p1, pointsPerSegment, pointsPerStep, pos, ref, ref1, ret, sub, t, u;
if (controlPoints.length < 2) {
throw "Invalid number of arguments to hermite";
}
ret = {};
lerp = function(a, b, t) {
return a * (1 - t) + b * t;
};
add = (function(_this) {
return function(a, b, c, d) {
return [a[0] + b[0] + c[0] + d[0], a[1] + b[1] + c[1] + d[1]];
};
})(this);
mul = (function(_this) {
return function(a, b) {
return [a[0] * b[0], a[1] * b[1]];
};
})(this);
sub = (function(_this) {
return function(a, b) {
return [a[0] - b[0], a[1] - b[1]];
};
})(this);
clamp = function(a, min, max) {
return Math.min(Math.max(a, min), max);
};
count = 0;
for (i = o = 0, ref = controlPoints.length - 2; 0 <= ref ? o <= ref : o >= ref; i = 0 <= ref ? ++o : --o) {
p0 = controlPoints[i];
p1 = controlPoints[i + 1];
pointsPerSegment = p1[0] - p0[0];
pointsPerStep = 1 / pointsPerSegment;
if (i === controlPoints.length - 2) {
pointsPerStep = 1 / (pointsPerSegment - 1);
}
p = i > 0 ? controlPoints[i - 1] : p0;
m0 = mul(sub(p1, p), [0.5, 0.5]);
p = i < controlPoints.length - 2 ? controlPoints[i + 2] : p1;
m1 = mul(sub(p, p0), [0.5, 0.5]);
for (j = u = 0, ref1 = pointsPerSegment; 0 <= ref1 ? u <= ref1 : u >= ref1; j = 0 <= ref1 ? ++u : --u) {
t = j * pointsPerStep;
fac0 = 2.0 * t * t * t - 3.0 * t * t + 1.0;
fac1 = t * t * t - 2.0 * t * t + t;
fac2 = -2.0 * t * t * t + 3.0 * t * t;
fac3 = t * t * t - t * t;
pos = add(mul(p0, [fac0, fac0]), mul(m0, [fac1, fac1]), mul(p1, [fac2, fac2]), mul(m1, [fac3, fac3]));
ret[Math.round(pos[0])] = Math.round(clamp(pos[1], lowBound, highBound));
count += 1;
}
}
endX = controlPoints[controlPoints.length - 1][0];
ret = Caman.Calculate.missingValues(ret, endX);
return ret;
};
Calculate.missingValues = function(values, endX) {
var i, j, leftCoord, o, ref, ref1, ref2, ret, rightCoord, u;
if (Object.keys(values).length < endX + 1) {
ret = {};
for (i = o = 0, ref = endX; 0 <= ref ? o <= ref : o >= ref; i = 0 <= ref ? ++o : --o) {
if (values[i] != null) {
ret[i] = values[i];
} else {
leftCoord = [i - 1, ret[i - 1]];
for (j = u = ref1 = i, ref2 = endX; ref1 <= ref2 ? u <= ref2 : u >= ref2; j = ref1 <= ref2 ? ++u : --u) {
if (values[j] != null) {
rightCoord = [j, values[j]];
break;
}
}
if (rightCoord) {
ret[i] = leftCoord[1] + ((rightCoord[1] - leftCoord[1]) / (rightCoord[0] - leftCoord[0])) * (i - leftCoord[0]);
}
}
}
return ret;
}
return values;
};
return Calculate;
})();
Calculate = Caman.Calculate;
Caman.Convert = (function() {
function Convert() {}
Convert.hexToRGB = function(hex) {
var b, g, r;
if (hex.charAt(0) === "#") {
hex = hex.substr(1);
}
r = parseInt(hex.substr(0, 2), 16);
g = parseInt(hex.substr(2, 2), 16);
b = parseInt(hex.substr(4, 2), 16);
return {
r: r,
g: g,
b: b
};
};
Convert.rgbToHSL = function(r, g, b) {
var d, h, l, max, min, s;
if (typeof r === "object") {
g = r.g;
b = r.b;
r = r.r;
}
r /= 255;
g /= 255;
b /= 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
h = (function() {
switch (max) {
case r:
return (g - b) / d + (g < b ? 6 : 0);
case g:
return (b - r) / d + 2;
case b:
return (r - g) / d + 4;
}
})();
h /= 6;
}
return {
h: h,
s: s,
l: l
};
};
Convert.hslToRGB = function(h, s, l) {
var b, g, p, q, r;
if (typeof h === "object") {
s = h.s;
l = h.l;
h = h.h;
}
if (s === 0) {
r = g = b = l;
} else {
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
r = this.hueToRGB(p, q, h + 1 / 3);
g = this.hueToRGB(p, q, h);
b = this.hueToRGB(p, q, h - 1 / 3);
}
return {
r: r * 255,
g: g * 255,
b: b * 255
};
};
Convert.hueToRGB = function(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;
};
Convert.rgbToHSV = function(r, g, b) {
var d, h, max, min, s, v;
r /= 255;
g /= 255;
b /= 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
v = max;
d = max - min;
s = max === 0 ? 0 : d / max;
if (max === min) {
h = 0;
} else {
h = (function() {
switch (max) {
case r:
return (g - b) / d + (g < b ? 6 : 0);
case g:
return (b - r) / d + 2;
case b:
return (r - g) / d + 4;
}
})();
h /= 6;
}
return {
h: h,
s: s,
v: v
};
};
Convert.hsvToRGB = function(h, s, v) {
var b, f, g, i, p, q, r, t;
i = Math.floor(h * 6);
f = h * 6 - i;
p = v * (1 - s);
q = v * (1 - f * s);
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;
}
return {
r: Math.floor(r * 255),
g: Math.floor(g * 255),
b: Math.floor(b * 255)
};
};
Convert.rgbToXYZ = function(r, g, b) {
var x, y, z;
r /= 255;
g /= 255;
b /= 255;
if (r > 0.04045) {
r = Math.pow((r + 0.055) / 1.055, 2.4);
} else {
r /= 12.92;
}
if (g > 0.04045) {
g = Math.pow((g + 0.055) / 1.055, 2.4);
} else {
g /= 12.92;
}
if (b > 0.04045) {
b = Math.pow((b + 0.055) / 1.055, 2.4);
} else {
b /= 12.92;
}
x = r * 0.4124 + g * 0.3576 + b * 0.1805;
y = r * 0.2126 + g * 0.7152 + b * 0.0722;
z = r * 0.0193 + g * 0.1192 + b * 0.9505;
return {
x: x * 100,
y: y * 100,
z: z * 100
};
};
Convert.xyzToRGB = function(x, y, z) {
var b, g, r;
x /= 100;
y /= 100;
z /= 100;
r = (3.2406 * x) + (-1.5372 * y) + (-0.4986 * z);
g = (-0.9689 * x) + (1.8758 * y) + (0.0415 * z);
b = (0.0557 * x) + (-0.2040 * y) + (1.0570 * z);
if (r > 0.0031308) {
r = (1.055 * Math.pow(r, 0.4166666667)) - 0.055;
} else {
r *= 12.92;
}
if (g > 0.0031308) {
g = (1.055 * Math.pow(g, 0.4166666667)) - 0.055;
} else {
g *= 12.92;
}
if (b > 0.0031308) {
b = (1.055 * Math.pow(b, 0.4166666667)) - 0.055;
} else {
b *= 12.92;
}
return {
r: r * 255,
g: g * 255,
b: b * 255
};
};
Convert.xyzToLab = function(x, y, z) {
var a, b, l, whiteX, whiteY, whiteZ;
if (typeof x === "object") {
y = x.y;
z = x.z;
x = x.x;
}
whiteX = 95.047;
whiteY = 100.0;
whiteZ = 108.883;
x /= whiteX;
y /= whiteY;
z /= whiteZ;
if (x > 0.008856451679) {
x = Math.pow(x, 0.3333333333);
} else {
x = (7.787037037 * x) + 0.1379310345;
}
if (y > 0.008856451679) {
y = Math.pow(y, 0.3333333333);
} else {
y = (7.787037037 * y) + 0.1379310345;
}
if (z > 0.008856451679) {
z = Math.pow(z, 0.3333333333);
} else {
z = (7.787037037 * z) + 0.1379310345;
}
l = 116 * y - 16;
a = 500 * (x - y);
b = 200 * (y - z);
return {
l: l,
a: a,
b: b
};
};
Convert.labToXYZ = function(l, a, b) {
var x, y, z;
if (typeof l === "object") {
a = l.a;
b = l.b;
l = l.l;
}
y = (l + 16) / 116;
x = y + (a / 500);
z = y - (b / 200);
if (x > 0.2068965517) {
x = x * x * x;
} else {
x = 0.1284185493 * (x - 0.1379310345);
}
if (y > 0.2068965517) {
y = y * y * y;
} else {
y = 0.1284185493 * (y - 0.1379310345);
}
if (z > 0.2068965517) {
z = z * z * z;
} else {
z = 0.1284185493 * (z - 0.1379310345);
}
return {
x: x * 95.047,
y: y * 100.0,
z: z * 108.883
};
};
Convert.rgbToLab = function(r, g, b) {
var xyz;
if (typeof r === "object") {
g = r.g;
b = r.b;
r = r.r;
}
xyz = this.rgbToXYZ(r, g, b);
return this.xyzToLab(xyz);
};
Convert.labToRGB = function(l, a, b) {};
return Convert;
})();
Convert = Caman.Convert;
Caman.Event = (function() {
function Event() {}
Event.events = {};
Event.types = ["processStart", "processComplete", "renderStart", "renderFinished", "blockStarted", "blockFinished"];
Event.trigger = function(target, type, data) {
var event, len, o, ref, results;
if (data == null) {
data = null;
}
if (this.events[type] && this.events[type].length) {
ref = this.events[type];
results = [];
for (o = 0, len = ref.length; o < len; o++) {
event = ref[o];
if (event.target === null || target.id === event.target.id) {
results.push(event.fn.call(target, data));
} else {
results.push(void 0);
}
}
return results;
}
};
Event.listen = function(target, type, fn) {
var _fn, _type;
if (typeof target === "string") {
_type = target;
_fn = type;
target = null;
type = _type;
fn = _fn;
}
if (indexOf.call(this.types, type) < 0) {
return false;
}
if (!this.events[type]) {
this.events[type] = [];
}
this.events[type].push({
target: target,
fn: fn
});
return true;
};
return Event;
})();
Event = Caman.Event;
Caman.Filter = (function() {
function Filter() {}
Filter.Type = {
Single: 1,
Kernel: 2,
LayerDequeue: 3,
LayerFinished: 4,
LoadOverlay: 5,
Plugin: 6
};
Filter.register = function(name, filterFunc) {
return Caman.prototype[name] = filterFunc;
};
return Filter;
})();
Filter = Caman.Filter;
Caman.IO = (function() {
function IO() {}
IO.domainRegex = /(?:(?:http|https):\/\/)((?:[-|\w]+)\.(?:(?:-|\w|\.)+))/;
IO.isRemote = function(img) {
if (img == null) {
return false;
}
if (this.corsEnabled(img)) {
return false;
}
return this.isURLRemote(img.src);
};
IO.corsEnabled = function(img) {
return true;
};
IO.isURLRemote = function(url) {
var matches;
matches = url.match(this.domainRegex);
if (matches) {
return matches[1] !== document.domain;
} else {
return false;
}
};
IO.remoteCheck = function(src) {
if (this.isURLRemote(src)) {
if (!Caman.remoteProxy.length) {
Log.info("Attempting to load a remote image without a configured proxy. URL: " + src);
} else {
if (Caman.isURLRemote(Caman.remoteProxy)) {
Log.info("Cannot use a remote proxy for loading images.");
return;
}
return this.proxyUrl(src);
}
}
};
IO.proxyUrl = function(src) {
return Caman.remoteProxy + "?" + Caman.proxyParam + "=" + (encodeURIComponent(src));
};
IO.useProxy = function(lang) {
var langToExt;
langToExt = {
ruby: 'rb',
python: 'py',
perl: 'pl',
javascript: 'js'
};
lang = lang.toLowerCase();
if (langToExt[lang] != null) {
lang = langToExt[lang];
}
return "proxies/caman_proxy." + lang;
};
return IO;
})();
Caman.prototype.save = function() {
if (typeof exports !== "undefined" && exports !== null) {
return this.nodeSave.apply(this, arguments);
} else {
return this.browserSave.apply(this, arguments);
}
};
Caman.prototype.browserSave = function(type) {
var image;
if (type == null) {
type = "png";
}
type = type.toLowerCase();
image = this.toBase64(type).replace("image/" + type, "image/octet-stream");
return document.location.href = image;
};
Caman.prototype.nodeSave = function(file, overwrite, callback) {
var e, stats;
if (overwrite == null) {
overwrite = true;
}
if (callback == null) {
callback = null;
}
try {
stats = fs.statSync(file);
if (stats.isFile() && !overwrite) {
return false;
}
} catch (error) {
e = error;
Log.debug("Creating output file " + file);
}
return fs.writeFile(file, this.canvas.toBuffer(), function(err) {
Log.debug("Finished writing to " + file);
if (callback) {
return callback.call(this, err);
}
});
};
Caman.prototype.toImage = function(type) {
var img;
img = new Image();
img.src = this.toBase64(type);
img.width = this.dimensions.width;
img.height = this.dimensions.height;
if (window.devicePixelRatio) {
img.width /= window.devicePixelRatio;
img.height /= window.devicePixelRatio;
}
return img;
};
Caman.prototype.toBase64 = function(type) {
if (type == null) {
type = "png";
}
type = type.toLowerCase();
return this.renderingCanvas.toDataURL("image/" + type);
};
IO = Caman.IO;
Caman.Layer = (function() {
function Layer(c1) {
this.c = c1;
this.filter = this.c;
this.options = {
blendingMode: 'normal',
opacity: 1.0
};
this.layerID = Util.uniqid.get();
this.canvas = typeof exports !== "undefined" && exports !== null ? new Canvas() : document.createElement('canvas');
this.canvas.width = this.c.dimensions.width;
this.canvas.height = this.c.dimensions.height;
this.context = this.canvas.getContext('2d');
this.context.createImageData(this.canvas.width, this.canvas.height);
this.imageData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height);
this.pixelData = this.imageData.data;
}
Layer.prototype.newLayer = function(cb) {
return this.c.newLayer.call(this.c, cb);
};
Layer.prototype.setBlendingMode = function(mode) {
this.options.blendingMode = mode;
return this;
};
Layer.prototype.opacity = function(opacity) {
this.options.opacity = opacity / 100;
return this;
};
Layer.prototype.copyParent = function() {
var i, o, parentData, ref;
parentData = this.c.pixelData;
for (i = o = 0, ref = this.c.pixelData.length; o < ref; i = o += 4) {
this.pixelData[i] = parentData[i];
this.pixelData[i + 1] = parentData[i + 1];
this.pixelData[i + 2] = parentData[i + 2];
this.pixelData[i + 3] = parentData[i + 3];
}
return this;
};
Layer.prototype.fillColor = function() {
return this.c.fillColor.apply(this.c, arguments);
};
Layer.prototype.overlayImage = function(image) {
if (typeof image === "object") {
image = image.src;
} else if (typeof image === "string" && image[0] === "#") {
image = $(image).src;
}
if (!image) {
return this;
}
this.c.renderer.renderQueue.push({
type: Filter.Type.LoadOverlay,
src: image,
layer: this
});
return this;
};
Layer.prototype.applyToParent = function() {
var i, layerData, o, parentData, ref, result, results, rgbaLayer, rgbaParent;
parentData = this.c.pixelStack[this.c.pixelStack.length - 1];
layerData = this.c.pixelData;
results = [];
for (i = o = 0, ref = layerData.length; o < ref; i = o += 4) {
rgbaParent = {
r: parentData[i],
g: parentData[i + 1],
b: parentData[i + 2],
a: parentData[i + 3]
};
rgbaLayer = {
r: layerData[i],
g: layerData[i + 1],
b: layerData[i + 2],
a: layerData[i + 3]
};
result = Blender.execute(this.options.blendingMode, rgbaLayer, rgbaParent);
result.r = Util.clampRGB(result.r);
result.g = Util.clampRGB(result.g);
result.b = Util.clampRGB(result.b);
if (result.a == null) {
result.a = rgbaLayer.a;
}
parentData[i] = rgbaParent.r - ((rgbaParent.r - result.r) * (this.options.opacity * (result.a / 255)));
parentData[i + 1] = rgbaParent.g - ((rgbaParent.g - result.g) * (this.options.opacity * (result.a / 255)));
results.push(parentData[i + 2] = rgbaParent.b - ((rgbaParent.b - result.b) * (this.options.opacity * (result.a / 255))));
}
return results;
};
return Layer;
})();
Layer = Caman.Layer;
Caman.Logger = (function() {
function Logger() {
var len, name, o, ref;
ref = ['log', 'info', 'warn', 'error'];
for (o = 0, len = ref.length; o < len; o++) {
name = ref[o];
this[name] = (function(name) {
return function() {
var args, e;
args = 1 <= arguments.length ? slice1.call(arguments, 0) : [];
if (!Caman.DEBUG) {
return;
}
try {
return console[name].apply(console, args);
} catch (error) {
e = error;
return console[name](args);
}
};
})(name);
}
this.debug = this.log;
}
return Logger;
})();
Log = new Caman.Logger();
Caman.Pixel = (function() {
Pixel.coordinatesToLocation = function(x, y, width) {
return (y * width + x) * 4;
};
Pixel.locationToCoordinates = function(loc, width) {
var x, y;
y = Math.floor(loc / (width * 4));
x = (loc % (width * 4)) / 4;
return {
x: x,
y: y
};
};
function Pixel(r1, g1, b1, a1, c1) {
this.r = r1 != null ? r1 : 0;
this.g = g1 != null ? g1 : 0;
this.b = b1 != null ? b1 : 0;
this.a = a1 != null ? a1 : 255;
this.c = c1 != null ? c1 : null;
this.loc = 0;
}
Pixel.prototype.setContext = function(c) {
return this.c = c;
};
Pixel.prototype.locationXY = function() {
var x, y;
if (this.c == null) {
throw "Requires a CamanJS context";
}
y = this.c.dimensions.height - Math.floor(this.loc / (this.c.dimensions.width * 4));
x = (this.loc % (this.c.dimensions.width * 4)) / 4;
return {
x: x,
y: y
};
};
Pixel.prototype.pixelAtLocation = function(loc) {
if (this.c == null) {
throw "Requires a CamanJS context";
}
return new Pixel(this.c.pixelData[loc], this.c.pixelData[loc + 1], this.c.pixelData[loc + 2], this.c.pixelData[loc + 3], this.c);
};
Pixel.prototype.getPixelRelative = function(horiz, vert) {
var newLoc;
if (this.c == null) {
throw "Requires a CamanJS context";
}
newLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz);
if (newLoc > this.c.pixelData.length || newLoc < 0) {
return new Pixel(0, 0, 0, 255, this.c);
}
return this.pixelAtLocation(newLoc);
};
Pixel.prototype.putPixelRelative = function(horiz, vert, rgba) {
var nowLoc;
if (this.c == null) {
throw "Requires a CamanJS context";
}
nowLoc = this.loc + (this.c.dimensions.width * 4 * (vert * -1)) + (4 * horiz);
if (newLoc > this.c.pixelData.length || newLoc < 0) {
return;
}
this.c.pixelData[newLoc] = rgba.r;
this.c.pixelData[newLoc + 1] = rgba.g;
this.c.pixelData[newLoc + 2] = rgba.b;
this.c.pixelData[newLoc + 3] = rgba.a;
return true;
};
Pixel.prototype.getPixel = function(x, y) {
var loc;
if (this.c == null) {
throw "Requires a CamanJS context";
}
loc = this.coordinatesToLocation(x, y, this.width);
return this.pixelAtLocation(loc);
};
Pixel.prototype.putPixel = function(x, y, rgba) {
var loc;
if (this.c == null) {
throw "Requires a CamanJS context";
}
loc = this.coordinatesToLocation(x, y, this.width);
this.c.pixelData[loc] = rgba.r;
this.c.pixelData[loc + 1] = rgba.g;
this.c.pixelData[loc + 2] = rgba.b;
return this.c.pixelData[loc + 3] = rgba.a;
};
Pixel.prototype.toString = function() {
return this.toKey();
};
Pixel.prototype.toHex = function(includeAlpha) {
var hex;
if (includeAlpha == null) {
includeAlpha = false;
}
hex = '#' + this.r.toString(16) + this.g.toString(16) + this.b.toString(16);
if (includeAlpha) {
return hex + this.a.toString(16);
} else {
return hex;
}
};
return Pixel;
})();
Pixel = Caman.Pixel;
Caman.Plugin = (function() {
function Plugin() {}
Plugin.plugins = {};
Plugin.register = function(name, plugin) {
return this.plugins[name] = plugin;
};
Plugin.execute = function(context, name, args) {
return this.plugins[name].apply(context, args);
};
return Plugin;
})();
Plugin = Caman.Plugin;
Caman.Renderer = (function() {
Renderer.Blocks = Caman.NodeJS ? require('os').cpus().length : 4;
function Renderer(c1) {
this.c = c1;
this.processNext = bind(this.processNext, this);
this.renderQueue = [];
this.modPixelData = null;
}
Renderer.prototype.add = function(job) {
if (job == null) {
return;
}
return this.renderQueue.push(job);
};
Renderer.prototype.processNext = function() {
var layer;
if (this.renderQueue.length === 0) {
Event.trigger(this, "renderFinished");
if (this.finishedFn != null) {
this.finishedFn.call(this.c);
}
return this;
}
this.currentJob = this.renderQueue.shift();
switch (this.currentJob.type) {
case Filter.Type.LayerDequeue:
layer = this.c.canvasQueue.shift();
this.c.executeLayer(layer);
return this.processNext();
case Filter.Type.LayerFinished:
this.c.applyCurrentLayer();
this.c.popContext();
return this.processNext();
case Filter.Type.LoadOverlay:
return this.loadOverlay(this.currentJob.layer, this.currentJob.src);
case Filter.Type.Plugin:
return this.executePlugin();
default:
return this.executeFilter();
}
};
Renderer.prototype.execute = function(callback) {
this.finishedFn = callback;
this.modPixelData = Util.dataArray(this.c.pixelData.length);
return this.processNext();
};
Renderer.prototype.eachBlock = function(fn) {
var blockN, blockPixelLength, bnum, end, f, i, lastBlockN, n, o, ref, results, start;
this.blocksDone = 0;
n = this.c.pixelData.length;
blockPixelLength = Math.floor((n / 4) / Renderer.Blocks);
blockN = blockPixelLength * 4;
lastBlockN = blockN + ((n / 4) % Renderer.Blocks) * 4;
results = [];
for (i = o = 0, ref = Renderer.Blocks; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
start = i * blockN;
end = start + (i === Renderer.Blocks - 1 ? lastBlockN : blockN);
if (Caman.NodeJS) {
f = Fiber((function(_this) {
return function() {
return fn.call(_this, i, start, end);
};
})(this));
bnum = f.run();
results.push(this.blockFinished(bnum));
} else {
results.push(setTimeout((function(_this) {
return function(i, start, end) {
return function() {
return fn.call(_this, i, start, end);
};
};
})(this)(i, start, end), 0));
}
}
return results;
};
Renderer.prototype.executeFilter = function() {
Event.trigger(this.c, "processStart", this.currentJob);
if (this.currentJob.type === Filter.Type.Single) {
return this.eachBlock(this.renderBlock);
} else {
return this.eachBlock(this.renderKernel);
}
};
Renderer.prototype.executePlugin = function() {
Log.debug("Executing plugin " + this.currentJob.plugin);
Plugin.execute(this.c, this.currentJob.plugin, this.currentJob.args);
Log.debug("Plugin " + this.currentJob.plugin + " finished!");
return this.processNext();
};
Renderer.prototype.renderBlock = function(bnum, start, end) {
var i, o, pixel, ref, ref1;
Log.debug("Block #" + bnum + " - Filter: " + this.currentJob.name + ", Start: " + start + ", End: " + end);
Event.trigger(this.c, "blockStarted", {
blockNum: bnum,
totalBlocks: Renderer.Blocks,
startPixel: start,
endPixel: end
});
pixel = new Pixel();
pixel.setContext(this.c);
for (i = o = ref = start, ref1 = end; o < ref1; i = o += 4) {
pixel.loc = i;
pixel.r = this.c.pixelData[i];
pixel.g = this.c.pixelData[i + 1];
pixel.b = this.c.pixelData[i + 2];
pixel.a = this.c.pixelData[i + 3];
if (this.currentJob.processFn) {
this.currentJob.processFn(pixel);
}
this.c.pixelData[i] = Util.clampRGB(pixel.r);
this.c.pixelData[i + 1] = Util.clampRGB(pixel.g);
this.c.pixelData[i + 2] = Util.clampRGB(pixel.b);
this.c.pixelData[i + 3] = Util.clampRGB(pixel.a);
}
if (Caman.NodeJS) {
return Fiber["yield"](bnum);
} else {
return this.blockFinished(bnum);
}
};
Renderer.prototype.renderKernel = function(bnum, start, end) {
var adjust, adjustSize, bias, builder, builderIndex, divisor, i, j, k, kernel, n, name, o, p, pixel, ref, ref1, ref2, ref3, ref4, ref5, res, u, w;
name = this.currentJob.name;
bias = this.currentJob.bias;
divisor = this.currentJob.divisor;
n = this.c.pixelData.length;
adjust = this.currentJob.adjust;
if (!adjust) {
this.blockFinished(bnum);
return;
}
adjustSize = Math.sqrt(adjust.length);
kernel = [];
Log.debug("Rendering kernel - Filter: " + this.currentJob.name);
start = Math.max(start, this.c.dimensions.width * 4 * ((adjustSize - 1) / 2));
end = Math.min(end, n - (this.c.dimensions.width * 4 * ((adjustSize - 1) / 2)));
builder = (adjustSize - 1) / 2;
pixel = new Pixel();
pixel.setContext(this.c);
for (i = o = ref = start, ref1 = end; o < ref1; i = o += 4) {
pixel.loc = i;
builderIndex = 0;
for (j = u = ref2 = -builder, ref3 = builder; ref2 <= ref3 ? u <= ref3 : u >= ref3; j = ref2 <= ref3 ? ++u : --u) {
for (k = w = ref4 = builder, ref5 = -builder; ref4 <= ref5 ? w <= ref5 : w >= ref5; k = ref4 <= ref5 ? ++w : --w) {
p = pixel.getPixelRelative(j, k);
kernel[builderIndex * 3] = p.r;
kernel[builderIndex * 3 + 1] = p.g;
kernel[builderIndex * 3 + 2] = p.b;
builderIndex++;
}
}
res = this.processKernel(adjust, kernel, divisor, bias);
this.modPixelData[i] = Util.clampRGB(res.r);
this.modPixelData[i + 1] = Util.clampRGB(res.g);
this.modPixelData[i + 2] = Util.clampRGB(res.b);
this.modPixelData[i + 3] = this.c.pixelData[i + 3];
}
if (Caman.NodeJS) {
return Fiber["yield"](bnum);
} else {
return this.blockFinished(bnum);
}
};
Renderer.prototype.blockFinished = function(bnum) {
var i, o, ref;
if (bnum >= 0) {
Log.debug("Block #" + bnum + " finished! Filter: " + this.currentJob.name);
}
this.blocksDone++;
Event.trigger(this.c, "blockFinished", {
blockNum: bnum,
blocksFinished: this.blocksDone,
totalBlocks: Renderer.Blocks
});
if (this.blocksDone === Renderer.Blocks) {
if (this.currentJob.type === Filter.Type.Kernel) {
for (i = o = 0, ref = this.c.pixelData.length; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
this.c.pixelData[i] = this.modPixelData[i];
}
}
if (bnum >= 0) {
Log.debug("Filter " + this.currentJob.name + " finished!");
}
Event.trigger(this.c, "processComplete", this.currentJob);
return this.processNext();
}
};
Renderer.prototype.processKernel = function(adjust, kernel, divisor, bias) {
var i, o, ref, val;
val = {
r: 0,
g: 0,
b: 0
};
for (i = o = 0, ref = adjust.length; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
val.r += adjust[i] * kernel[i * 3];
val.g += adjust[i] * kernel[i * 3 + 1];
val.b += adjust[i] * kernel[i * 3 + 2];
}
val.r = (val.r / divisor) + bias;
val.g = (val.g / divisor) + bias;
val.b = (val.b / divisor) + bias;
return val;
};
Renderer.prototype.loadOverlay = function(layer, src) {
var img, proxyUrl;
img = new Image();
img.onload = (function(_this) {
return function() {
layer.context.drawImage(img, 0, 0, _this.c.dimensions.width, _this.c.dimensions.height);
layer.imageData = layer.context.getImageData(0, 0, _this.c.dimensions.width, _this.c.dimensions.height);
layer.pixelData = layer.imageData.data;
_this.c.pixelData = layer.pixelData;
return _this.processNext();
};
})(this);
proxyUrl = IO.remoteCheck(src);
return img.src = proxyUrl != null ? proxyUrl : src;
};
return Renderer;
})();
Renderer = Caman.Renderer;
Caman.Store = (function() {
function Store() {}
Store.items = {};
Store.has = function(search) {
return this.items[search] != null;
};
Store.get = function(search) {
return this.items[search];
};
Store.put = function(name, obj) {
return this.items[name] = obj;
};
Store.execute = function(search, callback) {
setTimeout((function(_this) {
return function() {
return callback.call(_this.get(search), _this.get(search));
};
})(this), 0);
return this.get(search);
};
Store.flush = function(name) {
if (name == null) {
name = false;
}
if (name) {
return delete this.items[name];
} else {
return this.items = {};
}
};
return Store;
})();
Store = Caman.Store;
Blender.register("normal", function(rgbaLayer, rgbaParent) {
return {
r: rgbaLayer.r,
g: rgbaLayer.g,
b: rgbaLayer.b
};
});
Blender.register("multiply", function(rgbaLayer, rgbaParent) {
return {
r: (rgbaLayer.r * rgbaParent.r) / 255,
g: (rgbaLayer.g * rgbaParent.g) / 255,
b: (rgbaLayer.b * rgbaParent.b) / 255
};
});
Blender.register("screen", function(rgbaLayer, rgbaParent) {
return {
r: 255 - (((255 - rgbaLayer.r) * (255 - rgbaParent.r)) / 255),
g: 255 - (((255 - rgbaLayer.g) * (255 - rgbaParent.g)) / 255),
b: 255 - (((255 - rgbaLayer.b) * (255 - rgbaParent.b)) / 255)
};
});
Blender.register("overlay", function(rgbaLayer, rgbaParent) {
var result;
result = {};
result.r = rgbaParent.r > 128 ? 255 - 2 * (255 - rgbaLayer.r) * (255 - rgbaParent.r) / 255 : (rgbaParent.r * rgbaLayer.r * 2) / 255;
result.g = rgbaParent.g > 128 ? 255 - 2 * (255 - rgbaLayer.g) * (255 - rgbaParent.g) / 255 : (rgbaParent.g * rgbaLayer.g * 2) / 255;
result.b = rgbaParent.b > 128 ? 255 - 2 * (255 - rgbaLayer.b) * (255 - rgbaParent.b) / 255 : (rgbaParent.b * rgbaLayer.b * 2) / 255;
return result;
});
Blender.register("difference", function(rgbaLayer, rgbaParent) {
return {
r: rgbaLayer.r - rgbaParent.r,
g: rgbaLayer.g - rgbaParent.g,
b: rgbaLayer.b - rgbaParent.b
};
});
Blender.register("addition", function(rgbaLayer, rgbaParent) {
return {
r: rgbaParent.r + rgbaLayer.r,
g: rgbaParent.g + rgbaLayer.g,
b: rgbaParent.b + rgbaLayer.b
};
});
Blender.register("exclusion", function(rgbaLayer, rgbaParent) {
return {
r: 128 - 2 * (rgbaParent.r - 128) * (rgbaLayer.r - 128) / 255,
g: 128 - 2 * (rgbaParent.g - 128) * (rgbaLayer.g - 128) / 255,
b: 128 - 2 * (rgbaParent.b - 128) * (rgbaLayer.b - 128) / 255
};
});
Blender.register("softLight", function(rgbaLayer, rgbaParent) {
var result;
result = {};
result.r = rgbaParent.r > 128 ? 255 - ((255 - rgbaParent.r) * (255 - (rgbaLayer.r - 128))) / 255 : (rgbaParent.r * (rgbaLayer.r + 128)) / 255;
result.g = rgbaParent.g > 128 ? 255 - ((255 - rgbaParent.g) * (255 - (rgbaLayer.g - 128))) / 255 : (rgbaParent.g * (rgbaLayer.g + 128)) / 255;
result.b = rgbaParent.b > 128 ? 255 - ((255 - rgbaParent.b) * (255 - (rgbaLayer.b - 128))) / 255 : (rgbaParent.b * (rgbaLayer.b + 128)) / 255;
return result;
});
Blender.register("lighten", function(rgbaLayer, rgbaParent) {
return {
r: rgbaParent.r > rgbaLayer.r ? rgbaParent.r : rgbaLayer.r,
g: rgbaParent.g > rgbaLayer.g ? rgbaParent.g : rgbaLayer.g,
b: rgbaParent.b > rgbaLayer.b ? rgbaParent.b : rgbaLayer.b
};
});
Blender.register("darken", function(rgbaLayer, rgbaParent) {
return {
r: rgbaParent.r > rgbaLayer.r ? rgbaLayer.r : rgbaParent.r,
g: rgbaParent.g > rgbaLayer.g ? rgbaLayer.g : rgbaParent.g,
b: rgbaParent.b > rgbaLayer.b ? rgbaLayer.b : rgbaParent.b
};
});
Filter.register("fillColor", function() {
var color;
if (arguments.length === 1) {
color = Convert.hexToRGB(arguments[0]);
} else {
color = {
r: arguments[0],
g: arguments[1],
b: arguments[2]
};
}
return this.process("fillColor", function(rgba) {
rgba.r = color.r;
rgba.g = color.g;
rgba.b = color.b;
rgba.a = 255;
return rgba;
});
});
Filter.register("brightness", function(adjust) {
adjust = Math.floor(255 * (adjust / 100));
return this.process("brightness", function(rgba) {
rgba.r += adjust;
rgba.g += adjust;
rgba.b += adjust;
return rgba;
});
});
Filter.register("saturation", function(adjust) {
adjust *= -0.01;
return this.process("saturation", function(rgba) {
var max;
max = Math.max(rgba.r, rgba.g, rgba.b);
if (rgba.r !== max) {
rgba.r += (max - rgba.r) * adjust;
}
if (rgba.g !== max) {
rgba.g += (max - rgba.g) * adjust;
}
if (rgba.b !== max) {
rgba.b += (max - rgba.b) * adjust;
}
return rgba;
});
});
Filter.register("vibrance", function(adjust) {
adjust *= -1;
return this.process("vibrance", function(rgba) {
var amt, avg, max;
max = Math.max(rgba.r, rgba.g, rgba.b);
avg = (rgba.r + rgba.g + rgba.b) / 3;
amt = ((Math.abs(max - avg) * 2 / 255) * adjust) / 100;
if (rgba.r !== max) {
rgba.r += (max - rgba.r) * amt;
}
if (rgba.g !== max) {
rgba.g += (max - rgba.g) * amt;
}
if (rgba.b !== max) {
rgba.b += (max - rgba.b) * amt;
}
return rgba;
});
});
Filter.register("greyscale", function(adjust) {
return this.process("greyscale", function(rgba) {
var avg;
avg = Calculate.luminance(rgba);
rgba.r = avg;
rgba.g = avg;
rgba.b = avg;
return rgba;
});
});
Filter.register("contrast", function(adjust) {
adjust = Math.pow((adjust + 100) / 100, 2);
return this.process("contrast", function(rgba) {
rgba.r /= 255;
rgba.r -= 0.5;
rgba.r *= adjust;
rgba.r += 0.5;
rgba.r *= 255;
rgba.g /= 255;
rgba.g -= 0.5;
rgba.g *= adjust;
rgba.g += 0.5;
rgba.g *= 255;
rgba.b /= 255;
rgba.b -= 0.5;
rgba.b *= adjust;
rgba.b += 0.5;
rgba.b *= 255;
return rgba;
});
});
Filter.register("hue", function(adjust) {
return this.process("hue", function(rgba) {
var b, g, h, hsv, r, ref;
hsv = Convert.rgbToHSV(rgba.r, rgba.g, rgba.b);
h = hsv.h * 100;
h += Math.abs(adjust);
h = h % 100;
h /= 100;
hsv.h = h;
ref = Convert.hsvToRGB(hsv.h, hsv.s, hsv.v), r = ref.r, g = ref.g, b = ref.b;
rgba.r = r;
rgba.g = g;
rgba.b = b;
return rgba;
});
});
Filter.register("colorize", function() {
var level, rgb;
if (arguments.length === 2) {
rgb = Convert.hexToRGB(arguments[0]);
level = arguments[1];
} else if (arguments.length === 4) {
rgb = {
r: arguments[0],
g: arguments[1],
b: arguments[2]
};
level = arguments[3];
}
return this.process("colorize", function(rgba) {
rgba.r -= (rgba.r - rgb.r) * (level / 100);
rgba.g -= (rgba.g - rgb.g) * (level / 100);
rgba.b -= (rgba.b - rgb.b) * (level / 100);
return rgba;
});
});
Filter.register("invert", function() {
return this.process("invert", function(rgba) {
rgba.r = 255 - rgba.r;
rgba.g = 255 - rgba.g;
rgba.b = 255 - rgba.b;
return rgba;
});
});
Filter.register("sepia", function(adjust) {
if (adjust == null) {
adjust = 100;
}
adjust /= 100;
return this.process("sepia", function(rgba) {
rgba.r = Math.min(255, (rgba.r * (1 - (0.607 * adjust))) + (rgba.g * (0.769 * adjust)) + (rgba.b * (0.189 * adjust)));
rgba.g = Math.min(255, (rgba.r * (0.349 * adjust)) + (rgba.g * (1 - (0.314 * adjust))) + (rgba.b * (0.168 * adjust)));
rgba.b = Math.min(255, (rgba.r * (0.272 * adjust)) + (rgba.g * (0.534 * adjust)) + (rgba.b * (1 - (0.869 * adjust))));
return rgba;
});
});
Filter.register("gamma", function(adjust) {
return this.process("gamma", function(rgba) {
rgba.r = Math.pow(rgba.r / 255, adjust) * 255;
rgba.g = Math.pow(rgba.g / 255, adjust) * 255;
rgba.b = Math.pow(rgba.b / 255, adjust) * 255;
return rgba;
});
});
Filter.register("noise", function(adjust) {
adjust = Math.abs(adjust) * 2.55;
return this.process("noise", function(rgba) {
var rand;
rand = Calculate.randomRange(adjust * -1, adjust);
rgba.r += rand;
rgba.g += rand;
rgba.b += rand;
return rgba;
});
});
Filter.register("clip", function(adjust) {
adjust = Math.abs(adjust) * 2.55;
return this.process("clip", function(rgba) {
if (rgba.r > 255 - adjust) {
rgba.r = 255;
} else if (rgba.r < adjust) {
rgba.r = 0;
}
if (rgba.g > 255 - adjust) {
rgba.g = 255;
} else if (rgba.g < adjust) {
rgba.g = 0;
}
if (rgba.b > 255 - adjust) {
rgba.b = 255;
} else if (rgba.b < adjust) {
rgba.b = 0;
}
return rgba;
});
});
Filter.register("channels", function(options) {
var chan, value;
if (typeof options !== "object") {
return this;
}
for (chan in options) {
if (!hasProp.call(options, chan)) continue;
value = options[chan];
if (value === 0) {
delete options[chan];
continue;
}
options[chan] /= 100;
}
if (options.length === 0) {
return this;
}
return this.process("channels", function(rgba) {
if (options.red != null) {
if (options.red > 0) {
rgba.r += (255 - rgba.r) * options.red;
} else {
rgba.r -= rgba.r * Math.abs(options.red);
}
}
if (options.green != null) {
if (options.green > 0) {
rgba.g += (255 - rgba.g) * options.green;
} else {
rgba.g -= rgba.g * Math.abs(options.green);
}
}
if (options.blue != null) {
if (options.blue > 0) {
rgba.b += (255 - rgba.b) * options.blue;
} else {
rgba.b -= rgba.b * Math.abs(options.blue);
}
}
return rgba;
});
});
Filter.register("curves", function() {
var algo, bezier, chans, cps, end, i, last, o, ref, ref1, start, u;
chans = arguments[0], cps = 2 <= arguments.length ? slice1.call(arguments, 1) : [];
last = cps[cps.length - 1];
if (typeof last === "function") {
algo = last;
cps.pop();
} else if (typeof last === "string") {
algo = Calculate[last];
cps.pop();
} else {
algo = Calculate.bezier;
}
if (typeof chans === "string") {
chans = chans.split("");
}
if (chans[0] === "v") {
chans = ['r', 'g', 'b'];
}
if (cps.length < 2) {
throw "Invalid number of arguments to curves filter";
}
bezier = algo(cps, 0, 255);
start = cps[0];
if (start[0] > 0) {
for (i = o = 0, ref = start[0]; 0 <= ref ? o < ref : o > ref; i = 0 <= ref ? ++o : --o) {
bezier[i] = start[1];
}
}
end = cps[cps.length - 1];
if (end[0] < 255) {
for (i = u = ref1 = end[0]; ref1 <= 255 ? u <= 255 : u >= 255; i = ref1 <= 255 ? ++u : --u) {
bezier[i] = end[1];
}
}
return this.process("curves", function(rgba) {
var ref2, w;
for (i = w = 0, ref2 = chans.length; 0 <= ref2 ? w < ref2 : w > ref2; i = 0 <= ref2 ? ++w : --w) {
rgba[chans[i]] = bezier[rgba[chans[i]]];
}
return rgba;
});
});
Filter.register("exposure", function(adjust) {
var ctrl1, ctrl2, p;
p = Math.abs(adjust) / 100;
ctrl1 = [0, 255 * p];
ctrl2 = [255 - (255 * p), 255];
if (adjust < 0) {
ctrl1 = ctrl1.reverse();
ctrl2 = ctrl2.reverse();
}
return this.curves('rgb', [0, 0], ctrl1, ctrl2, [255, 255]);
});
Caman.Plugin.register("crop", function(width, height, x, y) {
var canvas, ctx;
if (x == null) {
x = 0;
}
if (y == null) {
y = 0;
}
if (typeof exports !== "undefined" && exports !== null) {
canvas = new Canvas(width, height);
} else {
canvas = document.createElement('canvas');
Util.copyAttributes(this.canvas, canvas);
canvas.width = width;
canvas.height = height;
}
ctx = canvas.getContext('2d');
ctx.drawImage(this.canvas, x, y, width, height, 0, 0, width, height);
this.cropCoordinates = {
x: x,
y: y
};
this.cropped = true;
return this.replaceCanvas(canvas);
});
Caman.Plugin.register("resize", function(newDims) {
var canvas, ctx;
if (newDims == null) {
newDims = null;
}
if (newDims === null || ((newDims.width == null) && (newDims.height == null))) {
Log.error("Invalid or missing dimensions given for resize");
return;
}
if (newDims.width == null) {
newDims.width = this.canvas.width * newDims.height / this.canvas.height;
} else if (newDims.height == null) {
newDims.height = this.canvas.height * newDims.width / this.canvas.width;
}
if (typeof exports !== "undefined" && exports !== null) {
canvas = new Canvas(newDims.width, newDims.height);
} else {
canvas = document.createElement('canvas');
Util.copyAttributes(this.canvas, canvas);
canvas.width = newDims.width;
canvas.height = newDims.height;
}
ctx = canvas.getContext('2d');
ctx.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, newDims.width, newDims.height);
this.resized = true;
return this.replaceCanvas(canvas);
});
Caman.Filter.register("crop", function() {
return this.processPlugin("crop", Array.prototype.slice.call(arguments, 0));
});
Caman.Filter.register("resize", function() {
return this.processPlugin("resize", Array.prototype.slice.call(arguments, 0));
});
}).call(this);
|