Bug 20489 Configure illegal file characters https://bugzilla.wikimedia.org/show_bug...
[mediawiki.git] / js2 / mwEmbed / libClipEdit / pixastic-editor / pixastic.all.js
blobbee153ab58244ce112e38341407130478f3e044f
1 /*
2  * Pixastic Lib - Core Functions - v0.1.3
3  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
4  * License: [http://www.pixastic.com/lib/license.txt]
5  */
7 var Pixastic = (function() {
10         function addEvent(el, event, handler) {
11                 if (el.addEventListener)
12                         el.addEventListener(event, handler, false); 
13                 else if (el.attachEvent)
14                         el.attachEvent("on" + event, handler); 
15         }
17         function onready(handler) {
18                 var handlerDone = false;
19                 var execHandler = function() {
20                         if (!handlerDone) {
21                                 handlerDone = true;
22                                 handler();
23                         }
24                 }
25                 document.write("<"+"script defer src=\"//:\" id=\"__onload_ie_sumbox__\"></"+"script>");
26                 var script = document.getElementById("__onload_ie_sumbox__");
27                 script.onreadystatechange = function() {
28                         if (script.readyState == "complete") {
29                                 script.parentNode.removeChild(script);
30                                 execHandler();
31                         }
32                 }
33                 if (document.addEventListener)
34                         document.addEventListener("DOMContentLoaded", execHandler, false); 
35                 addEvent(window, "load", execHandler);
36         }
38         function init() {
39                 if (!Pixastic.parseOnLoad) return;
40                 var imgEls = getElementsByClass("pixastic", null, "img");
41                 var canvasEls = getElementsByClass("pixastic", null, "canvas");
42                 var elements = imgEls.concat(canvasEls);
43                 for (var i=0;i<elements.length;i++) {
44                         (function() {
46                         var el = elements[i];
47                         var actions = [];
48                         var classes = el.className.split(" ");
49                         for (var c=0;c<classes.length;c++) {
50                                 var cls = classes[c];
51                                 if (cls.substring(0,9) == "pixastic-") {
52                                         var actionName = cls.substring(9);
53                                         if (actionName != "")
54                                                 actions.push(actionName);
55                                 }
56                         }
57                         if (actions.length) {
58                                 if (el.tagName.toLowerCase() == "img") {
59                                         var dataImg = new Image();
60                                         dataImg.src = el.src;
61                                         if (dataImg.complete) {
62                                                 for (var a=0;a<actions.length;a++) {
63                                                         var res = Pixastic.applyAction(el, el, actions[a], null);
64                                                         if (res) 
65                                                                 el = res;
66                                                 }
67                                         } else {
68                                                 dataImg.onload = function() {
69                                                         for (var a=0;a<actions.length;a++) {
70                                                                 var res = Pixastic.applyAction(el, el, actions[a], null)
71                                                                 if (res) 
72                                                                         el = res;
73                                                         }
74                                                 }
75                                         }
76                                 } else {
77                                         setTimeout(function() {
78                                                 for (var a=0;a<actions.length;a++) {
79                                                         var res = Pixastic.applyAction(
80                                                                 el, el, actions[a], null
81                                                         );
82                                                         if (res) 
83                                                                 el = res;
84                                                 }
85                                         },1);
86                                 }
87                         }
89                         })();
90                 }
91         }
93 //      if (typeof pixastic_no_onready == "undefined") // yuck.
94 //              onready(init);
96         // getElementsByClass by Dustin Diaz, http://www.dustindiaz.com/getelementsbyclass/
97         function getElementsByClass(searchClass,node,tag) {
98                 var classElements = new Array();
99                 if ( node == null )
100                         node = document;
101                 if ( tag == null )
102                         tag = '*';
104                 var els = node.getElementsByTagName(tag);
105                 var elsLen = els.length;
106                 var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
107                 for (i = 0, j = 0; i < elsLen; i++) {
108                         if ( pattern.test(els[i].className) ) {
109                                 classElements[j] = els[i];
110                                 j++;
111                         }
112                 }
113                 return classElements;
114         }
116         var debugElement;
118         function writeDebug(text, level) {
119                 if (!Pixastic.debug) return;
120                 try {
121                         switch (level) {
122                                 case "warn" : 
123                                         console.warn("Pixastic:", text);
124                                         break;
125                                 case "error" :
126                                         console.error("Pixastic:", text);
127                                         break;
128                                 default:
129                                         console.log("Pixastic:", text);
130                         }
131                 } catch(e) {
132                 }
133                 if (!debugElement) {
134                         
135                 }
136         }
139         return {
141                 parseOnLoad : false,
143                 debug : false,
144                 
145                 applyAction : function(img, dataImg, actionName, options) {
147                         options = options || {};
149                         var imageIsCanvas = (img.tagName.toLowerCase() == "canvas");
150                         if (imageIsCanvas && Pixastic.Client.isIE()) {
151                                 if (Pixastic.debug) writeDebug("Tried to process a canvas element but browser is IE.");
152                                 return false;
153                         }
155                         var canvas, ctx;
156                         if (Pixastic.Client.hasCanvas()) {
157                                 canvas = document.createElement("canvas");
158                                 ctx = canvas.getContext("2d");
159                         }
161                         var w = parseInt(img.offsetWidth);
162                         var h = parseInt(img.offsetHeight);
164                         if (imageIsCanvas) {
165                                 w = img.width;
166                                 h = img.height;
167                         }
169                         if (actionName.indexOf("(") > -1) {
170                                 var tmp = actionName;
171                                 actionName = tmp.substr(0, tmp.indexOf("("));
172                                 var arg = tmp.match(/\((.*?)\)/);
173                                 if (arg[1]) {
174                                         arg = arg[1].split(";");
175                                         for (var a=0;a<arg.length;a++) {
176                                                 thisArg = arg[a].split("=");
177                                                 if (thisArg.length == 2) {
178                                                         if (thisArg[0] == "rect") {
179                                                                 var rectVal = thisArg[1].split(",");
180                                                                 options[thisArg[0]] = {
181                                                                         left : parseInt(rectVal[0],10)||0,
182                                                                         top : parseInt(rectVal[1],10)||0,
183                                                                         width : parseInt(rectVal[2],10)||0,
184                                                                         height : parseInt(rectVal[3],10)||0
185                                                                 }
186                                                         } else {
187                                                                 options[thisArg[0]] = thisArg[1];
188                                                         }
189                                                 }
190                                         }
191                                 }
192                         }
194                         if (!options.rect) {
195                                 options.rect = {
196                                         left : 0, top : 0, width : w, height : h
197                                 };
198                         }
199                         var validAction = false;
200                         if (Pixastic.Actions[actionName] && typeof Pixastic.Actions[actionName].process == "function") {
201                                 validAction = true;
202                         }
203                         if (!validAction) {
204                                 if (Pixastic.debug) writeDebug("Invalid action \"" + actionName + "\". Maybe file not included?");
205                                 return false;
206                         }
207                         if (!Pixastic.Actions[actionName].checkSupport()) {
208                                 if (Pixastic.debug) writeDebug("Action \"" + actionName + "\" not supported by this browser.");
209                                 return false;
210                         }
212                         if (Pixastic.Client.hasCanvas()) {
213                                 canvas.width = w;
214                                 canvas.height = h;
215                                 canvas.style.width = w+"px";
216                                 canvas.style.height = h+"px";
217                                 ctx.drawImage(dataImg,0,0,w,h);
219                                 if (!img.__pixastic_org_image) {
220                                         canvas.__pixastic_org_image = img;
221                                         canvas.__pixastic_org_width = w;
222                                         canvas.__pixastic_org_height = h;
223                                 } else {
224                                         canvas.__pixastic_org_image = img.__pixastic_org_image;
225                                         canvas.__pixastic_org_width = img.__pixastic_org_width;
226                                         canvas.__pixastic_org_height = img.__pixastic_org_height;
227                                 }
229                         } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style == "undefined") {
230                                 img.__pixastic_org_style = img.style.cssText;
231                         }
233                         var params = {
234                                 image : img,
235                                 canvas : canvas,
236                                 width : w,
237                                 height : h,
238                                 useData : true,
239                                 options : options
240                         }
242                         // Ok, let's do it!
244                         var res = Pixastic.Actions[actionName].process(params);
246                         if (!res) {
247                                 return false;
248                         }
250                         if (Pixastic.Client.hasCanvas()) {
251                                 if (params.useData) {
252                                         if (Pixastic.Client.hasCanvasImageData()) {
253                                                 canvas.getContext("2d").putImageData(params.canvasData, options.rect.left, options.rect.top);
255                                                 // Opera doesn't seem to update the canvas until we draw something on it, lets draw a 0x0 rectangle.
256                                                 canvas.getContext("2d").fillRect(0,0,0,0);
257                                         }
258                                 }
260                                 if (!options.leaveDOM) {
261                                         // copy properties and stuff from the source image
262                                         canvas.title = img.title;
263                                         canvas.imgsrc = img.imgsrc;
264                                         if (!imageIsCanvas) canvas.alt  = img.alt;
265                                         if (!imageIsCanvas) canvas.imgsrc = img.src;
266                                         canvas.className = img.className;
267                                         canvas.style.cssText = img.style.cssText;
268                                         canvas.name = img.name;
269                                         canvas.tabIndex = img.tabIndex;
270                                         canvas.id = img.id;
271                                         if (img.parentNode && img.parentNode.replaceChild) {
272                                                 img.parentNode.replaceChild(canvas, img);
273                                         }
274                                 }
276                                 options.resultCanvas = canvas;
278                                 return canvas;
279                         }
281                         return img;
282                 },
284                 prepareData : function(params, getCopy) {
285                         var ctx = params.canvas.getContext("2d");
286                         var rect = params.options.rect;
287                         var dataDesc = ctx.getImageData(rect.left, rect.top, rect.width, rect.height);
288                         var data = dataDesc.data;
289                         if (!getCopy) params.canvasData = dataDesc;
290                         return data;
291                 },
293                 // load the image file
294                 process : function(img, actionName, options, callback)
295                 {
296                         if (img.tagName.toLowerCase() == "img") {
297                                 var dataImg = new Image();
298                                 dataImg.src = img.src;
299                                 if (dataImg.complete) {
300                                         var res = Pixastic.applyAction(img, dataImg, actionName, options);
301                                         if (callback) callback(res);
302                                         return res;
303                                 } else {
304                                         dataImg.onload = function() {
305                                                 var res = Pixastic.applyAction(img, dataImg, actionName, options)
306                                                 if (callback) callback(res);
307                                         }
308                                 }
309                         }
310                         if (img.tagName.toLowerCase() == "canvas") {
311                                 var res = Pixastic.applyAction(img, img, actionName, options);
312                                 if (callback) callback(res);
313                                 return res;
314                         }
315                 },
317                 revert : function(img) {
318                         if (Pixastic.Client.hasCanvas()) {
319                                 if (img.tagName.toLowerCase() == "canvas" && img.__pixastic_org_image) {
320                                         img.width = img.__pixastic_org_width;
321                                         img.height = img.__pixastic_org_height;
322                                         img.getContext("2d").drawImage(img.__pixastic_org_image, 0, 0);
324                                         if (img.parentNode && img.parentNode.replaceChild) {
325                                                 img.parentNode.replaceChild(img.__pixastic_org_image, img);
326                                         }
328                                         return img;
329                                 }
330                         } else if (Pixastic.Client.isIE() && typeof img.__pixastic_org_style != "undefined") {
331                                 img.style.cssText = img.__pixastic_org_style;
332                         }
333                 },
335                 Client : {
336                         hasCanvas : (function() {
337                                 var c = document.createElement("canvas");
338                                 var val = false;
339                                 try {
340                                         val = !!((typeof c.getContext == "function") && c.getContext("2d"));
341                                 } catch(e) {}
342                                 return function() {
343                                         return val;
344                                 }
345                         })(),
347                         hasCanvasImageData : (function() {
348                                 var c = document.createElement("canvas");
349                                 var val = false;
350                                 var ctx;
351                                 try {
352                                         if (typeof c.getContext == "function" && (ctx = c.getContext("2d"))) {
353                                                 val = (typeof ctx.getImageData == "function");
354                                         }
355                                 } catch(e) {}
356                                 return function() {
357                                         return val;
358                                 }
359                         })(),
361                         isIE : function() {
362                                 return !!document.all && !!window.attachEvent && !window.opera;
363                         }
364                 },
366                 Actions : {}
367         }
370 })();
372  * Pixastic Lib - jQuery plugin
373  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
374  * License: [http://www.pixastic.com/lib/license.txt]
375  */
377 if (typeof jQuery != "undefined" && jQuery && jQuery.fn) {
378         jQuery.fn.pixastic = function(action, options) {
379                 var newElements = [];
380                 this.each(
381                         function () {
382                                 if (this.tagName.toLowerCase() == "img" && !this.complete) {
383                                         return;
384                                 }
385                                 var res = Pixastic.process(this, action, options);
386                                 if (res) {
387                                         newElements.push(res);
388                                 }
389                         }
390                 );
391                 if (newElements.length > 0)
392                         return jQuery(newElements);
393                 else
394                         return this;
395         };
399  * Pixastic Lib - Blend - v0.1.1
400  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
401  * License: [http://www.pixastic.com/lib/license.txt]
402  */
404 Pixastic.Actions.blend = {
406         process : function(params) {
407                 var amount = parseFloat(params.options.amount);
408                 var mode = (params.options.mode || "normal").toLowerCase();
409                 var image = params.options.image;
411                 amount = Math.max(0,Math.min(1,amount));
413                 if (!image) return false;
415                 if (Pixastic.Client.hasCanvasImageData()) {
416                         var rect = params.options.rect;
417                         var data = Pixastic.prepareData(params);
418                         var w = rect.width;
419                         var h = rect.height;
421                         params.useData = false;
423                         var otherCanvas = document.createElement("canvas");
424                         otherCanvas.width = params.canvas.width;
425                         otherCanvas.height = params.canvas.height;
426                         var otherCtx = otherCanvas.getContext("2d");
427                         otherCtx.drawImage(image,0,0);
429                         var params2 = {canvas:otherCanvas,options:params.options};
430                         var data2 = Pixastic.prepareData(params2);
431                         var dataDesc2 = params2.canvasData;
433                         var p = w*h;
434                         var pix = p*4;
435                         var pix1, pix2;
436                         var r1, g1, b1;
437                         var r2, g2, b2;
438                         var r3, g3, b3;
439                         var r4, g4, b4;
441                         var dataChanged = false;
443                         switch (mode) {
444                                 case "normal" : 
445                                         //while (p--) {
446                                         //      data2[pix-=4] = data2[pix];
447                                         //      data2[pix1=pix+1] = data2[pix1];
448                                         //      data2[pix2=pix+2] = data2[pix2];
449                                         //}
450                                         break;
452                                 case "multiply" : 
453                                         while (p--) {
454                                                 data2[pix-=4] = data[pix] * data2[pix] / 255;
455                                                 data2[pix1=pix+1] = data[pix1] * data2[pix1] / 255;
456                                                 data2[pix2=pix+2] = data[pix2] * data2[pix2] / 255;
457                                         }
458                                         dataChanged = true;
459                                         break;
461                                 case "lighten" : 
462                                         while (p--) {
463                                                 if ((r1 = data[pix-=4]) > data2[pix])
464                                                         data2[pix] = r1;
465                                                 if ((g1 = data[pix1=pix+1]) > data2[pix1])
466                                                         data2[pix1] = g1;
467                                                 if ((b1 = data[pix2=pix+2]) > data2[pix2])
468                                                         data2[pix2] = b1;
469                                         }
470                                         dataChanged = true;
471                                         break;
473                                 case "darken" : 
474                                         while (p--) {
475                                                 if ((r1 = data[pix-=4]) < data2[pix])
476                                                         data2[pix] = r1;
477                                                 if ((g1 = data[pix1=pix+1]) < data2[pix1])
478                                                         data2[pix1] = g1;
479                                                 if ((b1 = data[pix2=pix+2]) < data2[pix2])
480                                                         data2[pix2] = b1;
482                                         }
483                                         dataChanged = true;
484                                         break;
486                                 case "darkercolor" : 
487                                         while (p--) {
488                                                 if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) <= (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
489                                                         data2[pix] = r1;
490                                                         data2[pix1] = g1;
491                                                         data2[pix2] = b1;
492                                                 }
493                                         }
494                                         dataChanged = true;
495                                         break;
497                                 case "lightercolor" : 
498                                         while (p--) {
499                                                 if (((r1 = data[pix-=4])*0.3+(g1 = data[pix1=pix+1])*0.59+(b1 = data[pix2=pix+2])*0.11) > (data2[pix]*0.3+data2[pix1]*0.59+data2[pix2]*0.11)) {
500                                                         data2[pix] = r1;
501                                                         data2[pix1] = g1;
502                                                         data2[pix2] = b1;
503                                                 }
504                                         }
505                                         dataChanged = true;
506                                         break;
508                                 case "lineardodge" : 
509                                         otherCtx.globalCompositeOperation = "source-over";
510                                         otherCtx.drawImage(params.canvas, 0, 0);
511                                         otherCtx.globalCompositeOperation = "lighter";
512                                         otherCtx.drawImage(image, 0, 0);
514                                         /*
515                                         while (p--) {
516                                                 if ((r3 = data[pix-=4] + data2[pix]) > 255)
517                                                         data2[pix] = 255;
518                                                 else
519                                                         data2[pix] = r3;
520                                                 if ((g3 = data[pix1=pix+1] + data2[pix1]) > 255)
521                                                         data2[pix1] = 255;
522                                                 else
523                                                         data2[pix1] = g3;
524                                                 if ((b3 = data[pix2=pix+2] + data2[pix2]) > 255)
525                                                         data2[pix2] = 255;
526                                                 else
527                                                         data2[pix2] = b3;
528                                         }
529                                         dataChanged = true;
530                                         */
532                                         break;
534                                 case "linearburn" : 
535                                         while (p--) {
536                                                 if ((r3 = data[pix-=4] + data2[pix]) < 255)
537                                                         data2[pix] = 0;
538                                                 else
539                                                         data2[pix] = (r3 - 255);
540                                                 if ((g3 = data[pix1=pix+1] + data2[pix1]) < 255)
541                                                         data2[pix1] = 0;
542                                                 else
543                                                         data2[pix1] = (g3 - 255);
544                                                 if ((b3 = data[pix2=pix+2] + data2[pix2]) < 255)
545                                                         data2[pix2] = 0;
546                                                 else
547                                                         data2[pix2] = (b3 - 255);
548                                         }
549                                         dataChanged = true;
550                                         break;
552                                 case "difference" : 
553                                         while (p--) {
554                                                 if ((r3 = data[pix-=4] - data2[pix]) < 0)
555                                                         data2[pix] = -r3;
556                                                 else
557                                                         data2[pix] = r3;
558                                                 if ((g3 = data[pix1=pix+1] - data2[pix1]) < 0)
559                                                         data2[pix1] = -g3;
560                                                 else
561                                                         data2[pix1] = g3;
562                                                 if ((b3 = data[pix2=pix+2] - data2[pix2]) < 0)
563                                                         data2[pix2] = -b3;
564                                                 else
565                                                         data2[pix2] = b3;
566                                         }
567                                         dataChanged = true;
568                                         break;
570                                 case "screen" : 
571                                         while (p--) {
572                                                 data2[pix-=4] = (255 - ( ((255-data2[pix])*(255-data[pix])) >> 8));
573                                                 data2[pix1=pix+1] = (255 - ( ((255-data2[pix1])*(255-data[pix1])) >> 8));
574                                                 data2[pix2=pix+2] = (255 - ( ((255-data2[pix2])*(255-data[pix2])) >> 8));
575                                         }
576                                         dataChanged = true;
577                                         break;
579                                 case "exclusion" : 
580                                         var div_2_255 = 2 / 255;
581                                         while (p--) {
582                                                 data2[pix-=4] = (r1 = data[pix]) - (r1 * div_2_255 - 1) * data2[pix];
583                                                 data2[pix1=pix+1] = (g1 = data[pix1]) - (g1 * div_2_255 - 1) * data2[pix1];
584                                                 data2[pix2=pix+2] = (b1 = data[pix2]) - (b1 * div_2_255 - 1) * data2[pix2];
585                                         }
586                                         dataChanged = true;
587                                         break;
589                                 case "overlay" : 
590                                         var div_2_255 = 2 / 255;
591                                         while (p--) {
592                                                 if ((r1 = data[pix-=4]) < 128)
593                                                         data2[pix] = data2[pix]*r1*div_2_255;
594                                                 else
595                                                         data2[pix] = 255 - (255-data2[pix])*(255-r1)*div_2_255;
597                                                 if ((g1 = data[pix1=pix+1]) < 128)
598                                                         data2[pix1] = data2[pix1]*g1*div_2_255;
599                                                 else
600                                                         data2[pix1] = 255 - (255-data2[pix1])*(255-g1)*div_2_255;
602                                                 if ((b1 = data[pix2=pix+2]) < 128)
603                                                         data2[pix2] = data2[pix2]*b1*div_2_255;
604                                                 else
605                                                         data2[pix2] = 255 - (255-data2[pix2])*(255-b1)*div_2_255;
607                                         }
608                                         dataChanged = true;
609                                         break;
611                                 case "softlight" : 
612                                         var div_2_255 = 2 / 255;
613                                         while (p--) {
614                                                 if ((r1 = data[pix-=4]) < 128)
615                                                         data2[pix] = ((data2[pix]>>1) + 64) * r1 * div_2_255;
616                                                 else
617                                                         data2[pix] = 255 - (191 - (data2[pix]>>1)) * (255-r1) * div_2_255;
619                                                 if ((g1 = data[pix1=pix+1]) < 128)
620                                                         data2[pix1] = ((data2[pix1]>>1)+64) * g1 * div_2_255;
621                                                 else
622                                                         data2[pix1] = 255 - (191 - (data2[pix1]>>1)) * (255-g1) * div_2_255;
624                                                 if ((b1 = data[pix2=pix+2]) < 128)
625                                                         data2[pix2] = ((data2[pix2]>>1)+64) * b1 * div_2_255;
626                                                 else
627                                                         data2[pix2] = 255 - (191 - (data2[pix2]>>1)) * (255-b1) * div_2_255;
629                                         }
630                                         dataChanged = true;
631                                         break;
633                                 case "hardlight" : 
634                                         var div_2_255 = 2 / 255;
635                                         while (p--) {
636                                                 if ((r2 = data2[pix-=4]) < 128)
637                                                         data2[pix] = data[pix] * r2 * div_2_255;
638                                                 else
639                                                         data2[pix] = 255 - (255-data[pix]) * (255-r2) * div_2_255;
641                                                 if ((g2 = data2[pix1=pix+1]) < 128)
642                                                         data2[pix1] = data[pix1] * g2 * div_2_255;
643                                                 else
644                                                         data2[pix1] = 255 - (255-data[pix1]) * (255-g2) * div_2_255;
646                                                 if ((b2 = data2[pix2=pix+2]) < 128)
647                                                         data2[pix2] = data[pix2] * b2 * div_2_255;
648                                                 else
649                                                         data2[pix2] = 255 - (255-data[pix2]) * (255-b2) * div_2_255;
651                                         }
652                                         dataChanged = true;
653                                         break;
655                                 case "colordodge" : 
656                                         while (p--) {
657                                                 if ((r3 = (data[pix-=4]<<8)/(255-(r2 = data2[pix]))) > 255 || r2 == 255)
658                                                         data2[pix] = 255;
659                                                 else
660                                                         data2[pix] = r3;
662                                                 if ((g3 = (data[pix1=pix+1]<<8)/(255-(g2 = data2[pix1]))) > 255 || g2 == 255)
663                                                         data2[pix1] = 255;
664                                                 else
665                                                         data2[pix1] = g3;
667                                                 if ((b3 = (data[pix2=pix+2]<<8)/(255-(b2 = data2[pix2]))) > 255 || b2 == 255)
668                                                         data2[pix2] = 255;
669                                                 else
670                                                         data2[pix2] = b3;
671                                         }
672                                         dataChanged = true;
673                                         break;
675                                 case "colorburn" : 
676                                         while (p--) {
677                                                 if ((r3 = 255-((255-data[pix-=4])<<8)/data2[pix]) < 0 || data2[pix] == 0)
678                                                         data2[pix] = 0;
679                                                 else
680                                                         data2[pix] = r3;
682                                                 if ((g3 = 255-((255-data[pix1=pix+1])<<8)/data2[pix1]) < 0 || data2[pix1] == 0)
683                                                         data2[pix1] = 0;
684                                                 else
685                                                         data2[pix1] = g3;
687                                                 if ((b3 = 255-((255-data[pix2=pix+2])<<8)/data2[pix2]) < 0 || data2[pix2] == 0)
688                                                         data2[pix2] = 0;
689                                                 else
690                                                         data2[pix2] = b3;
691                                         }
692                                         dataChanged = true;
693                                         break;
695                                 case "linearlight" : 
696                                         while (p--) {
697                                                 if ( ((r3 = 2*(r2=data2[pix-=4])+data[pix]-256) < 0) || (r2 < 128 && r3 < 0)) {
698                                                         data2[pix] = 0
699                                                 } else {
700                                                         if (r3 > 255)
701                                                                 data2[pix] = 255;
702                                                         else
703                                                                 data2[pix] = r3;
704                                                 }
705                                                 if ( ((g3 = 2*(g2=data2[pix1=pix+1])+data[pix1]-256) < 0) || (g2 < 128 && g3 < 0)) {
706                                                         data2[pix1] = 0
707                                                 } else {
708                                                         if (g3 > 255)
709                                                                 data2[pix1] = 255;
710                                                         else
711                                                                 data2[pix1] = g3;
712                                                 }
713                                                 if ( ((b3 = 2*(b2=data2[pix2=pix+2])+data[pix2]-256) < 0) || (b2 < 128 && b3 < 0)) {
714                                                         data2[pix2] = 0
715                                                 } else {
716                                                         if (b3 > 255)
717                                                                 data2[pix2] = 255;
718                                                         else
719                                                                 data2[pix2] = b3;
720                                                 }
721                                         }
722                                         dataChanged = true;
723                                         break;
725                                 case "vividlight" : 
726                                         while (p--) {
727                                                 if ((r2=data2[pix-=4]) < 128) {
728                                                         if (r2) {
729                                                                 if ((r3 = 255 - ((255-data[pix])<<8) / (2*r2)) < 0) 
730                                                                         data2[pix] = 0;
731                                                                 else
732                                                                         data2[pix] = r3
733                                                         } else {
734                                                                 data2[pix] = 0;
735                                                         }
736                                                 } else if ((r3 = (r4=2*r2-256)) < 255) {
737                                                         if ((r3 = (data[pix]<<8)/(255-r4)) > 255) 
738                                                                 data2[pix] = 255;
739                                                         else
740                                                                 data2[pix] = r3;
741                                                 } else {
742                                                         if (r3 < 0) 
743                                                                 data2[pix] = 0;
744                                                         else
745                                                                 data2[pix] = r3
746                                                 }
748                                                 if ((g2=data2[pix1=pix+1]) < 128) {
749                                                         if (g2) {
750                                                                 if ((g3 = 255 - ((255-data[pix1])<<8) / (2*g2)) < 0) 
751                                                                         data2[pix1] = 0;
752                                                                 else
753                                                                         data2[pix1] = g3;
754                                                         } else {
755                                                                 data2[pix1] = 0;
756                                                         }
757                                                 } else if ((g3 = (g4=2*g2-256)) < 255) {
758                                                         if ((g3 = (data[pix1]<<8)/(255-g4)) > 255)
759                                                                 data2[pix1] = 255;
760                                                         else
761                                                                 data2[pix1] = g3;
762                                                 } else {
763                                                         if (g3 < 0) 
764                                                                 data2[pix1] = 0;
765                                                         else
766                                                                 data2[pix1] = g3;
767                                                 }
769                                                 if ((b2=data2[pix2=pix+2]) < 128) {
770                                                         if (b2) {
771                                                                 if ((b3 = 255 - ((255-data[pix2])<<8) / (2*b2)) < 0) 
772                                                                         data2[pix2] = 0;
773                                                                 else
774                                                                         data2[pix2] = b3;
775                                                         } else {
776                                                                 data2[pix2] = 0;
777                                                         }
778                                                 } else if ((b3 = (b4=2*b2-256)) < 255) {
779                                                         if ((b3 = (data[pix2]<<8)/(255-b4)) > 255) 
780                                                                 data2[pix2] = 255;
781                                                         else
782                                                                 data2[pix2] = b3;
783                                                 } else {
784                                                         if (b3 < 0) 
785                                                                 data2[pix2] = 0;
786                                                         else
787                                                                 data2[pix2] = b3;
788                                                 }
789                                         }
790                                         dataChanged = true;
791                                         break;
793                                 case "pinlight" : 
794                                         while (p--) {
795                                                 if ((r2=data2[pix-=4]) < 128)
796                                                         if ((r1=data[pix]) < (r4=2*r2))
797                                                                 data2[pix] = r1;
798                                                         else
799                                                                 data2[pix] = r4;
800                                                 else
801                                                         if ((r1=data[pix]) > (r4=2*r2-256))
802                                                                 data2[pix] = r1;
803                                                         else
804                                                                 data2[pix] = r4;
806                                                 if ((g2=data2[pix1=pix+1]) < 128)
807                                                         if ((g1=data[pix1]) < (g4=2*g2))
808                                                                 data2[pix1] = g1;
809                                                         else
810                                                                 data2[pix1] = g4;
811                                                 else
812                                                         if ((g1=data[pix1]) > (g4=2*g2-256))
813                                                                 data2[pix1] = g1;
814                                                         else
815                                                                 data2[pix1] = g4;
817                                                 if ((r2=data2[pix2=pix+2]) < 128)
818                                                         if ((r1=data[pix2]) < (r4=2*r2))
819                                                                 data2[pix2] = r1;
820                                                         else
821                                                                 data2[pix2] = r4;
822                                                 else
823                                                         if ((r1=data[pix2]) > (r4=2*r2-256))
824                                                                 data2[pix2] = r1;
825                                                         else
826                                                                 data2[pix2] = r4;
827                                         }
828                                         dataChanged = true;
829                                         break;
831                                 case "hardmix" : 
832                                         while (p--) {
833                                                 if ((r2 = data2[pix-=4]) < 128)
834                                                         if (255 - ((255-data[pix])<<8)/(2*r2) < 128 || r2 == 0)
835                                                                 data2[pix] = 0;
836                                                         else
837                                                                 data2[pix] = 255;
838                                                 else if ((r4=2*r2-256) < 255 && (data[pix]<<8)/(255-r4) < 128)
839                                                         data2[pix] = 0;
840                                                 else
841                                                         data2[pix] = 255;
843                                                 if ((g2 = data2[pix1=pix+1]) < 128)
844                                                         if (255 - ((255-data[pix1])<<8)/(2*g2) < 128 || g2 == 0)
845                                                                 data2[pix1] = 0;
846                                                         else
847                                                                 data2[pix1] = 255;
848                                                 else if ((g4=2*g2-256) < 255 && (data[pix1]<<8)/(255-g4) < 128)
849                                                         data2[pix1] = 0;
850                                                 else
851                                                         data2[pix1] = 255;
853                                                 if ((b2 = data2[pix2=pix+2]) < 128)
854                                                         if (255 - ((255-data[pix2])<<8)/(2*b2) < 128 || b2 == 0)
855                                                                 data2[pix2] = 0;
856                                                         else
857                                                                 data2[pix2] = 255;
858                                                 else if ((b4=2*b2-256) < 255 && (data[pix2]<<8)/(255-b4) < 128)
859                                                         data2[pix2] = 0;
860                                                 else
861                                                         data2[pix2] = 255;
862                                         }
863                                         dataChanged = true;
864                                         break;
865                         }
867                         if (dataChanged) 
868                                 otherCtx.putImageData(dataDesc2,0,0);
870                         var ctx = params.canvas.getContext("2d");
871                         ctx.save();
872                         ctx.globalAlpha = amount;
873                         ctx.drawImage(
874                                 otherCanvas,
875                                 0,0,rect.width,rect.height,
876                                 rect.left,rect.top,rect.width,rect.height
877                         );
878                         ctx.globalAlpha = 1;
879                         ctx.restore();
881                         return true;
882                 }
883         },
884         checkSupport : function() {
885                 return Pixastic.Client.hasCanvasImageData();
886         }
888  * Pixastic Lib - Blur filter - v0.1.0
889  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
890  * License: [http://www.pixastic.com/lib/license.txt]
891  */
893 Pixastic.Actions.blur = {
894         process : function(params) {
896                 if (typeof params.options.fixMargin == "undefined")
897                         params.options.fixMargin = true;
899                 if (Pixastic.Client.hasCanvasImageData()) {
900                         var data = Pixastic.prepareData(params);
901                         var dataCopy = Pixastic.prepareData(params, true)
903                         /*
904                         var kernel = [
905                                 [0.5,   1,      0.5],
906                                 [1,     2,      1],
907                                 [0.5,   1,      0.5]
908                         ];
909                         */
911                         var kernel = [
912                                 [0,     1,      0],
913                                 [1,     2,      1],
914                                 [0,     1,      0]
915                         ];
917                         var weight = 0;
918                         for (var i=0;i<3;i++) {
919                                 for (var j=0;j<3;j++) {
920                                         weight += kernel[i][j];
921                                 }
922                         }
924                         weight = 1 / (weight*2);
926                         var rect = params.options.rect;
927                         var w = rect.width;
928                         var h = rect.height;
930                         var w4 = w*4;
931                         var y = h;
932                         do {
933                                 var offsetY = (y-1)*w4;
935                                 var prevY = (y == 1) ? 0 : y-2;
936                                 var nextY = (y == h) ? y - 1 : y;
938                                 var offsetYPrev = prevY*w*4;
939                                 var offsetYNext = nextY*w*4;
941                                 var x = w;
942                                 do {
943                                         var offset = offsetY + (x*4-4);
945                                         var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
946                                         var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
947         
948                                         data[offset] = (
949                                                 /*
950                                                 dataCopy[offsetPrev - 4]
951                                                 + dataCopy[offsetPrev+4] 
952                                                 + dataCopy[offsetNext - 4]
953                                                 + dataCopy[offsetNext+4]
954                                                 + 
955                                                 */
956                                                 (dataCopy[offsetPrev]
957                                                 + dataCopy[offset-4]
958                                                 + dataCopy[offset+4]
959                                                 + dataCopy[offsetNext])         * 2
960                                                 + dataCopy[offset]              * 4
961                                                 ) * weight;
963                                         data[offset+1] = (
964                                                 /*
965                                                 dataCopy[offsetPrev - 3]
966                                                 + dataCopy[offsetPrev+5] 
967                                                 + dataCopy[offsetNext - 3] 
968                                                 + dataCopy[offsetNext+5]
969                                                 + 
970                                                 */
971                                                 (dataCopy[offsetPrev+1]
972                                                 + dataCopy[offset-3]
973                                                 + dataCopy[offset+5]
974                                                 + dataCopy[offsetNext+1])       * 2
975                                                 + dataCopy[offset+1]            * 4
976                                                 ) * weight;
978                                         data[offset+2] = (
979                                                 /*
980                                                 dataCopy[offsetPrev - 2] 
981                                                 + dataCopy[offsetPrev+6] 
982                                                 + dataCopy[offsetNext - 2] 
983                                                 + dataCopy[offsetNext+6]
984                                                 + 
985                                                 */
986                                                 (dataCopy[offsetPrev+2]
987                                                 + dataCopy[offset-2]
988                                                 + dataCopy[offset+6]
989                                                 + dataCopy[offsetNext+2])       * 2
990                                                 + dataCopy[offset+2]            * 4
991                                                 ) * weight;
993                                 } while (--x);
994                         } while (--y);
996                         return true;
998                 } else if (Pixastic.Client.isIE()) {
999                         params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=1.5)";
1001                         if (params.options.fixMargin) {
1002                                 params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - 2 + "px";
1003                                 params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - 2 + "px";
1004                         }
1006                         return true;
1007                 }
1008         },
1009         checkSupport : function() {
1010                 return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
1011         }
1013  * Pixastic Lib - Blur Fast - v0.1.1
1014  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1015  * License: [http://www.pixastic.com/lib/license.txt]
1016  */
1018 Pixastic.Actions.blurfast = {
1019         process : function(params) {
1021                 var amount = parseFloat(params.options.amount)||0;
1022                 var clear = !!(params.options.clear && params.options.clear != "false");
1024                 amount = Math.max(0,Math.min(5,amount));
1026                 if (Pixastic.Client.hasCanvas()) {
1027                         var rect = params.options.rect;
1029                         var ctx = params.canvas.getContext("2d");
1030                         ctx.save();
1031                         ctx.beginPath();
1032                         ctx.rect(rect.left, rect.top, rect.width, rect.height);
1033                         ctx.clip();
1035                         var scale = 2;
1036                         var smallWidth = Math.round(params.width / scale);
1037                         var smallHeight = Math.round(params.height / scale);
1039                         var copy = document.createElement("canvas");
1040                         copy.width = smallWidth;
1041                         copy.height = smallHeight;
1043                         var clear = false;
1044                         var steps = Math.round(amount * 20);
1046                         var copyCtx = copy.getContext("2d");
1047                         for (var i=0;i<steps;i++) {
1048                                 var scaledWidth = Math.max(1,Math.round(smallWidth - i));
1049                                 var scaledHeight = Math.max(1,Math.round(smallHeight - i));
1050         
1051                                 copyCtx.clearRect(0,0,smallWidth,smallHeight);
1052         
1053                                 copyCtx.drawImage(
1054                                         params.canvas,
1055                                         0,0,params.width,params.height,
1056                                         0,0,scaledWidth,scaledHeight
1057                                 );
1058         
1059                                 if (clear)
1060                                         ctx.clearRect(rect.left,rect.top,rect.width,rect.height);
1061         
1062                                 ctx.drawImage(
1063                                         copy,
1064                                         0,0,scaledWidth,scaledHeight,
1065                                         0,0,params.width,params.height
1066                                 );
1067                         }
1069                         ctx.restore();
1071                         params.useData = false;
1072                         return true;
1073                 } else if (Pixastic.Client.isIE()) {
1074                         var radius = 10 * amount;
1075                         params.image.style.filter += " progid:DXImageTransform.Microsoft.Blur(pixelradius=" + radius + ")";
1077                         if (params.options.fixMargin || 1) {
1078                                 params.image.style.marginLeft = (parseInt(params.image.style.marginLeft,10)||0) - Math.round(radius) + "px";
1079                                 params.image.style.marginTop = (parseInt(params.image.style.marginTop,10)||0) - Math.round(radius) + "px";
1080                         }
1082                         return true;
1083                 }
1084         },
1085         checkSupport : function() {
1086                 return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
1087         }
1090  * Pixastic Lib - Brightness/Contrast filter - v0.1.1
1091  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1092  * License: [http://www.pixastic.com/lib/license.txt]
1093  */
1095 Pixastic.Actions.brightness = {
1097         process : function(params) {
1099                 var brightness = parseInt(params.options.brightness,10) || 0;
1100                 var contrast = parseFloat(params.options.contrast)||0;
1101                 var legacy = !!(params.options.legacy && params.options.legacy != "false");
1103                 if (legacy) {
1104                         brightness = Math.min(150,Math.max(-150,brightness));
1105                 } else {
1106                         var brightMul = 1 + Math.min(150,Math.max(-150,brightness)) / 150;
1107                 }
1108                 contrast = Math.max(0,contrast+1);
1110                 if (Pixastic.Client.hasCanvasImageData()) {
1111                         var data = Pixastic.prepareData(params);
1112                         var rect = params.options.rect;
1113                         var w = rect.width;
1114                         var h = rect.height;
1116                         var p = w*h;
1117                         var pix = p*4, pix1, pix2;
1119                         var mul, add;
1120                         if (contrast != 1) {
1121                                 if (legacy) {
1122                                         mul = contrast;
1123                                         add = (brightness - 128) * contrast + 128;
1124                                 } else {
1125                                         mul = brightMul * contrast;
1126                                         add = - contrast * 128 + 128;
1127                                 }
1128                         } else {  // this if-then is not necessary anymore, is it?
1129                                 if (legacy) {
1130                                         mul = 1;
1131                                         add = brightness;
1132                                 } else {
1133                                         mul = brightMul;
1134                                         add = 0;
1135                                 }
1136                         }
1137                         var r, g, b;
1138                         while (p--) {
1139                                 if ((r = data[pix-=4] * mul + add) > 255 )
1140                                         data[pix] = 255;
1141                                 else if (r < 0)
1142                                         data[pix] = 0;
1143                                 else
1144                                         data[pix] = r;
1146                                 if ((g = data[pix1=pix+1] * mul + add) > 255 ) 
1147                                         data[pix1] = 255;
1148                                 else if (g < 0)
1149                                         data[pix1] = 0;
1150                                 else
1151                                         data[pix1] = g;
1153                                 if ((b = data[pix2=pix+2] * mul + add) > 255 ) 
1154                                         data[pix2] = 255;
1155                                 else if (b < 0)
1156                                         data[pix2] = 0;
1157                                 else
1158                                         data[pix2] = b;
1159                         }
1160                         return true;
1161                 }
1162         },
1163         checkSupport : function() {
1164                 return Pixastic.Client.hasCanvasImageData();
1165         }
1169  * Pixastic Lib - Color adjust filter - v0.1.1
1170  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1171  * License: [http://www.pixastic.com/lib/license.txt]
1172  */
1174 Pixastic.Actions.coloradjust = {
1176         process : function(params) {
1177                 var red = parseFloat(params.options.red) || 0;
1178                 var green = parseFloat(params.options.green) || 0;
1179                 var blue = parseFloat(params.options.blue) || 0;
1181                 red = Math.round(red*255);
1182                 green = Math.round(green*255);
1183                 blue = Math.round(blue*255);
1185                 if (Pixastic.Client.hasCanvasImageData()) {
1186                         var data = Pixastic.prepareData(params);
1187                         var rect = params.options.rect;
1189                         var p = rect.width*rect.height;
1190                         var pix = p*4, pix1, pix2;
1192                         var r, g, b;
1193                         while (p--) {
1194                                 pix -= 4;
1196                                 if (red) {
1197                                         if ((r = data[pix] + red) < 0 ) 
1198                                                 data[pix] = 0;
1199                                         else if (r > 255 ) 
1200                                                 data[pix] = 255;
1201                                         else
1202                                                 data[pix] = r;
1203                                 }
1205                                 if (green) {
1206                                         if ((g = data[pix1=pix+1] + green) < 0 ) 
1207                                                 data[pix1] = 0;
1208                                         else if (g > 255 ) 
1209                                                 data[pix1] = 255;
1210                                         else
1211                                                 data[pix1] = g;
1212                                 }
1214                                 if (blue) {
1215                                         if ((b = data[pix2=pix+2] + blue) < 0 ) 
1216                                                 data[pix2] = 0;
1217                                         else if (b > 255 ) 
1218                                                 data[pix2] = 255;
1219                                         else
1220                                                 data[pix2] = b;
1221                                 }
1222                         }
1223                         return true;
1224                 }
1225         },
1226         checkSupport : function() {
1227                 return (Pixastic.Client.hasCanvasImageData());
1228         }
1231  * Pixastic Lib - Histogram - v0.1.0
1232  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1233  * License: [http://www.pixastic.com/lib/license.txt]
1234  */
1237 Pixastic.Actions.colorhistogram = {
1239         array256 : function(default_value) {
1240                 arr = [];
1241                 for (var i=0; i<256; i++) { arr[i] = default_value; }
1242                 return arr
1243         },
1245         process : function(params) {
1246                 var values = [];
1247                 if (typeof params.options.returnValue != "object") {
1248                         params.options.returnValue = {rvals:[], gvals:[], bvals:[]};
1249                 }
1250                 var paint = !!(params.options.paint);
1252                 var returnValue = params.options.returnValue;
1253                 if (typeof returnValue.values != "array") {
1254                         returnValue.rvals = [];
1255                         returnValue.gvals = [];
1256                         returnValue.bvals = [];
1257                 }
1259                 if (Pixastic.Client.hasCanvasImageData()) {
1260                         var data = Pixastic.prepareData(params);
1261                         params.useData = false;
1263                         var rvals = this.array256(0);
1264                         var gvals = this.array256(0);
1265                         var bvals = this.array256(0);
1267                         var rect = params.options.rect;
1269                         var p = rect.width*rect.height;
1270                         var pix = p*4;
1271                         while (p--) {
1272                                 rvals[data[pix-=4]]++;
1273                                 gvals[data[pix+1]]++;
1274                                 bvals[data[pix+2]]++;
1275                         }
1277                         returnValue.rvals = rvals;
1278                         returnValue.gvals = gvals;
1279                         returnValue.bvals = bvals;
1281                         if (paint) {
1282                                 var ctx = params.canvas.getContext("2d");
1283                                 var vals = [rvals, gvals, bvals];
1284                                 for (var v=0;v<3;v++) {
1285                                         var yoff = (v+1) * params.height / 3;
1286                                         var maxValue = 0;
1287                                         for (var i=0;i<256;i++) {
1288                                                 if (vals[v][i] > maxValue)
1289                                                         maxValue = vals[v][i];
1290                                         }
1291                                         var heightScale = params.height / 3 / maxValue;
1292                                         var widthScale = params.width / 256;
1293                                         if (v==0) ctx.fillStyle = "rgba(255,0,0,0.5)";
1294                                         else if (v==1) ctx.fillStyle = "rgba(0,255,0,0.5)";
1295                                         else if (v==2) ctx.fillStyle = "rgba(0,0,255,0.5)";
1296                                         for (var i=0;i<256;i++) {
1297                                                 ctx.fillRect(
1298                                                         i * widthScale, params.height - heightScale * vals[v][i] - params.height + yoff,
1299                                                         widthScale, vals[v][i] * heightScale
1300                                                 );
1301                                         }
1302                                 }
1303                         }
1304                         return true;
1305                 }
1306         },
1308         checkSupport : function() {
1309                 return Pixastic.Client.hasCanvasImageData();
1310         }
1312  * Pixastic Lib - Crop - v0.1.1
1313  * Copyright (c) 2008-2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1314  * License: [http://www.pixastic.com/lib/license.txt]
1315  */
1317 Pixastic.Actions.crop = {
1318         process : function(params) {
1319                 if (Pixastic.Client.hasCanvas()) {
1320                         var rect = params.options.rect;
1322                         var width = rect.width;
1323                         var height = rect.height;
1324                         var top = rect.top;
1325                         var left = rect.left;
1327                         if (typeof params.options.left != "undefined")
1328                                 left = parseInt(params.options.left,10);
1329                         if (typeof params.options.top != "undefined")
1330                                 top = parseInt(params.options.top,10);
1331                         if (typeof params.options.height != "undefined")
1332                                 width = parseInt(params.options.width,10);
1333                         if (typeof params.options.height != "undefined")
1334                                 height = parseInt(params.options.height,10);
1336                         if (left < 0) left = 0;
1337                         if (left > params.width-1) left = params.width-1;
1339                         if (top < 0) top = 0;
1340                         if (top > params.height-1) top = params.height-1;
1342                         if (width < 1) width = 1;
1343                         if (left + width > params.width)
1344                                 width = params.width - left;
1346                         if (height < 1) height = 1;
1347                         if (top + height > params.height)
1348                                 height = params.height - top;
1350                         var copy = document.createElement("canvas");
1351                         copy.width = params.width;
1352                         copy.height = params.height;
1353                         copy.getContext("2d").drawImage(params.canvas,0,0);
1355                         params.canvas.width = width;
1356                         params.canvas.height = height;
1357                         params.canvas.getContext("2d").clearRect(0,0,width,height);
1359                         params.canvas.getContext("2d").drawImage(copy,
1360                                 left,top,width,height,
1361                                 0,0,width,height
1362                         );
1364                         params.useData = false;
1365                         return true;
1366                 }
1367         },
1368         checkSupport : function() {
1369                 return Pixastic.Client.hasCanvas();
1370         }
1375  * Pixastic Lib - Desaturation filter - v0.1.1
1376  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1377  * License: [http://www.pixastic.com/lib/license.txt]
1378  */
1380 Pixastic.Actions.desaturate = {
1382         process : function(params) {
1383                 var useAverage = !!(params.options.average && params.options.average != "false");
1385                 if (Pixastic.Client.hasCanvasImageData()) {
1386                         var data = Pixastic.prepareData(params);
1387                         var rect = params.options.rect;
1388                         var w = rect.width;
1389                         var h = rect.height;
1391                         var p = w*h;
1392                         var pix = p*4, pix1, pix2;
1394                         if (useAverage) {
1395                                 while (p--) 
1396                                         data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]+data[pix1]+data[pix2])/3
1397                         } else {
1398                                 while (p--)
1399                                         data[pix-=4] = data[pix1=pix+1] = data[pix2=pix+2] = (data[pix]*0.3 + data[pix1]*0.59 + data[pix2]*0.11);
1400                         }
1401                         return true;
1402                 } else if (Pixastic.Client.isIE()) {
1403                         params.image.style.filter += " gray";
1404                         return true;
1405                 }
1406         },
1407         checkSupport : function() {
1408                 return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
1409         }
1411  * Pixastic Lib - Edge detection filter - v0.1.1
1412  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1413  * License: [http://www.pixastic.com/lib/license.txt]
1414  */
1416 Pixastic.Actions.edges = {
1417         process : function(params) {
1419                 var mono = !!(params.options.mono && params.options.mono != "false");
1420                 var invert = !!(params.options.invert && params.options.invert != "false");
1422                 if (Pixastic.Client.hasCanvasImageData()) {
1423                         var data = Pixastic.prepareData(params);
1424                         var dataCopy = Pixastic.prepareData(params, true)
1426                         var c = -1/8;
1427                         var kernel = [
1428                                 [c,     c,      c],
1429                                 [c,     1,      c],
1430                                 [c,     c,      c]
1431                         ];
1433                         weight = 1/c;
1435                         var rect = params.options.rect;
1436                         var w = rect.width;
1437                         var h = rect.height;
1439                         var w4 = w*4;
1440                         var y = h;
1441                         do {
1442                                 var offsetY = (y-1)*w4;
1444                                 var nextY = (y == h) ? y - 1 : y;
1445                                 var prevY = (y == 1) ? 0 : y-2;
1447                                 var offsetYPrev = prevY*w*4;
1448                                 var offsetYNext = nextY*w*4;
1450                                 var x = w;
1451                                 do {
1452                                         var offset = offsetY + (x*4-4);
1454                                         var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
1455                                         var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
1456         
1457                                         var r = ((dataCopy[offsetPrev-4]
1458                                                 + dataCopy[offsetPrev]
1459                                                 + dataCopy[offsetPrev+4]
1460                                                 + dataCopy[offset-4]
1461                                                 + dataCopy[offset+4]
1462                                                 + dataCopy[offsetNext-4]
1463                                                 + dataCopy[offsetNext]
1464                                                 + dataCopy[offsetNext+4]) * c
1465                                                 + dataCopy[offset]
1466                                                 ) 
1467                                                 * weight;
1468         
1469                                         var g = ((dataCopy[offsetPrev-3]
1470                                                 + dataCopy[offsetPrev+1]
1471                                                 + dataCopy[offsetPrev+5]
1472                                                 + dataCopy[offset-3]
1473                                                 + dataCopy[offset+5]
1474                                                 + dataCopy[offsetNext-3]
1475                                                 + dataCopy[offsetNext+1]
1476                                                 + dataCopy[offsetNext+5]) * c
1477                                                 + dataCopy[offset+1])
1478                                                 * weight;
1479         
1480                                         var b = ((dataCopy[offsetPrev-2]
1481                                                 + dataCopy[offsetPrev+2]
1482                                                 + dataCopy[offsetPrev+6]
1483                                                 + dataCopy[offset-2]
1484                                                 + dataCopy[offset+6]
1485                                                 + dataCopy[offsetNext-2]
1486                                                 + dataCopy[offsetNext+2]
1487                                                 + dataCopy[offsetNext+6]) * c
1488                                                 + dataCopy[offset+2])
1489                                                 * weight;
1491                                         if (mono) {
1492                                                 var brightness = (r*0.3 + g*0.59 + b*0.11)||0;
1493                                                 if (invert) brightness = 255 - brightness;
1494                                                 if (brightness < 0 ) brightness = 0;
1495                                                 if (brightness > 255 ) brightness = 255;
1496                                                 r = g = b = brightness;
1497                                         } else {
1498                                                 if (invert) {
1499                                                         r = 255 - r;
1500                                                         g = 255 - g;
1501                                                         b = 255 - b;
1502                                                 }
1503                                                 if (r < 0 ) r = 0;
1504                                                 if (g < 0 ) g = 0;
1505                                                 if (b < 0 ) b = 0;
1506                                                 if (r > 255 ) r = 255;
1507                                                 if (g > 255 ) g = 255;
1508                                                 if (b > 255 ) b = 255;
1509                                         }
1511                                         data[offset] = r;
1512                                         data[offset+1] = g;
1513                                         data[offset+2] = b;
1515                                 } while (--x);
1516                         } while (--y);
1518                         return true;
1519                 }
1520         },
1521         checkSupport : function() {
1522                 return Pixastic.Client.hasCanvasImageData();
1523         }
1525  * Pixastic Lib - Edge detection 2 - v0.1.0
1526  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1527  * License: [http://www.pixastic.com/lib/license.txt]
1528  * 
1529  * Contribution by Oliver Hunt (http://nerget.com/, http://nerget.com/canvas/edgeDetection.js). Thanks Oliver!
1531  */
1533 Pixastic.Actions.edges2 = {
1534         process : function(params) {
1536                 if (Pixastic.Client.hasCanvasImageData()) {
1537                         var data = Pixastic.prepareData(params);
1538                         var dataCopy = Pixastic.prepareData(params, true)
1540                         var rect = params.options.rect;
1541                         var w = rect.width;
1542                         var h = rect.height;
1544                         var w4 = w * 4;
1545                         var pixel = w4 + 4; // Start at (1,1)
1546                         var hm1 = h - 1;
1547                         var wm1 = w - 1;
1548                         for (var y = 1; y < hm1; ++y) {
1549                                 // Prepare initial cached values for current row
1550                                 var centerRow = pixel - 4;
1551                                 var priorRow = centerRow - w4;
1552                                 var nextRow = centerRow + w4;
1553                                 
1554                                 var r1 = - dataCopy[priorRow]   - dataCopy[centerRow]   - dataCopy[nextRow];
1555                                 var g1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
1556                                 var b1 = - dataCopy[++priorRow] - dataCopy[++centerRow] - dataCopy[++nextRow];
1557                                 
1558                                 var rp = dataCopy[priorRow += 2];
1559                                 var gp = dataCopy[++priorRow];
1560                                 var bp = dataCopy[++priorRow];
1561                                 
1562                                 var rc = dataCopy[centerRow += 2];
1563                                 var gc = dataCopy[++centerRow];
1564                                 var bc = dataCopy[++centerRow];
1565                                 
1566                                 var rn = dataCopy[nextRow += 2];
1567                                 var gn = dataCopy[++nextRow];
1568                                 var bn = dataCopy[++nextRow];
1569                                 
1570                                 var r2 = - rp - rc - rn;
1571                                 var g2 = - gp - gc - gn;
1572                                 var b2 = - bp - bc - bn;
1573                                 
1574                                 // Main convolution loop
1575                                 for (var x = 1; x < wm1; ++x) {
1576                                         centerRow = pixel + 4;
1577                                         priorRow = centerRow - w4;
1578                                         nextRow = centerRow + w4;
1579                                         
1580                                         var r = 127 + r1 - rp - (rc * -8) - rn;
1581                                         var g = 127 + g1 - gp - (gc * -8) - gn;
1582                                         var b = 127 + b1 - bp - (bc * -8) - bn;
1583                                         
1584                                         r1 = r2;
1585                                         g1 = g2;
1586                                         b1 = b2;
1587                                         
1588                                         rp = dataCopy[  priorRow];
1589                                         gp = dataCopy[++priorRow];
1590                                         bp = dataCopy[++priorRow];
1591                                         
1592                                         rc = dataCopy[  centerRow];
1593                                         gc = dataCopy[++centerRow];
1594                                         bc = dataCopy[++centerRow];
1595                                         
1596                                         rn = dataCopy[  nextRow];
1597                                         gn = dataCopy[++nextRow];
1598                                         bn = dataCopy[++nextRow];
1599                                         
1600                                         r += (r2 = - rp - rc - rn);
1601                                         g += (g2 = - gp - gc - gn);
1602                                         b += (b2 = - bp - bc - bn);
1604                                         if (r > 255) r = 255;
1605                                         if (g > 255) g = 255;
1606                                         if (b > 255) b = 255;
1607                                         if (r < 0) r = 0;
1608                                         if (g < 0) g = 0;
1609                                         if (b < 0) b = 0;
1611                                         data[pixel] = r;
1612                                         data[++pixel] = g;
1613                                         data[++pixel] = b;
1614                                         //data[++pixel] = 255; // alpha
1616                                         pixel+=2;
1617                                 }
1618                                 pixel += 8;
1619                         }
1620                         return true;
1621                 }
1622         },
1623         checkSupport : function() {
1624                 return Pixastic.Client.hasCanvasImageData();
1625         }
1627  * Pixastic Lib - Emboss filter - v0.1.0
1628  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1629  * License: [http://www.pixastic.com/lib/license.txt]
1630  */
1632 Pixastic.Actions.emboss = {
1633         process : function(params) {
1635                 var strength = parseFloat(params.options.strength)||1;
1636                 var greyLevel = typeof params.options.greyLevel != "undefined" ? parseInt(params.options.greyLevel) : 180;
1637                 var direction = params.options.direction||"topleft";
1638                 var blend = !!(params.options.blend && params.options.blend != "false");
1640                 var dirY = 0;
1641                 var dirX = 0;
1643                 switch (direction) {
1644                         case "topleft":                 // top left
1645                                 dirY = -1;
1646                                 dirX = -1;
1647                                 break;
1648                         case "top":                     // top
1649                                 dirY = -1;
1650                                 dirX = 0;
1651                                 break;
1652                         case "topright":                        // top right
1653                                 dirY = -1;
1654                                 dirX = 1;
1655                                 break;
1656                         case "right":                   // right
1657                                 dirY = 0;
1658                                 dirX = 1;
1659                                 break;
1660                         case "bottomright":                     // bottom right
1661                                 dirY = 1;
1662                                 dirX = 1;
1663                                 break;
1664                         case "bottom":                  // bottom
1665                                 dirY = 1;
1666                                 dirX = 0;
1667                                 break;
1668                         case "bottomleft":                      // bottom left
1669                                 dirY = 1;
1670                                 dirX = -1;
1671                                 break;
1672                         case "left":                    // left
1673                                 dirY = 0;
1674                                 dirX = -1;
1675                                 break;
1676                 }
1678                 if (Pixastic.Client.hasCanvasImageData()) {
1679                         var data = Pixastic.prepareData(params);
1680                         var dataCopy = Pixastic.prepareData(params, true)
1682                         var invertAlpha = !!params.options.invertAlpha;
1683                         var rect = params.options.rect;
1684                         var w = rect.width;
1685                         var h = rect.height;
1687                         var w4 = w*4;
1688                         var y = h;
1689                         do {
1690                                 var offsetY = (y-1)*w4;
1692                                 var otherY = dirY;
1693                                 if (y + otherY < 1) otherY = 0;
1694                                 if (y + otherY > h) otherY = 0;
1696                                 var offsetYOther = (y-1+otherY)*w*4;
1698                                 var x = w;
1699                                 do {
1700                                                 var offset = offsetY + (x-1)*4;
1702                                                 var otherX = dirX;
1703                                                 if (x + otherX < 1) otherX = 0;
1704                                                 if (x + otherX > w) otherX = 0;
1706                                                 var offsetOther = offsetYOther + (x-1+otherX)*4;
1708                                                 var dR = dataCopy[offset] - dataCopy[offsetOther];
1709                                                 var dG = dataCopy[offset+1] - dataCopy[offsetOther+1];
1710                                                 var dB = dataCopy[offset+2] - dataCopy[offsetOther+2];
1712                                                 var dif = dR;
1713                                                 var absDif = dif > 0 ? dif : -dif;
1715                                                 var absG = dG > 0 ? dG : -dG;
1716                                                 var absB = dB > 0 ? dB : -dB;
1718                                                 if (absG > absDif) {
1719                                                         dif = dG;
1720                                                 }
1721                                                 if (absB > absDif) {
1722                                                         dif = dB;
1723                                                 }
1725                                                 dif *= strength;
1727                                                 if (blend) {
1728                                                         var r = data[offset] + dif;
1729                                                         var g = data[offset+1] + dif;
1730                                                         var b = data[offset+2] + dif;
1732                                                         data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);
1733                                                         data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);
1734                                                         data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);
1735                                                 } else {
1736                                                         var grey = greyLevel - dif;
1737                                                         if (grey < 0) {
1738                                                                 grey = 0;
1739                                                         } else if (grey > 255) {
1740                                                                 grey = 255;
1741                                                         }
1743                                                         data[offset] = data[offset+1] = data[offset+2] = grey;
1744                                                 }
1746                                 } while (--x);
1747                         } while (--y);
1748                         return true;
1750                 } else if (Pixastic.Client.isIE()) {
1751                         params.image.style.filter += " progid:DXImageTransform.Microsoft.emboss()";
1752                         return true;
1753                 }
1754         },
1755         checkSupport : function() {
1756                 return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
1757         }
1761  * Pixastic Lib - Flip - v0.1.0
1762  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1763  * License: [http://www.pixastic.com/lib/license.txt]
1764  */
1766 Pixastic.Actions.flip = {
1767         process : function(params) {
1768                 var rect = params.options.rect;
1769                 var copyCanvas = document.createElement("canvas");
1770                 copyCanvas.width = rect.width;
1771                 copyCanvas.height = rect.height;
1772                 copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
1774                 var ctx = params.canvas.getContext("2d");
1775                 ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
1777                 if (params.options.axis == "horizontal") {
1778                         ctx.scale(-1,1);
1779                         ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
1780                 } else {
1781                         ctx.scale(1,-1);
1782                         ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
1783                 }
1785                 params.useData = false;
1787                 return true;            
1788         },
1789         checkSupport : function() {
1790                 return Pixastic.Client.hasCanvas();
1791         }
1795  * Pixastic Lib - Horizontal flip - v0.1.0
1796  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1797  * License: [http://www.pixastic.com/lib/license.txt]
1798  */
1800 Pixastic.Actions.fliph = {
1801         process : function(params) {
1802                 if (Pixastic.Client.hasCanvas()) {
1803                         var rect = params.options.rect;
1804                         var copyCanvas = document.createElement("canvas");
1805                         copyCanvas.width = rect.width;
1806                         copyCanvas.height = rect.height;
1807                         copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
1809                         var ctx = params.canvas.getContext("2d");
1810                         ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
1811                         ctx.scale(-1,1);
1812                         ctx.drawImage(copyCanvas, -rect.left-rect.width, rect.top, rect.width, rect.height)
1813                         params.useData = false;
1815                         return true;            
1817                 } else if (Pixastic.Client.isIE()) {
1818                         params.image.style.filter += " fliph";
1819                         return true;
1820                 }
1821         },
1822         checkSupport : function() {
1823                 return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
1824         }
1828  * Pixastic Lib - Vertical flip - v0.1.0
1829  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1830  * License: [http://www.pixastic.com/lib/license.txt]
1831  */
1833 Pixastic.Actions.flipv = {
1834         process : function(params) {
1835                 if (Pixastic.Client.hasCanvas()) {
1836                         var rect = params.options.rect;
1837                         var copyCanvas = document.createElement("canvas");
1838                         copyCanvas.width = rect.width;
1839                         copyCanvas.height = rect.height;
1840                         copyCanvas.getContext("2d").drawImage(params.image, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
1842                         var ctx = params.canvas.getContext("2d");
1843                         ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
1844                         ctx.scale(1,-1);
1845                         ctx.drawImage(copyCanvas, rect.left, -rect.top-rect.height, rect.width, rect.height)
1846                         params.useData = false;
1848                         return true;            
1850                 } else if (Pixastic.Client.isIE()) {
1851                         params.image.style.filter += " flipv";
1852                         return true;
1853                 }
1854         },
1855         checkSupport : function() {
1856                 return (Pixastic.Client.hasCanvas() || Pixastic.Client.isIE());
1857         }
1861  * Pixastic Lib - Glow - v0.1.0
1862  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1863  * License: [http://www.pixastic.com/lib/license.txt]
1864  */
1867 Pixastic.Actions.glow = {
1868         process : function(params) {
1870                 var amount = (parseFloat(params.options.amount)||0);
1871                 var blurAmount = parseFloat(params.options.radius)||0;
1873                 amount = Math.min(1,Math.max(0,amount));
1874                 blurAmount = Math.min(5,Math.max(0,blurAmount));
1876                 if (Pixastic.Client.hasCanvasImageData()) {
1877                         var rect = params.options.rect;
1879                         var blurCanvas = document.createElement("canvas");
1880                         blurCanvas.width = params.width;
1881                         blurCanvas.height = params.height;
1882                         var blurCtx = blurCanvas.getContext("2d");
1883                         blurCtx.drawImage(params.canvas,0,0);
1885                         var scale = 2;
1886                         var smallWidth = Math.round(params.width / scale);
1887                         var smallHeight = Math.round(params.height / scale);
1889                         var copy = document.createElement("canvas");
1890                         copy.width = smallWidth;
1891                         copy.height = smallHeight;
1893                         var clear = true;
1894                         var steps = Math.round(blurAmount * 20);
1896                         var copyCtx = copy.getContext("2d");
1897                         for (var i=0;i<steps;i++) {
1898                                 var scaledWidth = Math.max(1,Math.round(smallWidth - i));
1899                                 var scaledHeight = Math.max(1,Math.round(smallHeight - i));
1900         
1901                                 copyCtx.clearRect(0,0,smallWidth,smallHeight);
1902         
1903                                 copyCtx.drawImage(
1904                                         blurCanvas,
1905                                         0,0,params.width,params.height,
1906                                         0,0,scaledWidth,scaledHeight
1907                                 );
1908         
1909                                 blurCtx.clearRect(0,0,params.width,params.height);
1910         
1911                                 blurCtx.drawImage(
1912                                         copy,
1913                                         0,0,scaledWidth,scaledHeight,
1914                                         0,0,params.width,params.height
1915                                 );
1916                         }
1918                         var data = Pixastic.prepareData(params);
1919                         var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
1920                         var w = rect.width;
1921                         var h = rect.height;
1922                         var w4 = w*4;
1923                         var y = h;
1924                         do {
1925                                 var offsetY = (y-1)*w4;
1926                                 var x = w;
1927                                 do {
1928                                         var offset = offsetY + (x*4-4);
1930                                         var r = data[offset] + amount * blurData[offset];
1931                                         var g = data[offset+1] + amount * blurData[offset+1];
1932                                         var b = data[offset+2] + amount * blurData[offset+2];
1933         
1934                                         if (r > 255) r = 255;
1935                                         if (g > 255) g = 255;
1936                                         if (b > 255) b = 255;
1937                                         if (r < 0) r = 0;
1938                                         if (g < 0) g = 0;
1939                                         if (b < 0) b = 0;
1941                                         data[offset] = r;
1942                                         data[offset+1] = g;
1943                                         data[offset+2] = b;
1945                                 } while (--x);
1946                         } while (--y);
1948                         return true;
1949                 }
1950         },
1951         checkSupport : function() {
1952                 return Pixastic.Client.hasCanvasImageData();
1953         }
1959  * Pixastic Lib - Histogram - v0.1.0
1960  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
1961  * License: [http://www.pixastic.com/lib/license.txt]
1962  */
1964 Pixastic.Actions.histogram = {
1965         process : function(params) {
1967                 var average = !!(params.options.average && params.options.average != "false");
1968                 var paint = !!(params.options.paint && params.options.paint != "false");
1969                 var color = params.options.color || "rgba(255,255,255,0.5)";
1970                 var values = [];
1971                 if (typeof params.options.returnValue != "object") {
1972                         params.options.returnValue = {values:[]};
1973                 }
1974                 var returnValue = params.options.returnValue;
1975                 if (typeof returnValue.values != "array") {
1976                         returnValue.values = [];
1977                 }
1978                 values = returnValue.values;
1980                 if (Pixastic.Client.hasCanvasImageData()) {
1981                         var data = Pixastic.prepareData(params);
1982                         params.useData = false;
1984                         for (var i=0;i<256;i++) {
1985                                 values[i] = 0;
1986                         }
1988                         var rect = params.options.rect;
1989                         var w = rect.width;
1990                         var h = rect.height;
1991                         var w4 = w*4;
1992                         var y = h;
1993                         do {
1994                                 var offsetY = (y-1)*w4;
1995                                 var x = w;
1996                                 do {
1997                                         var offset = offsetY + (x*4-4);
1998                                         var brightness = average ? 
1999                                                 Math.round((data[offset]+data[offset+1]+data[offset+2])/3)
2000                                                 : Math.round(data[offset]*0.3 + data[offset+1]*0.59 + data[offset+2]*0.11);
2001                                         values[brightness]++;
2003                                 } while (--x);
2004                         } while (--y);
2006                         if (paint) {
2007                                 var maxValue = 0;
2008                                 for (var i=0;i<256;i++) {
2009                                         if (values[i] > maxValue) {
2010                                                 maxValue = values[i];
2011                                         }
2012                                 }
2013                                 var heightScale = params.height / maxValue;
2014                                 var widthScale = params.width / 256;
2015                                 var ctx = params.canvas.getContext("2d");
2016                                 ctx.fillStyle = color;
2017                                 for (var i=0;i<256;i++) {
2018                                         ctx.fillRect(
2019                                                 i * widthScale, params.height - heightScale * values[i],
2020                                                 widthScale, values[i] * heightScale
2021                                         );
2022                                 }
2023                         }
2025                         returnValue.values = values;
2027                         return true;
2028                 }
2029         },
2030         checkSupport : function() {
2031                 return Pixastic.Client.hasCanvasImageData();
2032         }
2035  * Pixastic Lib - HSL Adjust  - v0.1.0
2036  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2037  * License: [http://www.pixastic.com/lib/license.txt]
2038  */
2040 Pixastic.Actions.hsl = {
2041         process : function(params) {
2043                 var hue = parseInt(params.options.hue,10)||0;
2044                 var saturation = (parseInt(params.options.saturation,10)||0) / 100;
2045                 var lightness = (parseInt(params.options.lightness,10)||0) / 100;
2048                 // this seems to give the same result as Photoshop
2049                 if (saturation < 0) {
2050                         var satMul = 1+saturation;
2051                 } else {
2052                         var satMul = 1+saturation*2;
2053                 }
2055                 hue = (hue%360) / 360;
2056                 var hue6 = hue * 6;
2058                 var rgbDiv = 1 / 255;
2060                 var light255 = lightness * 255;
2061                 var lightp1 = 1 + lightness;
2062                 var lightm1 = 1 - lightness;
2063                 if (Pixastic.Client.hasCanvasImageData()) {
2064                         var data = Pixastic.prepareData(params);
2066                         var rect = params.options.rect;
2067                         var w = rect.width;
2068                         var h = rect.height;
2070                         var w4 = w*4;
2071                         var y = h;
2073                         do {
2074                                 var offsetY = (y-1)*w4;
2075                                 var x = w;
2076                                 do {
2077                                         var offset = offsetY + (x*4-4);
2079                                         var r = data[offset];
2080                                         var g = data[offset+1];
2081                                         var b = data[offset+2];
2083                                         if (hue != 0 || saturation != 0) {
2084                                                 // ok, here comes rgb to hsl + adjust + hsl to rgb, all in one jumbled mess. 
2085                                                 // It's not so pretty, but it's been optimized to get somewhat decent performance.
2086                                                 // The transforms were originally adapted from the ones found in Graphics Gems, but have been heavily modified.
2087                                                 var vs = r;
2088                                                 if (g > vs) vs = g;
2089                                                 if (b > vs) vs = b;
2090                                                 var ms = r;
2091                                                 if (g < ms) ms = g;
2092                                                 if (b < ms) ms = b;
2093                                                 var vm = (vs-ms);
2094                                                 var l = (ms+vs)/255 * 0.5;
2095                                                 if (l > 0) {
2096                                                         if (vm > 0) {
2097                                                                 if (l <= 0.5) {
2098                                                                         var s = vm / (vs+ms) * satMul;
2099                                                                         if (s > 1) s = 1;
2100                                                                         var v = (l * (1+s));
2101                                                                 } else {
2102                                                                         var s = vm / (510-vs-ms) * satMul;
2103                                                                         if (s > 1) s = 1;
2104                                                                         var v = (l+s - l*s);
2105                                                                 }
2106                                                                 if (r == vs) {
2107                                                                         if (g == ms)
2108                                                                                 var h = 5 + ((vs-b)/vm) + hue6;
2109                                                                         else
2110                                                                                 var h = 1 - ((vs-g)/vm) + hue6;
2111                                                                 } else if (g == vs) {
2112                                                                         if (b == ms)
2113                                                                                 var h = 1 + ((vs-r)/vm) + hue6;
2114                                                                         else
2115                                                                                 var h = 3 - ((vs-b)/vm) + hue6;
2116                                                                 } else {
2117                                                                         if (r == ms)
2118                                                                                 var h = 3 + ((vs-g)/vm) + hue6;
2119                                                                         else
2120                                                                                 var h = 5 - ((vs-r)/vm) + hue6;
2121                                                                 }
2122                                                                 if (h < 0) h+=6;
2123                                                                 if (h >= 6) h-=6;
2124                                                                 var m = (l+l-v);
2125                                                                 var sextant = h>>0;
2126                                                                 switch (sextant) {
2127                                                                         case 0: r = v*255; g = (m+((v-m)*(h-sextant)))*255; b = m*255; break;
2128                                                                         case 1: r = (v-((v-m)*(h-sextant)))*255; g = v*255; b = m*255; break;
2129                                                                         case 2: r = m*255; g = v*255; b = (m+((v-m)*(h-sextant)))*255; break;
2130                                                                         case 3: r = m*255; g = (v-((v-m)*(h-sextant)))*255; b = v*255; break;
2131                                                                         case 4: r = (m+((v-m)*(h-sextant)))*255; g = m*255; b = v*255; break;
2132                                                                         case 5: r = v*255; g = m*255; b = (v-((v-m)*(h-sextant)))*255; break;
2133                                                                 }
2134                                                         }
2135                                                 }
2136                                         }
2138                                         if (lightness < 0) {
2139                                                 r *= lightp1;
2140                                                 g *= lightp1;
2141                                                 b *= lightp1;
2142                                         } else if (lightness > 0) {
2143                                                 r = r * lightm1 + light255;
2144                                                 g = g * lightm1 + light255;
2145                                                 b = b * lightm1 + light255;
2146                                         }
2148                                         if (r < 0) r = 0;
2149                                         if (g < 0) g = 0;
2150                                         if (b < 0) b = 0;
2151                                         if (r > 255) r = 255;
2152                                         if (g > 255) g = 255;
2153                                         if (b > 255) b = 255;
2155                                         data[offset] = r;
2156                                         data[offset+1] = g;
2157                                         data[offset+2] = b;
2159                                 } while (--x);
2160                         } while (--y);
2161                         return true;
2162                 }
2163         },
2164         checkSupport : function() {
2165                 return Pixastic.Client.hasCanvasImageData();
2166         }
2170  * Pixastic Lib - Invert filter - v0.1.0
2171  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2172  * License: [http://www.pixastic.com/lib/license.txt]
2173  */
2175 Pixastic.Actions.invert = {
2176         process : function(params) {
2177                 if (Pixastic.Client.hasCanvasImageData()) {
2178                         var data = Pixastic.prepareData(params);
2180                         var invertAlpha = !!params.options.invertAlpha;
2181                         var rect = params.options.rect;
2182                         var w = rect.width;
2183                         var h = rect.height;
2185                         var w4 = w*4;
2186                         var y = h;
2187                         do {
2188                                 var offsetY = (y-1)*w4;
2189                                 var x = w;
2190                                 do {
2191                                         var offset = offsetY + (x-1)*4;
2192                                         data[offset] = 255 - data[offset];
2193                                         data[offset+1] = 255 - data[offset+1];
2194                                         data[offset+2] = 255 - data[offset+2];
2195                                         if (invertAlpha) data[offset+3] = 255 - data[offset+3];
2196                                 } while (--x);
2197                         } while (--y);
2199                         return true;
2200                 } else if (Pixastic.Client.isIE()) {
2201                         params.image.style.filter += " invert";
2202                         return true;
2203                 }
2204         },
2205         checkSupport : function() {
2206                 return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
2207         }
2210  * Pixastic Lib - Laplace filter - v0.1.0
2211  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2212  * License: [http://www.pixastic.com/lib/license.txt]
2213  */
2215 Pixastic.Actions.laplace = {
2216         process : function(params) {
2218                 var strength = 1.0;
2219                 var invert = !!(params.options.invert && params.options.invert != "false");
2220                 var contrast = parseFloat(params.options.edgeStrength)||0;
2222                 var greyLevel = parseInt(params.options.greyLevel)||0;
2224                 contrast = -contrast;
2226                 if (Pixastic.Client.hasCanvasImageData()) {
2227                         var data = Pixastic.prepareData(params);
2228                         var dataCopy = Pixastic.prepareData(params, true)
2230                         var kernel = [
2231                                 [-1,    -1,     -1],
2232                                 [-1,    8,      -1],
2233                                 [-1,    -1,     -1]
2234                         ];
2236                         var weight = 1/8;
2238                         var rect = params.options.rect;
2239                         var w = rect.width;
2240                         var h = rect.height;
2242                         var w4 = w*4;
2243                         var y = h;
2244                         do {
2245                                 var offsetY = (y-1)*w4;
2247                                 var nextY = (y == h) ? y - 1 : y;
2248                                 var prevY = (y == 1) ? 0 : y-2;
2250                                 var offsetYPrev = prevY*w*4;
2251                                 var offsetYNext = nextY*w*4;
2253                                 var x = w;
2254                                 do {
2255                                         var offset = offsetY + (x*4-4);
2257                                         var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
2258                                         var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
2259         
2260                                         var r = ((-dataCopy[offsetPrev-4]
2261                                                 - dataCopy[offsetPrev]
2262                                                 - dataCopy[offsetPrev+4]
2263                                                 - dataCopy[offset-4]
2264                                                 - dataCopy[offset+4]
2265                                                 - dataCopy[offsetNext-4]
2266                                                 - dataCopy[offsetNext]
2267                                                 - dataCopy[offsetNext+4])
2268                                                 + dataCopy[offset] * 8) 
2269                                                 * weight;
2270         
2271                                         var g = ((-dataCopy[offsetPrev-3]
2272                                                 - dataCopy[offsetPrev+1]
2273                                                 - dataCopy[offsetPrev+5]
2274                                                 - dataCopy[offset-3]
2275                                                 - dataCopy[offset+5]
2276                                                 - dataCopy[offsetNext-3]
2277                                                 - dataCopy[offsetNext+1]
2278                                                 - dataCopy[offsetNext+5])
2279                                                 + dataCopy[offset+1] * 8)
2280                                                 * weight;
2281         
2282                                         var b = ((-dataCopy[offsetPrev-2]
2283                                                 - dataCopy[offsetPrev+2]
2284                                                 - dataCopy[offsetPrev+6]
2285                                                 - dataCopy[offset-2]
2286                                                 - dataCopy[offset+6]
2287                                                 - dataCopy[offsetNext-2]
2288                                                 - dataCopy[offsetNext+2]
2289                                                 - dataCopy[offsetNext+6])
2290                                                 + dataCopy[offset+2] * 8)
2291                                                 * weight;
2293                                         var brightness = ((r + g + b)/3) + greyLevel;
2295                                         if (contrast != 0) {
2296                                                 if (brightness > 127) {
2297                                                         brightness += ((brightness + 1) - 128) * contrast;
2298                                                 } else if (brightness < 127) {
2299                                                         brightness -= (brightness + 1) * contrast;
2300                                                 }
2301                                         }
2302                                         if (invert) {
2303                                                 brightness = 255 - brightness;
2304                                         }
2305                                         if (brightness < 0 ) brightness = 0;
2306                                         if (brightness > 255 ) brightness = 255;
2308                                         data[offset] = data[offset+1] = data[offset+2] = brightness;
2310                                 } while (--x);
2311                         } while (--y);
2313                         return true;
2314                 }
2315         },
2316         checkSupport : function() {
2317                 return Pixastic.Client.hasCanvasImageData();
2318         }
2322  * Pixastic Lib - Lighten filter - v0.1.0
2323  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2324  * License: [http://www.pixastic.com/lib/license.txt]
2325  */
2327 Pixastic.Actions.lighten = {
2329         process : function(params) {
2330                 var amount = parseFloat(params.options.amount) || 0;
2332                 if (Pixastic.Client.hasCanvasImageData()) {
2333                         var data = Pixastic.prepareData(params);
2334                         var rect = params.options.rect;
2335                         var w = rect.width;
2336                         var h = rect.height;
2337                         var w4 = w*4;
2338                         var y = h;
2339                         do {
2340                                 var offsetY = (y-1)*w4;
2341                                 var x = w;
2342                                 do {
2343                                         var offset = offsetY + (x-1)*4;
2345                                         var r = data[offset];
2346                                         var g = data[offset+1];
2347                                         var b = data[offset+2];
2349                                         r += r*amount;
2350                                         g += g*amount;
2351                                         b += b*amount;
2353                                         if (r < 0 ) r = 0;
2354                                         if (g < 0 ) g = 0;
2355                                         if (b < 0 ) b = 0;
2356                                         if (r > 255 ) r = 255;
2357                                         if (g > 255 ) g = 255;
2358                                         if (b > 255 ) b = 255;
2360                                         data[offset] = r;
2361                                         data[offset+1] = g;
2362                                         data[offset+2] = b;
2364                                 } while (--x);
2365                         } while (--y);
2366                         return true;
2368                 } else if (Pixastic.Client.isIE()) {
2369                         var img = params.image;
2370                         if (amount < 0) {
2371                                 img.style.filter += " light()";
2372                                 img.filters[img.filters.length-1].addAmbient(
2373                                         255,255,255,
2374                                         100 * -amount
2375                                 );
2376                         } else if (amount > 0) {
2377                                 img.style.filter += " light()";
2378                                 img.filters[img.filters.length-1].addAmbient(
2379                                         255,255,255,
2380                                         100
2381                                 );
2382                                 img.filters[img.filters.length-1].addAmbient(
2383                                         255,255,255,
2384                                         100 * amount
2385                                 );
2386                         }
2387                         return true;
2388                 }
2389         },
2390         checkSupport : function() {
2391                 return (Pixastic.Client.hasCanvasImageData() || Pixastic.Client.isIE());
2392         }
2395  * Pixastic Lib - Mosaic filter - v0.1.0
2396  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2397  * License: [http://www.pixastic.com/lib/license.txt]
2398  */
2400 Pixastic.Actions.mosaic = {
2402         process : function(params) {
2403                 var blockSize = Math.max(1,parseInt(params.options.blockSize,10));
2405                 if (Pixastic.Client.hasCanvasImageData()) {
2406                         var rect = params.options.rect;
2407                         var w = rect.width;
2408                         var h = rect.height;
2409                         var w4 = w*4;
2410                         var y = h;
2412                         var ctx = params.canvas.getContext("2d");
2414                         var pixel = document.createElement("canvas");
2415                         pixel.width = pixel.height = 1;
2416                         var pixelCtx = pixel.getContext("2d");
2418                         var copy = document.createElement("canvas");
2419                         copy.width = w;
2420                         copy.height = h;
2421                         var copyCtx = copy.getContext("2d");
2422                         copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
2424                         for (var y=0;y<h;y+=blockSize) {
2425                                 for (var x=0;x<w;x+=blockSize) {
2426                                         var blockSizeX = blockSize;
2427                                         var blockSizeY = blockSize;
2428                 
2429                                         if (blockSizeX + x > w)
2430                                                 blockSizeX = w - x;
2431                                         if (blockSizeY + y > h)
2432                                                 blockSizeY = h - y;
2434                                         pixelCtx.drawImage(copy, x, y, blockSizeX, blockSizeY, 0, 0, 1, 1);
2435                                         var data = pixelCtx.getImageData(0,0,1,1).data;
2436                                         ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
2437                                         ctx.fillRect(rect.left + x, rect.top + y, blockSize, blockSize);
2438                                 }
2439                         }
2440                         params.useData = false;
2442                         return true;
2443                 }
2444         },
2445         checkSupport : function() {
2446                 return (Pixastic.Client.hasCanvasImageData());
2447         }
2449  * Pixastic Lib - Noise filter - v0.1.0
2450  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2451  * License: [http://www.pixastic.com/lib/license.txt]
2452  */
2454 Pixastic.Actions.noise = {
2456         process : function(params) {
2457                 var amount = 0;
2458                 var strength = 0;
2459                 var mono = false;
2461                 if (typeof params.options.amount != "undefined")
2462                         amount = parseFloat(params.options.amount)||0;
2463                 if (typeof params.options.strength != "undefined")
2464                         strength = parseFloat(params.options.strength)||0;
2465                 if (typeof params.options.mono != "undefined")
2466                         mono = !!(params.options.mono && params.options.mono != "false");
2468                 amount = Math.max(0,Math.min(1,amount));
2469                 strength = Math.max(0,Math.min(1,strength));
2471                 var noise = 128 * strength;
2472                 var noise2 = noise / 2;
2474                 if (Pixastic.Client.hasCanvasImageData()) {
2475                         var data = Pixastic.prepareData(params);
2476                         var rect = params.options.rect;
2477                         var w = rect.width;
2478                         var h = rect.height;
2479                         var w4 = w*4;
2480                         var y = h;
2481                         var random = Math.random;
2483                         do {
2484                                 var offsetY = (y-1)*w4;
2485                                 var x = w;
2486                                 do {
2487                                         var offset = offsetY + (x-1)*4;
2488                                         if (random() < amount) {
2489                                                 if (mono) {
2490                                                         var pixelNoise = - noise2 + random() * noise;
2491                                                         var r = data[offset] + pixelNoise;
2492                                                         var g = data[offset+1] + pixelNoise;
2493                                                         var b = data[offset+2] + pixelNoise;
2494                                                 } else {
2495                                                         var r = data[offset] - noise2 + (random() * noise);
2496                                                         var g = data[offset+1] - noise2 + (random() * noise);
2497                                                         var b = data[offset+2] - noise2 + (random() * noise);
2498                                                 }
2500                                                 if (r < 0 ) r = 0;
2501                                                 if (g < 0 ) g = 0;
2502                                                 if (b < 0 ) b = 0;
2503                                                 if (r > 255 ) r = 255;
2504                                                 if (g > 255 ) g = 255;
2505                                                 if (b > 255 ) b = 255;
2507                                                 data[offset] = r;
2508                                                 data[offset+1] = g;
2509                                                 data[offset+2] = b;
2510                                         }
2511                                 } while (--x);
2512                         } while (--y);
2513                         return true;
2514                 }
2515         },
2516         checkSupport : function() {
2517                 return Pixastic.Client.hasCanvasImageData();
2518         }
2522  * Pixastic Lib - Posterize effect - v0.1.0
2523  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2524  * License: [http://www.pixastic.com/lib/license.txt]
2525  */
2527 Pixastic.Actions.posterize = {
2529         process : function(params) {
2531                 
2532                 var numLevels = 256;
2533                 if (typeof params.options.levels != "undefined")
2534                         numLevels = parseInt(params.options.levels,10)||1;
2536                 if (Pixastic.Client.hasCanvasImageData()) {
2537                         var data = Pixastic.prepareData(params);
2539                         numLevels = Math.max(2,Math.min(256,numLevels));
2540         
2541                         var numAreas = 256 / numLevels;
2542                         var numValues = 256 / (numLevels-1);
2544                         var rect = params.options.rect;
2545                         var w = rect.width;
2546                         var h = rect.height;
2547                         var w4 = w*4;
2548                         var y = h;
2549                         do {
2550                                 var offsetY = (y-1)*w4;
2551                                 var x = w;
2552                                 do {
2553                                         var offset = offsetY + (x-1)*4;
2555                                         var r = numValues * ((data[offset] / numAreas)>>0);
2556                                         var g = numValues * ((data[offset+1] / numAreas)>>0);
2557                                         var b = numValues * ((data[offset+2] / numAreas)>>0);
2559                                         if (r > 255) r = 255;
2560                                         if (g > 255) g = 255;
2561                                         if (b > 255) b = 255;
2563                                         data[offset] = r;
2564                                         data[offset+1] = g;
2565                                         data[offset+2] = b;
2567                                 } while (--x);
2568                         } while (--y);
2569                         return true;
2570                 }
2571         },
2572         checkSupport : function() {
2573                 return Pixastic.Client.hasCanvasImageData();
2574         }
2579  * Pixastic Lib - Pointillize filter - v0.1.0
2580  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2581  * License: [http://www.pixastic.com/lib/license.txt]
2582  */
2584 Pixastic.Actions.pointillize = {
2586         process : function(params) {
2587                 var radius = Math.max(1,parseInt(params.options.radius,10));
2588                 var density = Math.min(5,Math.max(0,parseFloat(params.options.density)||0));
2589                 var noise = Math.max(0,parseFloat(params.options.noise)||0);
2590                 var transparent = !!(params.options.transparent && params.options.transparent != "false");
2592                 if (Pixastic.Client.hasCanvasImageData()) {
2593                         var rect = params.options.rect;
2594                         var w = rect.width;
2595                         var h = rect.height;
2596                         var w4 = w*4;
2597                         var y = h;
2599                         var ctx = params.canvas.getContext("2d");
2600                         var canvasWidth = params.canvas.width;
2601                         var canvasHeight = params.canvas.height;
2603                         var pixel = document.createElement("canvas");
2604                         pixel.width = pixel.height = 1;
2605                         var pixelCtx = pixel.getContext("2d");
2607                         var copy = document.createElement("canvas");
2608                         copy.width = w;
2609                         copy.height = h;
2610                         var copyCtx = copy.getContext("2d");
2611                         copyCtx.drawImage(params.canvas,rect.left,rect.top,w,h, 0,0,w,h);
2613                         var diameter = radius * 2;
2615                         if (transparent)
2616                                 ctx.clearRect(rect.left, rect.top, rect.width, rect.height);
2618                         var noiseRadius = radius * noise;
2620                         var dist = 1 / density;
2622                         for (var y=0;y<h+radius;y+=diameter*dist) {
2623                                 for (var x=0;x<w+radius;x+=diameter*dist) {
2624                                         rndX = noise ? (x+((Math.random()*2-1) * noiseRadius))>>0 : x;
2625                                         rndY = noise ? (y+((Math.random()*2-1) * noiseRadius))>>0 : y;
2627                                         var pixX = rndX - radius;
2628                                         var pixY = rndY - radius;
2629                                         if (pixX < 0) pixX = 0;
2630                                         if (pixY < 0) pixY = 0;
2632                                         var cx = rndX + rect.left;
2633                                         var cy = rndY + rect.top;
2634                                         if (cx < 0) cx = 0;
2635                                         if (cx > canvasWidth) cx = canvasWidth;
2636                                         if (cy < 0) cy = 0;
2637                                         if (cy > canvasHeight) cy = canvasHeight;
2639                                         var diameterX = diameter;
2640                                         var diameterY = diameter;
2642                                         if (diameterX + pixX > w)
2643                                                 diameterX = w - pixX;
2644                                         if (diameterY + pixY > h)
2645                                                 diameterY = h - pixY;
2646                                         if (diameterX < 1) diameterX = 1;
2647                                         if (diameterY < 1) diameterY = 1;
2649                                         pixelCtx.drawImage(copy, pixX, pixY, diameterX, diameterY, 0, 0, 1, 1);
2650                                         var data = pixelCtx.getImageData(0,0,1,1).data;
2652                                         ctx.fillStyle = "rgb(" + data[0] + "," + data[1] + "," + data[2] + ")";
2653                                         ctx.beginPath();
2654                                         ctx.arc(cx, cy, radius, 0, Math.PI*2, true);
2655                                         ctx.closePath();
2656                                         ctx.fill();
2657                                 }
2658                         }
2660                         params.useData = false;
2662                         return true;
2663                 }
2664         },
2665         checkSupport : function() {
2666                 return (Pixastic.Client.hasCanvasImageData());
2667         }
2669  * Pixastic Lib - Resize - v0.1.0
2670  * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2671  * License: [http://www.pixastic.com/lib/license.txt]
2672  */
2674 Pixastic.Actions.resize = {
2675         process : function(params) {
2676                 if (Pixastic.Client.hasCanvas()) {
2677                         var width = parseInt(params.options.width,10);
2678                         var height = parseInt(params.options.height,10);
2679                         var canvas = params.canvas;
2681                         if (width < 1) width = 1;
2682                         if (width < 2) width = 2;
2684                         var copy = document.createElement("canvas");
2685                         copy.width = width;
2686                         copy.height = height;
2688                         copy.getContext("2d").drawImage(canvas,0,0,width,height);
2689                         canvas.width = width;
2690                         canvas.height = height;
2692                         canvas.getContext("2d").drawImage(copy,0,0);
2694                         params.useData = false;
2695                         return true;
2696                 }
2697         },
2698         checkSupport : function() {
2699                 return Pixastic.Client.hasCanvas();
2700         }
2705  * Pixastic Lib - Remove noise - v0.1.0
2706  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2707  * License: [http://www.pixastic.com/lib/license.txt]
2708  */
2710 Pixastic.Actions.removenoise = {
2711         process : function(params) {
2713                 if (Pixastic.Client.hasCanvasImageData()) {
2714                         var data = Pixastic.prepareData(params);
2716                         var rect = params.options.rect;
2717                         var w = rect.width;
2718                         var h = rect.height;
2720                         var w4 = w*4;
2721                         var y = h;
2722                         do {
2723                                 var offsetY = (y-1)*w4;
2725                                 var nextY = (y == h) ? y - 1 : y;
2726                                 var prevY = (y == 1) ? 0 : y-2;
2728                                 var offsetYPrev = prevY*w*4;
2729                                 var offsetYNext = nextY*w*4;
2731                                 var x = w;
2732                                 do {
2733                                         var offset = offsetY + (x*4-4);
2735                                         var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
2736                                         var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
2738                                         var minR, maxR, minG, maxG, minB, maxB;
2740                                         minR = maxR = data[offsetPrev];
2741                                         var r1 = data[offset-4], r2 = data[offset+4], r3 = data[offsetNext];
2742                                         if (r1 < minR) minR = r1;
2743                                         if (r2 < minR) minR = r2;
2744                                         if (r3 < minR) minR = r3;
2745                                         if (r1 > maxR) maxR = r1;
2746                                         if (r2 > maxR) maxR = r2;
2747                                         if (r3 > maxR) maxR = r3;
2749                                         minG = maxG = data[offsetPrev+1];
2750                                         var g1 = data[offset-3], g2 = data[offset+5], g3 = data[offsetNext+1];
2751                                         if (g1 < minG) minG = g1;
2752                                         if (g2 < minG) minG = g2;
2753                                         if (g3 < minG) minG = g3;
2754                                         if (g1 > maxG) maxG = g1;
2755                                         if (g2 > maxG) maxG = g2;
2756                                         if (g3 > maxG) maxG = g3;
2758                                         minB = maxB = data[offsetPrev+2];
2759                                         var b1 = data[offset-2], b2 = data[offset+6], b3 = data[offsetNext+2];
2760                                         if (b1 < minB) minB = b1;
2761                                         if (b2 < minB) minB = b2;
2762                                         if (b3 < minB) minB = b3;
2763                                         if (b1 > maxB) maxB = b1;
2764                                         if (b2 > maxB) maxB = b2;
2765                                         if (b3 > maxB) maxB = b3;
2767                                         if (data[offset] > maxR) {
2768                                                 data[offset] = maxR;
2769                                         } else if (data[offset] < minR) {
2770                                                 data[offset] = minR;
2771                                         }
2772                                         if (data[offset+1] > maxG) {
2773                                                 data[offset+1] = maxG;
2774                                         } else if (data[offset+1] < minG) {
2775                                                 data[offset+1] = minG;
2776                                         }
2777                                         if (data[offset+2] > maxB) {
2778                                                 data[offset+2] = maxB;
2779                                         } else if (data[offset+2] < minB) {
2780                                                 data[offset+2] = minB;
2781                                         }
2783                                 } while (--x);
2784                         } while (--y);
2786                         return true;
2787                 }
2788         },
2789         checkSupport : function() {
2790                 return Pixastic.Client.hasCanvasImageData();
2791         }
2793  * Pixastic Lib - Rotate - v0.1.0
2794  * Copyright (c) 2009 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2795  * License: [http://www.pixastic.com/lib/license.txt]
2796  */
2798 Pixastic.Actions.rotate = {
2799         process : function(params) {
2800                 if (Pixastic.Client.hasCanvas()) {
2801                         var canvas = params.canvas;
2803                         var width = params.width;
2804                         var height = params.height;
2806                         var copy = document.createElement("canvas");
2807                         copy.width = width;
2808                         copy.height = height;
2809                         copy.getContext("2d").drawImage(canvas,0,0,width,height);
2811                         var angle = -parseFloat(params.options.angle) * Math.PI / 180;
2813                         var dimAngle = angle;
2814                         if (dimAngle > Math.PI*0.5)
2815                                 dimAngle = Math.PI - dimAngle;
2816                         if (dimAngle < -Math.PI*0.5)
2817                                 dimAngle = -Math.PI - dimAngle;
2819                         var diag = Math.sqrt(width*width + height*height);
2821                         var diagAngle1 = Math.abs(dimAngle) - Math.abs(Math.atan2(height, width));
2822                         var diagAngle2 = Math.abs(dimAngle) + Math.abs(Math.atan2(height, width));
2824                         var newWidth = Math.abs(Math.cos(diagAngle1) * diag);
2825                         var newHeight = Math.abs(Math.sin(diagAngle2) * diag);
2827                         canvas.width = newWidth;
2828                         canvas.height = newHeight;
2830                         var ctx = canvas.getContext("2d");
2831                         ctx.translate(newWidth/2, newHeight/2);
2832                         ctx.rotate(angle);
2833                         ctx.drawImage(copy,-width/2,-height/2);
2835                         params.useData = false;
2836                         return true;
2837                 }
2838         },
2839         checkSupport : function() {
2840                 return Pixastic.Client.hasCanvas();
2841         }
2846  * Pixastic Lib - Sepia filter - v0.1.0
2847  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2848  * License: [http://www.pixastic.com/lib/license.txt]
2849  */
2851 Pixastic.Actions.sepia = {
2853         process : function(params) {
2854                 var mode = (parseInt(params.options.mode,10)||0);
2855                 if (mode < 0) mode = 0;
2856                 if (mode > 1) mode = 1;
2858                 if (Pixastic.Client.hasCanvasImageData()) {
2859                         var data = Pixastic.prepareData(params);
2860                         var rect = params.options.rect;
2861                         var w = rect.width;
2862                         var h = rect.height;
2863                         var w4 = w*4;
2864                         var y = h;
2865                         do {
2866                                 var offsetY = (y-1)*w4;
2867                                 var x = w;
2868                                 do {
2869                                         var offset = offsetY + (x-1)*4;
2871                                         if (mode) {
2872                                                 // a bit faster, but not as good
2873                                                 var d = data[offset] * 0.299 + data[offset+1] * 0.587 + data[offset+2] * 0.114;
2874                                                 var r = (d + 39);
2875                                                 var g = (d + 14);
2876                                                 var b = (d - 36);
2877                                         } else {
2878                                                 // Microsoft
2879                                                 var or = data[offset];
2880                                                 var og = data[offset+1];
2881                                                 var ob = data[offset+2];
2882         
2883                                                 var r = (or * 0.393 + og * 0.769 + ob * 0.189);
2884                                                 var g = (or * 0.349 + og * 0.686 + ob * 0.168);
2885                                                 var b = (or * 0.272 + og * 0.534 + ob * 0.131);
2886                                         }
2888                                         if (r < 0) r = 0; if (r > 255) r = 255;
2889                                         if (g < 0) g = 0; if (g > 255) g = 255;
2890                                         if (b < 0) b = 0; if (b > 255) b = 255;
2892                                         data[offset] = r;
2893                                         data[offset+1] = g;
2894                                         data[offset+2] = b;
2896                                 } while (--x);
2897                         } while (--y);
2898                         return true;
2899                 }
2900         },
2901         checkSupport : function() {
2902                 return Pixastic.Client.hasCanvasImageData();
2903         }
2905  * Pixastic Lib - Sharpen filter - v0.1.0
2906  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
2907  * License: [http://www.pixastic.com/lib/license.txt]
2908  */
2910 Pixastic.Actions.sharpen = {
2911         process : function(params) {
2913                 var strength = 0;
2914                 if (typeof params.options.amount != "undefined")
2915                         strength = parseFloat(params.options.amount)||0;
2917                 if (strength < 0) strength = 0;
2918                 if (strength > 1) strength = 1;
2920                 if (Pixastic.Client.hasCanvasImageData()) {
2921                         var data = Pixastic.prepareData(params);
2922                         var dataCopy = Pixastic.prepareData(params, true)
2924                         var mul = 15;
2925                         var mulOther = 1 + 3*strength;
2927                         var kernel = [
2928                                 [0,     -mulOther,      0],
2929                                 [-mulOther,     mul,    -mulOther],
2930                                 [0,     -mulOther,      0]
2931                         ];
2933                         var weight = 0;
2934                         for (var i=0;i<3;i++) {
2935                                 for (var j=0;j<3;j++) {
2936                                         weight += kernel[i][j];
2937                                 }
2938                         }
2940                         weight = 1 / weight;
2942                         var rect = params.options.rect;
2943                         var w = rect.width;
2944                         var h = rect.height;
2946                         mul *= weight;
2947                         mulOther *= weight;
2949                         var w4 = w*4;
2950                         var y = h;
2951                         do {
2952                                 var offsetY = (y-1)*w4;
2954                                 var nextY = (y == h) ? y - 1 : y;
2955                                 var prevY = (y == 1) ? 0 : y-2;
2957                                 var offsetYPrev = prevY*w4;
2958                                 var offsetYNext = nextY*w4;
2960                                 var x = w;
2961                                 do {
2962                                         var offset = offsetY + (x*4-4);
2964                                         var offsetPrev = offsetYPrev + ((x == 1) ? 0 : x-2) * 4;
2965                                         var offsetNext = offsetYNext + ((x == w) ? x-1 : x) * 4;
2967                                         var r = ((
2968                                                 - dataCopy[offsetPrev]
2969                                                 - dataCopy[offset-4]
2970                                                 - dataCopy[offset+4]
2971                                                 - dataCopy[offsetNext])         * mulOther
2972                                                 + dataCopy[offset]      * mul
2973                                                 );
2975                                         var g = ((
2976                                                 - dataCopy[offsetPrev+1]
2977                                                 - dataCopy[offset-3]
2978                                                 - dataCopy[offset+5]
2979                                                 - dataCopy[offsetNext+1])       * mulOther
2980                                                 + dataCopy[offset+1]    * mul
2981                                                 );
2983                                         var b = ((
2984                                                 - dataCopy[offsetPrev+2]
2985                                                 - dataCopy[offset-2]
2986                                                 - dataCopy[offset+6]
2987                                                 - dataCopy[offsetNext+2])       * mulOther
2988                                                 + dataCopy[offset+2]    * mul
2989                                                 );
2992                                         if (r < 0 ) r = 0;
2993                                         if (g < 0 ) g = 0;
2994                                         if (b < 0 ) b = 0;
2995                                         if (r > 255 ) r = 255;
2996                                         if (g > 255 ) g = 255;
2997                                         if (b > 255 ) b = 255;
2999                                         data[offset] = r;
3000                                         data[offset+1] = g;
3001                                         data[offset+2] = b;
3003                                 } while (--x);
3004                         } while (--y);
3006                         return true;
3008                 }
3009         },
3010         checkSupport : function() {
3011                 return Pixastic.Client.hasCanvasImageData();
3012         }
3015  * Pixastic Lib - Solarize filter - v0.1.0
3016  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
3017  * License: [http://www.pixastic.com/lib/license.txt]
3018  */
3020 Pixastic.Actions.solarize = {
3022         process : function(params) {
3023                 var useAverage = !!(params.options.average && params.options.average != "false");
3025                 if (Pixastic.Client.hasCanvasImageData()) {
3026                         var data = Pixastic.prepareData(params);
3027                         var rect = params.options.rect;
3028                         var w = rect.width;
3029                         var h = rect.height;
3030                         var w4 = w*4;
3031                         var y = h;
3032                         do {
3033                                 var offsetY = (y-1)*w4;
3034                                 var x = w;
3035                                 do {
3036                                         var offset = offsetY + (x-1)*4;
3038                                         var r = data[offset];
3039                                         var g = data[offset+1];
3040                                         var b = data[offset+2];
3042                                         if (r > 127) r = 255 - r;
3043                                         if (g > 127) g = 255 - g;
3044                                         if (b > 127) b = 255 - b;
3046                                         data[offset] = r;
3047                                         data[offset+1] = g;
3048                                         data[offset+2] = b;
3050                                 } while (--x);
3051                         } while (--y);
3052                         return true;
3053                 }
3054         },
3055         checkSupport : function() {
3056                 return (Pixastic.Client.hasCanvasImageData());
3057         }
3059  * Pixastic Lib - USM - v0.1.0
3060  * Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
3061  * License: [http://www.pixastic.com/lib/license.txt]
3062  */
3065 Pixastic.Actions.unsharpmask = {
3066         process : function(params) {
3068                 var amount = (parseFloat(params.options.amount)||0);
3069                 var blurAmount = parseFloat(params.options.radius)||0;
3070                 var threshold = parseFloat(params.options.threshold)||0;
3072                 amount = Math.min(500,Math.max(0,amount)) / 2;
3073                 blurAmount = Math.min(5,Math.max(0,blurAmount)) / 10;
3074                 threshold = Math.min(255,Math.max(0,threshold));
3076                 threshold--;
3077                 var thresholdNeg = -threshold;
3079                 amount *= 0.016;
3080                 amount++;
3082                 if (Pixastic.Client.hasCanvasImageData()) {
3083                         var rect = params.options.rect;
3085                         var blurCanvas = document.createElement("canvas");
3086                         blurCanvas.width = params.width;
3087                         blurCanvas.height = params.height;
3088                         var blurCtx = blurCanvas.getContext("2d");
3089                         blurCtx.drawImage(params.canvas,0,0);
3091                         var scale = 2;
3092                         var smallWidth = Math.round(params.width / scale);
3093                         var smallHeight = Math.round(params.height / scale);
3095                         var copy = document.createElement("canvas");
3096                         copy.width = smallWidth;
3097                         copy.height = smallHeight;
3099                         var steps = Math.round(blurAmount * 20);
3101                         var copyCtx = copy.getContext("2d");
3102                         for (var i=0;i<steps;i++) {
3103                                 var scaledWidth = Math.max(1,Math.round(smallWidth - i));
3104                                 var scaledHeight = Math.max(1,Math.round(smallHeight - i));
3106                                 copyCtx.clearRect(0,0,smallWidth,smallHeight);
3108                                 copyCtx.drawImage(
3109                                         blurCanvas,
3110                                         0,0,params.width,params.height,
3111                                         0,0,scaledWidth,scaledHeight
3112                                 );
3113         
3114                                 blurCtx.clearRect(0,0,params.width,params.height);
3115         
3116                                 blurCtx.drawImage(
3117                                         copy,
3118                                         0,0,scaledWidth,scaledHeight,
3119                                         0,0,params.width,params.height
3120                                 );
3121                         }
3123                         var data = Pixastic.prepareData(params);
3124                         var blurData = Pixastic.prepareData({canvas:blurCanvas,options:params.options});
3125                         var w = rect.width;
3126                         var h = rect.height;
3127                         var w4 = w*4;
3128                         var y = h;
3129                         do {
3130                                 var offsetY = (y-1)*w4;
3131                                 var x = w;
3132                                 do {
3133                                         var offset = offsetY + (x*4-4);
3135                                         var difR = data[offset] - blurData[offset];
3136                                         if (difR > threshold || difR < thresholdNeg) {
3137                                                 var blurR = blurData[offset];
3138                                                 blurR = amount * difR + blurR;
3139                                                 data[offset] = blurR > 255 ? 255 : (blurR < 0 ? 0 : blurR);
3140                                         }
3142                                         var difG = data[offset+1] - blurData[offset+1];
3143                                         if (difG > threshold || difG < thresholdNeg) {
3144                                                 var blurG = blurData[offset+1];
3145                                                 blurG = amount * difG + blurG;
3146                                                 data[offset+1] = blurG > 255 ? 255 : (blurG < 0 ? 0 : blurG);
3147                                         }
3149                                         var difB = data[offset+2] - blurData[offset+2];
3150                                         if (difB > threshold || difB < thresholdNeg) {
3151                                                 var blurB = blurData[offset+2];
3152                                                 blurB = amount * difB + blurB;
3153                                                 data[offset+2] = blurB > 255 ? 255 : (blurB < 0 ? 0 : blurB);
3154                                         }
3156                                 } while (--x);
3157                         } while (--y);
3159                         return true;
3160                 }
3161         },
3162         checkSupport : function() {
3163                 return Pixastic.Client.hasCanvasImageData();
3164         }