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… …
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”.
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:
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 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 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 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 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:
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.
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 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 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 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:
The following code fragment provides a method to draw a heart shape within given rectangle region.
//
// (x,y) - the top left corner of the surrounding rectangle
// width,height - the size of the surrounding rectangle
function drawHeart(canvas,x,y,width,height){
var x0 = x + 0.5 * width, y0 = y + 0.3 * height;
var x1 = x + 0.1 * width, y1 = y + 0.0 * height;
var x2 = x + 0.0 * width, y2 = y + 0.6 * height;
var x3 = x + 0.5 * width, y3 = y + 0.9 * height;
var x4 = x + 1.0 * width, y4 = y + 0.6 * height;
var x5 = x + 0.9 * width, y5 = y + 0.0 * height;
var ctx = canvas.getContext("2d");
ctx.save();
ctx.beginPath();
ctx.moveTo(x0,y0);
ctx.bezierCurveTo(x1,y1,x2,y2,x3,y3);
ctx.bezierCurveTo(x4,y4,x5,y5,x0,y0);
ctx.stroke();
ctx.restore();
}
To see this code in action, you can check out http://www.jswidget.com/ipaint.html
Image thresholding is the easiest method of image segmentation. It simply divides the image pixels into two categories. One contains the pixels with value less than the threshold and the other contains the pixels with value greater than the threshold. Though pick the right threshold value is difficult, there are many proposed methods on how to pick the right threshold value, such as using mean or median value, automatic thresholding algorithm, histogram valley point etc. In Adode Photoshop, it displays the luminosity histogram to help a user to pick the desired value. iPaintPro does the same as Adobe Photoshop.
The algorithm is very simple:
Lnew = 0 if Lcur < threshold value
= 255 if Lcur >= threshold value
Lcur is the calculated luminosity value of given (r, g, b) pixel using ITU-R BT.601 image grayscale method. (See my other post: http://jswidget.com/blog/2011/02/20/image-grayscale-itu-recommend-standards/).
Below is the screenshot taken from iPaintPro when doing image thresholding:

Invert and complement are two operations in digital image processing to get negative film effect. They are all to get the complement color from one color with a little different algorithm.
Invert operation is simple. We simply use 255 minus value in each channel. The result will be the negative film: COLORinvert = 255 – COLOR. From the formular, we can see that the invert operation actually make:
| Color | Inverted Color | ||
| Black | White | ||
| Red | Cyan | ||
| Green | Magenta | ||
| Blue | Yellow |
In Color Theroy, this is actually also refered as complement color for RGB color model. Red, green, blue are primary colors. Cyan, magenta and yellow are secondary colors.
Complement is actually using this formular:
COLORcomplement = MAX(ColorR,ColorG,ColorB) + MIN(ColorR,ColorG,ColorB) – COLOR
This different between invert and complement is that invert not only change the hue value, the saturation and lightness are also changed. But the complement operation does not change the lightness.
For example,
Complement(Color(0,0,0)) = MAX(0,0,0) + MIN(0,0,0) – Color(0,0,0) = Color(0,0,0).
This means complement of black is still black
Complement(Color(255,255,255)) = MAX(255,255,255) + MIN(255,255,255) – Color(255,255,255) = Color(255,255,255)
This means complement of white is still white.
You can see the two different effects performed within iPainPro 1.0:


