jswidget

Software Engineer/Web Application Developer. Skilled languages include in C++, C#, JAVA, PHP, JavaScript/AJAX. Certified DBA in Oracle and SQL Server 2005. Interested in implementing online version of some desktop applications using new HTML5 features. I really love programming, from C++, JAVA, C# to JavaScript. If you need a programmer to help on developing web based application, shoot me email to support@jswidget.com

# To understand recursion, see the bottom of this file 

 

/**
* For the brave souls who get this far: You are the chosen ones,
* the valiant knights of programming who toil away, without rest,
* fixing our most awful code. To you, true saviors, kings of men,
* I say this: never gonna give you up, never gonna let you down,
* never gonna run around and desert you. Never gonna make you cry,
* never gonna say goodbye. Never gonna tell a lie and hurt you.
*/

 

//
// Dear maintainer:
//
// Once you are done trying to 'optimize' this routine,
// and have realized what a terrible mistake that was,
// please increment the following counter as a warning
// to the next guy:
//
// total_hours_wasted_here = 39
// 
// I dedicate all this code, all my work, to my wife, Darlene, who will
// have to support me and our three children and the dog once it gets
// released into the public.
return 1; # returns 1
Catch (Exception e) {
 //who cares?
} 
/*
 * You may think you know what the following code does.
 * But you dont. Trust me.
 * Fiddle with it, and youll spend many a sleepless
 * night cursing the moment you thought youd be clever
 * enough to "optimize" the code below.
 * Now close this file and go play with something else.
 */ 
/* Please work */
//Dear future me. Please forgive me.
//I can't even begin to express how sorry I am.  
/* These magic numbers are fucking stupid. */

/* Dear free software world, do you NOW see we are fucking
   things up?! This is insane! */

/* We will NOT put a fucking timestamp in the header here. Every
   time you put it back, I will come in and take it out again. */

# However, this only works if there are MULTIPLE checkboxes!
# The fucking JS DOM *changes* based on one or multiple boxes!?!?!
# Damn damn damn I hate the JavaScript DOM so damn much!!!!!!

/* TODO: this is obviously not right ... this whole fucking module
   sucks anyway */

/* FIXME: please god, when will the hurting stop? Thus function is so
   fucking broken it's not even funny. */
# code below replaces code above - any problems?
 # yeah, it doesn't fucking work.
last = first; /* Biblical reference */
try {

}
catch (SQLException ex) {
    // Basically, without saying too much, you're screwed. Royally and totally.
}
catch(Exception ex)
{
    //If you thought you were screwed before, boy have I news for you!!!
}
// If you're reading this, that means you have been put in charge of my previous project.
// I am so, so sorry for you. God speed.
// If this code works, it was written by Paul DiLascia. If not, I don't know
// who wrote it
// The following strings are meant to be funny.  Do not edit these strings
// unless you are funny, too.  If you don't know if you're funny, you're
// not funny.  If fewer than 2 people unrelated to you have told you that
// you're funny, you're not funny.
$you = live("free") or die("hard");
stepOff(); //bitch
Catch (Exception e) {
    //eat it
}
// This should fix something that should never happen
// If I from the future read this I'll back in time and kill myself.
// This code was written by a genius so don't try to understand it with
// your tiny little brain.
/* Every time I re-visit this function, I feel like
 * I need to take a shower.
 *
 * Don't get too used to this function, its days are
 * numbered.
 */
		/************************************************************
		*                                                           *
		*  .=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-.       *
		*   |                     ______                     |      *
		*   |                  .-"      "-.                  |      *
		*   |                 /            \                 |      *
		*   |     _          |              |          _     |      *
		*   |    ( \         |,  .-.  .-.  ,|         / )    |      *
		*   |     > "=._     | )(__/  \__)( |     _.=" <     |      *
		*   |    (_/"=._"=._ |/     /\     \| _.="_.="\_)    |      *
		*   |           "=._"(_     ^^     _)"_.="           |      *
		*   |               "=\__|IIIIII|__/="               |      *
		*   |              _.="| \IIIIII/ |"=._              |      *
		*   |    _     _.="_.="\          /"=._"=._     _    |      *
		*   |   ( \_.="_.="     `--------`     "=._"=._/ )   |      *
		*   |    > _.="                            "=._ <    |      *
		*   |   (_/                                    \_)   |      *
		*   |                                                |      *
		*   '-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-='      *
		*                                                           *
		*      LASCIATE OGNI SPERANZA, VOI CH'ENTRATE               *
		*************************************************************/

So here comes:

# To understand recursion, see the top of this file

EasyComment is developed as a jQuery plugin to help you add comment function to your web page instantly. You can put EasyComment to any where within your web page, not only that, you can put as many EasyComments as you need within one web page. By simply specifying an element / or more elements as comment container, EasyComment will take care of all the rest of the works. EasyComment also contains a dashboard prototype for you to moderate user’s comments. If EasyComment is set to moderate, any new comment will be sent to your email box  for moderating before being viewed by other people. You can approve, trash or spam a comment. A spammer will be blocked to post any comments to your domain site.

To check out the source code and live demo, please check out http://www.jswidget.com/lab/easy-comment.html

 

ec

This is the continuation of my series regarding digital image blending algorithms. If you want to read other posts in this series, here is the list just for your convenient:

  1. Image Blending Algorithm–Part I
  2. Image Blending Algorithm–Part II
  3. Image Blending Algorithm–Part III
  4. Image Blending Algorithm–Part IV

This post will bring in four more image blending algorithms: Hue, Saturation, Color and Luminosity. These blending modes will use the color space convert algorithm introduced in RGB color model and HSL color model.

Before we start,  we need to modify a little bit to the generic function blending_canvas(canvas1,cavas2,blending_mode) to make sure it will handle the blending correctly. The reason is that the previous mentioned blending method processes the RGB channel individually and these four blending algorithms will need to convert the R, G, B value into H, S, L value. The new version will be modified as this:


// blend canvas1 to canvas2 using given blending_mode

function blending_canvas(canvas1, canvas2, blending_mode, flag){
   // Although it doesn't have to be, but for the sake of simplicity, let's assume
   // the two canvas must have same size;
   if ( canvas1.width != canvas2.width || canvas1.height != canvas2.height ){
      return canvas2;
   }
   var ctx1 = canvas1.getContext("2d"),
       ctx2 = canvas2.getContext("2d");
   var data1 = ctx1.getImageData(0,0,canvas1.width,canvas2.height).data;
   var imgData = ctx2.getImageData(0,0,canvas1.width,canvas2.height);
   var data2 = imgData.data;

   for ( var i = 0; i < data1.length; i += 4 ){

      if ( flag ){

          var newRGB = BLENDING_MACRO[blending_mode]({r:data1[i],g:data1[i+1],b:data1[i+2]},

                                                     {r:data2[i],g:data2[i+1],b:data2[i+2]}); 

          data2[i]     = newRGB.r;

          data2[i + 1] = newRGB.g;

          data2[i + 2] = newRGB.b;

      }else{
         //blending red channel
         data2[i]   = BLENDING_MACRO[blending_mode](data1[i],data2[i]);

         //blending green channel
         data2[i+1] = BLENDING_MACRO[blending_mode](data1[i],data2[i+1]);

         //blending blue channel
         data2[i+2] = BLENDING_MACRO[blending_mode](data1[i],data2[i+2]);

      }
   }

   ctx2.putImageData(imgData,0,0);

   return canvas2;
}

Ok, now we are ready to move on …

Blending Mode: Hue

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    hue:  function(v1,v2){
	   var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl2.s,hsl2.l);
          }
}

Now to apply the Hue blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"hue", true);

Blending Effect Screenshot taken from iPaintPro:

blending_hue
iPaintPro Image Blending: Hue
Blending Mode: Saturation

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    hue:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl2.s,hsl2.l);
          },
    saturation:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl2.h,hsl1.s,hsl2.l);
          }
}

Now to apply the Saturation blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"saturation", true);

Blending Effect Screenshot taken from iPaintPro:

blending_saturation
iPaintPro Image Blending: Saturation
Blending Mode: Color

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    hue:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl2.s,hsl2.l);
          },
    saturation:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl2.h,hsl1.s,hsl2.l);
          },
    color:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl1.s,hsl2.l);
          }
}

