使用canvas创建ios图标风格的图片

大家都知道canvas很好很强大,入门资料可以看mozilla developer center的Canvas教程,在这里就不多说了。

这里只是希望利用canvas的图像处理功能来创建ios图标风格的图片,就像下面这样:


接下来就开始吧:

  1. 准备原始图片

    将它绘制到canvas里的方法也很简单,首先在html中得有一个canvas标签:
    <canvas id="mycanvas" width="437" height="400"></canvas>
    然后是javascript代码:
    var context = document.getElementById("mycanvas").getContext("2d");
    var img = new Image(); 
    img.onload = function(){
        context.drawImage(img, 0, 0);
    }; 
    img.src='https://www.lofter.com/blog/shellchine/new/text/chihuo.png';
  2. 为图片裁剪圆边,简单的思路就是在canvas中画个圆角矩形clip一下,但问题是canvas没有给我们提供原生的圆角矩形函数,只好自己动手,丰衣足食了,先是定义一个圆角矩形绘制方法,然后用它来对canvas裁剪一下边界:
    CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
        if (w < 2 * r) r = w / 2;
        if (h < 2 * r) r = h / 2;
        this.beginPath();
        this.moveTo(x+r, y);
        this.arcTo(x+w, y,   x+w, y+h, r);
        this.arcTo(x+w, y+h, x,   y+h, r);
        this.arcTo(x,   y+h, x,   y,   r);
        this.arcTo(x,   y,   x+w, y,   r);
        this.closePath();
        return this;
    };
    context.roundRect(0, 0, 437, 400, 40).clip();
    得到的效果如下:

  3. 接下来为图片添加高亮效果,基本思路是使用蒙板图片叠加。说起来很简单,但这个图片叠加里是有很多讲究的,用不好的话就是差之毫厘,谬以千里了。
    首先我们得了解canvas为我们提供了哪些图片叠加方法,以下表格列出了目前canvas中可用的globalCompositeOperation,可将你的canvas context对象设置globalCompositeOperation属性为以下的任何一个值(默认为source-over)。图中蓝色矩形表示原有内容(destination),红色圆形表示新图形(source):

    source-over: 默认设置,新图形会覆盖在原有内容之上

    Image:Canvas_composite_srcovr.png

    destination-over: 在原有内容之下绘制新图形

    Image:Canvas_composite_destovr.png

    source-in: 新图形会仅仅出现与原有内容重叠的部分。其它区域都变成透明的

    Image:Canvas_composite_srcin.png

    destination-in: 原有内容中与新图形重叠的部分会被保留,其它区域都变成透明的

    Image:Canvas_composite_destin.png

    source-out: 只有新图形中与原有内容不重叠的部分会被绘制出来

    Image:Canvas_composite_srcout.png

    destination-out: 原有内容中与新图形不重叠的部分会被保留

    Image:Canvas_composite_destout.png

    source-atop: 新图形中与原有内容重叠的部分会被绘制,并覆盖于原有内容之上

    Image:Canvas_composite_srcatop.png

    destination-atop: 原有内容中与新内容重叠的部分会被保留,并会在原有内容之下绘制新图形

    Image:Canvas_composite_destatop.png

    lighter: 两图形中重叠部分作加色处理

    Image:Canvas_composite_lighten.png

    darker: 两图形中重叠的部分作减色处理
    (注:新的canvas标准已无此定义).

    Image:Canvas_composite_darken.png

    xor: 重叠的部分会变成透明

    Image:Canvas_composite_xor.png

    copy: 只有新图形会被保留,其它都被清除掉

    Image:Canvas_composite_copy.png

    现在我们再拿出要叠加到原始图片的蒙板图,是个半透明的灰度图(这张图是用imagemagick生成的,ps当然也可以,有闲再写下怎么用canvas来画),如下:

    对照前面的列表看来,在canvas默认提供的图片叠加方法,可能符合我们要求的也只有默认的source-over了,虽然觉得不是想要的,还是硬着头皮试试吧:

  4. 试完了,果然发现,这真的不是我们想要的~~~
    看来canvas默认提供的图片叠加效果是没戏了。幸好canvas同时还提供了图片像素级操作的接口,我们可以用它来实现更复杂的图片叠加算法,如Multiply, Screen, Bumpmap, Divide, Plus, Minus, ModulusAdd, ModulusSubtract, Difference, Exclusion, Lighten, Darken 等等。在这里,我们只需要实现Screen算法。
    实现算法前,首先看看我们要用到像素级的操作方法,包括:
    • createImageData(w,h):可以新建一个w*h尺寸的新的ImageData,不过也可以使用参数(anotherImageData)来创建【firefox5开始支持】。
    • getImageData(x,y,w,h):表示起点x,y,尺寸w,h。可以获取canvas.context中在参数范围内的ImageData。
    • putImageData(ImageData, dx, dy [, DirtyX] [, DirtyX] [, DirtyWidth] [, DirtyHeight]):imageData包含了图像的width,height, 还有一个CanvasPixelArray。dx, dy表示绘图起始位置。相对于canvas区域左上角。后面四个可选参数:表示可见区范围。相对于起绘点,即上面的参数dx,dy表示的点。缺省为0,0,ImageData.width,ImageData.height。
    然后再了解一下什么是Screen算法,简单地说,这是一种像素级别的图形运算,就是将原图和新图的像素值(0-255)进行数学计算后得到最终图像的像素值,以Screen为例,就是Final = 1-(1-Src)*(1-Dest)
    实现函数如下:
    function imageData(url, fn){
        var canvas = document.createElement("canvas");
        var ctx = canvas.getContext("2d");
        var img = new Image();
        img.onload = function(){
            var ht = img.height;
            var width = img.width;
            canvas.width = width;
            canvas.height = ht;
            ctx.drawImage(img, 0, 0);
            if(typeof fn == 'function'){
                fn(ctx.getImageData(0,0,width, ht));
            }
        };
        img.src = url;
    }

    imageData('chihuo_r.png', function(data1){
        imageData('ios-over.png', function(data2){
            var pix1 = data1.data;
            var pix2 = data2.data;
            for (var i = 0,n = pix1.length; i < n; i+=4) {
                var alpha = pix2[i+3]/255;
                for(var j = i; j < i+3; j++){
                    pix1[j] = 255*(1-(1-pix1[j]/255)*(1-pix2[j]*alpha/255));
                }
            }
            var context = document.getElementById("mycanvas").getContext("2d");
            context.putImageData(data1,0,0);
        });
    });
    这次得到的效果正是文章开头所示的样子了。

这个例子只是canvas图像处理功能的牛刀小试,事实上,利用canvas提供的像素级操作方法,我们便可以封装出大量的图像处理滤镜,实现photoshop的许多酷炫的特效,这是后话,暂且不表。

May
20
2012
 
评论(1)
热度(7)
© pm163 | Powered by LOFTER