Now to apply the Color blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"color", true);

Blending Effect Screenshot taken from iPaintPro:

blending_color
iPaintPro Image Blending: Color
Blending Mode: Luminosity

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    hue:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl2.s,hsl2.l);
          },
    saturation:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl2.h,hsl1.s,hsl2.l);
          },
    color: function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl1.h,hsl1.s,hsl2.l);
          },
    luminosity:  function(v1,v2){
             var hsl1 = COLOR_SPACE.rgb2hsl(v1.r,v1.g,v1.b);
             var hsl2 = COLOR_SPACE.rgb2hsl(v2.r,v2.g,v2.b);
             return COLOR_SPACE.hsl2rgb(hsl2.h,hsl2.s,hsl1.l);
          }
}

Now to apply the Luminosity blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"luminosity", true);

Blending Effect Screenshot taken from iPaintPro:

blending_luminosity
iPaintPro Image Blending: Luminosity
Now we see all the blending modes we have been using in Adobe Photoshop. You can now easily embed those JavaScript codes into your project.

The RGB color model is an additive color model in which red, green, and blue light are added together to produce many other different colors.

Typically, each channel are represented in the range of 0×00-0xff.  In theory, there could be 256x256x256 different colors generated from this color model.

HSL color model is a common cylindrical-coordinate representations of points in an RGB color model. H stands for hue, people can understand hue as different colors, like red, green,blue or orange. S stands for saturation, we can understand saturation as adding gray onto colors. L stands for lightness, each color has it’s own lightness from darkest to brightest.

RGB and HSL color model are just two different representation models for digital device to understands color more easily. Usually there is no use to convert from one to other, however in some cases, we do need convert a color from RGB model to HSL model or vise versa. In Adobe Photoshop there are four color blending modes: hue,  saturation,  color and luminance which will require the color conversion first.

I will provide the source code to convert RGB color to HSL and HSL convert back to RGB. You will find these two static functions defined in COLOR_SPACE object will be used in the image blending algorithm later.

COLOR_SPACE.rgb2hsl = function(red,green,blue){
   var r = red, g = green, b = blue;
   var h, s, l;
   var min, max;
   var delta;

   if (r > g){
      max = Math.max (r, b);
      min = Math.min (g, b);
   }else{
      max = Math.max (g, b);
      min = Math.min (r, b);
   }

   l = (max + min) / 2.0;

   if (max == min){
      s = 0.0;
      h = 0.0;
   }else{
      delta = (max - min);

      if (l < 128){
         s = 255 * delta / (max + min);
      }else{
         s = 255 * delta / (511 - max - min);
      }
      if (r == max){
         h = (g - b) / delta;
      }else if (g == max){
         h = 2 + (b - r) / delta;
      }else{
         h = 4 + (r - g) / delta;
      }

      h = h * 42.5;

      if (h < 0){ h += 255; }
      else if (h > 255){ h -= 255; }
   }

   red   = Math.round (h);
   green = Math.round (s);
   blue  = Math.round (l);
   return {h:red,s:green,l:blue};
};
COLOR_SPACE.hsl2rgb = function(hue,saturation,lightness){
   var h = hue, s = saturation, l = lightness;

   if (s == 0){
      /*  achromatic case  */
      hue        = l;
      lightness  = l;
      saturation = l;
   }else{
      var m1, m2;

      if (l < 128){
         m2 = (l * (255 + s)) / 65025.0;
      }else{
         m2 = (l + s - (l * s) / 255.0) / 255.0;
      }
      m1 = (l / 127.5) - m2;

      /*  chromatic case  */
      hue        = COLOR_SPACE.hslValue (m1, m2, h + 85);
      saturation = COLOR_SPACE.hslValue (m1, m2, h);
      lightness  = COLOR_SPACE.hslValue (m1, m2, h - 85);
   }
   return {r:hue,g:saturation,b:lightness};
};

COLOR_SPACE.hslValue = function(n1,n2,hue){
   var value;

   if (hue > 255){ hue -= 255; }
   else if (hue < 0) { hue += 255; }

   if (hue < 42.5){
      value = n1 + (n2 - n1) * (hue / 42.5);
   }else if (hue < 127.5){
      value = n2;
   }else if (hue < 170){
      value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
   }else{
      value = n1;
   }
   return Math.round(value * 255.0);
};

This is the continuation of my series regarding digital image blending algorithms. If you want to read other posts in this series, here is the list just for your convenient:

  1. Image Blending Algorithm–Part I
  2. Image Blending Algorithm–Part II
  3. Image Blending Algorithm–Part III

This post will bring in four more image blending algorithms: Linear Light, Pin Light, Vivid Light, Hard Mix. These blending mode will use the previous introduced blending mode as sub-procedure.

Blending Mode: Linear Light

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    linearlight:  function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.linearburn(v2,(2 * v1))
                            : BLENDING_MACRO.lineardodge(v2,(2 * (v1 - 128)));
                  }
}

Now to apply the Linear Light blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"linearlight");

Blending Effect Screenshot taken from iPaintPro:

linearlight
iPaintPro Image Blending: Linear  Light
 
Blending Mode: Pin Light

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    linearlight:  function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.linearburn(v2,(2 * v1))
                            : BLENDING_MACRO.lineardodge(v2,(2 * (v1 - 128)));
                  },
    pinlight:     function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.darken(v2,(2 * v1))
                            : BLENDING_MACRO.lighten(v2,(2 * (v1 - 128)));
                  }
}

Now to apply the Pin Lightblending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"pinlight");

Blending Effect Screenshot taken from iPaintPro:

pinlight
iPaintPro Image Blending: Pin Light
 
Blending Mode: Vivid Light

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    linearlight:  function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.linearburn(v2,(2 * v1))
                            : BLENDING_MACRO.lineardodge(v2,(2 * (v1 - 128)));
                  },
    pinlight:     function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.darken(v2,(2 * v1))
                            : BLENDING_MACRO.lighten(v2,(2 * (v1 - 128)));
                  },
    vividlight:   function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.colorburn(v2,(2 * v1))
                            : BLENDING_MACRO.colordodge(v2,(2 * (v1 - 128)));
                  }
}

Now to apply the Vivid Light blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"vividlight");

Blending Effect Screenshot taken from iPaintPro:

vividlight
iPaintPro Image Blending: Vivid Light
 

Blending Mode: Hard Mix

Code Fragment:


//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    linearlight:  function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.linearburn(v2,(2 * v1))
                            : BLENDING_MACRO.lineardodge(v2,(2 * (v1 - 128)));
                  },
    pinlight:     function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.darken(v2,(2 * v1))
                            : BLENDING_MACRO.lighten(v2,(2 * (v1 - 128)));
                  },
    vividlight:   function(v1,v2){
                     return (v1 < 128)
                            ? BLENDING_MACRO.colorburn(v2,(2 * v1))
                            : BLENDING_MACRO.colordodge(v2,(2 * (v1 - 128)));
                  },
    hardmix:      function(v1,v2){
                     return (BLENDING_MACRO.vividlight(v1,v2) < 128) ? 0 : 255;
                  }
}

Now to apply the Hard Mix blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"hardmix");

Blending Effect Screenshot taken from iPaintPro:

hardmix
iPaintPro Image Blending: Hard Mix
 

So far all the blending modes we have talked all work in RGB color space. However there is another set of blending modes that using HSL color space will be introduced in another post, those are HUE, SATURATION,COLOR and LUMINOSITY

 
To be continued…

You do not have to have Mac machine and you do not have to join the Apple developer center, yet you can still develop apps for Apple’s i-devices. The following resources are great for beginners. The list will getting longer… …

HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript
Written by Matthew Might
 
How to Make an HTML5 iPhone App
Written by Alex Kessinger
 
iPhone events
 
Detecting iPhone’s App Mode (Full Screen Mode) For Web Applications
Quick Note:  Since iPhone/iPod touch gave different window size  when running in app mode and web mode, detecting the running mode of your site is necessary to help you layout your application correctly. When you are in app mode, you have a screen size of 320×460. When you are in web mode, it has a screen size of 320×356.
 
Web Development for the iPhone
Creating native looking iPhone web apps with CSS3 (no images)
Implementing doubletap on iPhones and iPads
Simple drag n drop Javascript for iPhone and iPad
Using CSS3 Transitions, Transforms and Animation
TouchScroll, a scrolling layer for WebKit mobile

jQuery Mobile, a touch-optimized web framework for smartphones & tablets were released Alpha 3 version. If you want your site looks and feels just like an touch-based app when accessed through mobile device, this framework will ease a lot of your pain.  The framework “increased our A-Grade browser support to include Firefox Mobile (Fennec), Opera Mobile / Mini, and refined our support for iOS, Android, BlackBerry 6, Palm WebOS, and most modern desktop browser”.

image

With the help of this framework, you can now start developing native-look-like app for iPad/iPhone/iPod Touch without using Objective C++. Read this article on HOWTO: Create native-looking iPhone/iPad applications from HTML, CSS and JavaScript.

If you do not have iPhone/iPad to test your apps, you can configure Safari browser installed on your computer to act just like an mobile browser, here is how:  Using Safari for iPhone, iPad and iPod Touch Website Testing.

This is the continuation of my series regarding digital image blending algorithms. If you want to read other posts in this series, here is the list:

  1. Image Blending Algorithm–Part I
  2. Image Blending Algorithm–Part II

This post will bring in five more image blending algorithms: Darken, Lighten, Difference, Exclusion and Reflex.

Blending Mode: Darken

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    darken:  function(v1,v2){return Math.min(v1,v2);}
};

Now to apply the Darken blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"darken");

Blending Effect Screenshot taken from iPaintPro:

blending_darken
iPaintPro Image Blending: Darken
 
Blending Mode: Lighten

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    darken:  function(v1,v2){return Math.min(v1,v2);},
    lighten: function(v1,v2){return Math.max(v1,v2);}
};

Now to apply the Lighten blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"lighten");

Blending Effect Screenshot taken from iPaintPro:

blending_lighten
iPaintPro Image Blending: Lighten
Blending Mode: Difference

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    darken:     function(v1,v2){return Math.min(v1,v2);},
    lighten:    function(v1,v2){return Math.max(v1,v2);},
    difference: function(v1,v2){return Math.abs(v1-v2);}
};

Now to apply the Difference blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"difference");

Blending Effect Screenshot taken from iPaintPro:

blending_difference
iPaintPro Image Blending: Difference
 
Blending Mode: Exclusion

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    darken:     function(v1,v2){return Math.min(v1,v2);},
    lighten:    function(v1,v2){return Math.max(v1,v2);},
    difference: function(v1,v2){return Math.abs(v1-v2);},
    exclusion:  function(v1,v2){return v1 + v2 - v1 * v2 / 127.5;}
};

Now to apply the Exclusion blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"exclusion");

Blending Effect Screenshot taken from iPaintPro:

blending_exclusion
iPaintPro Image Blending: Exclusion
 
Blending Mode: Reflex

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    //
    // previous introduced blending modes will be skipped to save page space.
    // ....
    //
    //
    darken:     function(v1,v2){return Math.min(v1,v2);},
    lighten:    function(v1,v2){return Math.max(v1,v2);},
    difference: function(v1,v2){return Math.abs(v1-v2);},
    exclusion:  function(v1,v2){return v1 + v2 - v1 * v2 / 127.5;},
    reflex:     function(v1,v2){return ((v1 === 255) ? v1:Math.min(255, (v2 * v2 / (255 - v1))));}
};

Now to apply the Reflex blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"reflex");

Blending Effect Screenshot taken from iPaintPro:

blending_reflex
iPaintPro Image Blending: Reflex
 
 
 
To be continued…
global-composite-operation_thumb.png

Since Microsoft released the beta version of IE 9 last September, I started waiting for the implementation of the globalCompositeOperation of the <canvas> element in the hope that it’s going to make my image process program more easier in some aspects. Since then rumors came out that Microsoft has no plan to support that but I do see this property listed in MSDN (http://msdn.microsoft.com/en-us/library/ff974909(v=vs.85).aspx) for a long time even the Beta and the RC1 do not support it.  On Monday evening at the hip SXSW festival, Microsoft announced the availability of its new Web browser, Internet Explorer 9. Now let’s do a test.

The following is the source code I used to do the test. You can copy&paste the source code to any text editor and save it as a html file to do the test on your own. Or you can click here to run the test (open the following code in a new window/tab)

<!DOCTYPE html>
<html>
   <head>
      <meta http-equiv="X-UA-Compatible" content="IE=9" />
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
      <title>Test globalCompositeOperation Support</title>
      <style type="text/css">
      .container{float:left;position:relative;background:#cccccc;margin:1px;}
      .container canvas{position:absolute;left:0px;top:0px;}
      .container .name{position:absolute;left:0px;bottom:0px;right:0px;
                       height:20px;font:11px arial;line-height:20px;
                       text-align:center;background:#eeeeee;}
      </style>
   </head>

   <body>
      <script type="text/javascript">
      var operation = [
         "source-over",
         "source-in",
         "source-out",
         "source-atop",
         "destination-over",
         "destination-in",
         "destination-out",
         "destination-atop",
         "lighter",
         "xor",
         "copy"
      ];

      setupLayout(80);

      for ( var i = 0; i < operation.length; i ++ ){
         var canvas = document.getElementById(operation[i]);
         testGlobalCompositeOperation(canvas,operation[i]);
      }

      function setupLayout(size){
         var divTmpl = document.createElement("div");
         divTmpl.className = "container";
         divTmpl.style.width  = size + "px";
         //leave 20 pixel height for the operation name
         divTmpl.style.height = size + 20 + "px"; 

         var canvas = document.createElement("canvas");
         canvas.width = size; canvas.height = size;

         var div2 = document.createElement("div"); div2.className = "name";

         divTmpl.appendChild(canvas);
         divTmpl.appendChild(div2);
         for ( var i = 0; i < operation.length; i ++ ){
            var div = divTmpl.cloneNode(true);
            div.firstChild.id = operation[i];
            div.lastChild.innerHTML = operation[i];
            document.body.appendChild(div);
         }
      }
      function testGlobalCompositeOperation(canvas,op){
         var w = canvas.width/3 * 2, h = canvas.height/3 * 2;
         var ctx = canvas.getContext("2d");
         ctx.beginPath();
         ctx.fillStyle = "rgba(0,152,255,1)";
         ctx.fillRect(0,0,w,h);

         ctx.save();
         ctx.beginPath();

         ctx.globalCompositeOperation = op;

         ctx.fillStyle = "rgba(255,0,0,1)";
         ctx.arc(w,h,w/2,0,Math.PI * 2,false);
         ctx.fill();
         ctx.restore();
      }

      </script>
   </body>
</html>   

The following image is the test result combined from different browsers so that you can see the effects side-by-side after the globalCompositeOperation being applied. Basically, only source-over,  source-atop,  destination-over, destination-out, lighter and xor are cross-browser the same.

As a web developer, I really hates this. The behavior differences can not be programmatically tested at all because they all claim that they support this feature. To me, all I can do is to avoid using those non-consistent features at first place. Then the point goes:  why the  heck browser even supports them? And another funny thing is that for all the variances with other browsers, Microsoft simply claims that IE9 passed and other browsers failed. See here for more detail information.

Hey, people do not follow the standard except me”, the browser said.

global-composite-operation

Hey, people do not follow the standard except me

This is the continuation of my previous post Image Blending Algorithm–Part I regarding digital image blending algorithms. I will continue to reveal more blending mode algorithms used in Adobe Photoshop and iPaintPro.  In part I, five image blending algorithms have been revealed: Multiply, Screen, Overlay, Hard Light and Soft Light.  This post will introduce another 4 image blending algorithms: Color Dodge, Color Burn, Linear Color Dodge and Linear Color Burn.

Blending Mode: Color Dodge

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    multiply: function(v1,v2){return v1 * v2 / 255;},
    screen  : function(v1,v2){return v1 + v2 – v1 * v2 / 255;},
    overlay : function(v1,v2){
       return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);
    },
    softlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }else{
         return v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }
    },
    hardlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5);
      }else{
         return v2 * v1 / 127.5;
      }
    },
    colordodge: function (v1,v2){
      return (v1 === 255) ? v1:Math.min(255, ((v2 << 8 ) / (255 - v1)));
    }
};

Now to apply the Color Dodge blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"colordodge");

Blending Effect Screenshot taken from iPaintPro:

blending_colordodge
iPaintPro Image Blending: Color Dodge
 
Blending Mode: Color Burn

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    multiply: function(v1,v2){return v1 * v2 / 255;},
    screen  : function(v1,v2){return v1 + v2 – v1 * v2 / 255;},
    overlay : function(v1,v2){
       return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);
    },
    softlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }else{
         return v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }
    },
    hardlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5);
      }else{
         return v2 * v1 / 127.5;
      }
    },
    colordodge: function (v1,v2){
      return (v1 === 255) ? v1:Math.min(255, ((v2 << 8 ) / (255 - v1)));
    },
    colorburn:function(v1,v2){
      return (v1 === 0) ? v1:Math.max(0, (255 - ((255 - v2) << 8 ) / v1));
    }
};

Now to apply the Color Burn blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"colorburn");

Blending Effect Screenshot taken from iPaintPro:

blending_colorburn
iPaintPro Image Blending: Color Burn
 
Blending Mode: Linear Color Dodge

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    multiply: function(v1,v2){return v1 * v2 / 255;},
    screen  : function(v1,v2){return v1 + v2 – v1 * v2 / 255;},
    overlay : function(v1,v2){
       return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);
    },
    softlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }else{
         return v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }
    },
    hardlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5);
      }else{
         return v2 * v1 / 127.5;
      }
    },
    colordodge: function (v1,v2){
      return (v1 === 255) ? v1:Math.min(255, ((v2 << 8 ) / (255 - v1)));
    },
    colorburn:function(v1,v2){
      return (v1 === 0) ? v1:Math.max(0, (255 - ((255 - v2) << 8 ) / v1));
    },
    linearcolordodge:function(v1,v2){
      return Math.min(v1 + v2, 255);
    }
};

Now to apply the Linear Color Dodge blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"linearcolordodge");

Blending Effect Screenshot taken from iPaintPro:

blending_linearcolordodge
iPaintPro Image Blending: Linear Color Dodge
Blending Mode: Linear Color Burn

Code Fragment:

//v1: channel value taken from source image
//v2: channel value taken from destination image
var BLENDING_MACRO = {
    multiply: function(v1,v2){return v1 * v2 / 255;},
    screen  : function(v1,v2){return v1 + v2 – v1 * v2 / 255;},
    overlay : function(v1,v2){
       return (v2 < 128) ? (2 * v1 * v2 / 255):(255 - 2 * (255 - v1) * (255 - v2) / 255);
    },
    softlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }else{
         return v2 - v2 * ((127.5 -  v1) / 127.5) * (0.5 - Math.abs(v2-127.5)/255);
      }
    },
    hardlight: function (v1,v2){
      if ( v1 > 127.5 ){
         return v2 + (255 - v2) * ((v1 - 127.5) / 127.5);
      }else{
         return v2 * v1 / 127.5;
      }
    },
    colordodge: function (v1,v2){
      return (v1 === 255) ? v1:Math.min(255, ((v2 << 8 ) / (255 - v1)));
    },
    colorburn:function(v1,v2){
      return (v1 === 0) ? v1:Math.max(0, (255 - ((255 - v2) << 8 ) / v1));
    },
    linearcolordodge:function(v1,v2){
      return Math.min(v1 + v2, 255);
    },
    linearcolorburn:function(v1,v2){
      return ((v1 + v2) < 255) ? 0 : (v1 + v2 - 255);
    },
};

Now to apply the Linear Color Burn blending mode to two canvas, we can simply call our generic method using this macro.

blending_canvas(canvas1,canvas2,"linearcolorburn");

Blending Effect Screenshot taken from iPaintPro:

blending_linearcolorburn
iPaintPro Image Blending: Linear Color Burn

 

 

 

To be continued…
© 2011 iPaintPro Suffusion theme by Sayontan Sinha