首页 Javascript 正文
356

利用canvas给图片加水印

  • yiqingpeng
  • 2016-09-29
  • 0
  •  
图片加水印的活一般是由后台来做,本文出于对canvas技术的研究, 利用canvas特性实现图片前端加水印。考虑到实用性,文章后面依旧会给出后台PHP给图片加水印的代码,读者可以根据自身需要选择不同的方案。

一、canvas加水印其实就是将目标图片先画在canvas上,然后再把水印(文字或者图片)画在canvas上。如下代码:
function WaterMark($markImgSrc, $text, $textAngle){
    this.canvas = document.createElement('canvas'),
    this.context = this.canvas.getContext('2d'),
    this.markImg,
    PI=Math.PI,
    Tan=Math.tan,
    Sin=Math.sin,
    Cos=Math.cos,
    Int=parseInt,
    outer = this;
    
    function doMark(bkimg, originLoad, text, angle){
         var W=bkimg.width, H=bkimg.height, fontSize='40px';
         angle = (angle || 0)*PI/180;
         outer.canvas.width=W, outer.canvas.height=H;
         outer.context.drawImage(bkimg, 0, 0, W, H);
         !!$markImgSrc && outer.context.drawImage(outer.markImg, 10, 10, outer.markImg.width, outer.markImg.height);
         if(typeof text!=='undefined'){
            outer.context.save();
            outer.context.textAlign='start';//start,left,right,end,center
            outer.context.textBaseline='top';
            outer.context.font=fontSize+" 黑体";
            outer.context.fillStyle="red";
            //计算文字位置
            var txtWidth=+outer.context.measureText(text).width,/*获得文本宽度*/ txtHeight=Int(fontSize),
            x=W-txtWidth, y=H-txtHeight,
            centerX=txtWidth/2+x,centerY=txtHeight/2+y;
            outer.context.translate(centerX, centerY);//由于rotate的旋转中心是画布左上角,要使旋转围绕目标元素中心,则需要将画布原点移动到元素中心位置,而translate就能使我们达到目的。
            outer.context.rotate(angle);//注意顺序,一定是在translate将画布原点平移了之后,才可应用rotate.
            outer.context.fillText(text,-txtWidth/2,-txtHeight/2);//此时目标元素的左上角坐标是相对于平移之后的画布来算的
            outer.context.rotate(-angle);//还原旋转
            outer.context.translate(-centerX, -centerY);//记得将画布移动回原来的位置。
            outer.context.save();
         }
         bkimg.src = outer.canvas.toDataURL('image/jpeg');
         bkimg.onload = originLoad;
    }
    
    function randStr(){
        return ''+Math.random()+(new Date).getTime();
    }
    
    function log(obj){
        console.log(obj+Math.random());
    }
    
    this.setImage = function(img){
        img.crossOrigin = "Anonymous";//此行代码的作用请看二
        img.crossOrigin = "*";//此行代码的作用请看二
        return {
            mainImg:img,
            create:function(){
                if(!document.createElement('canvas').getContext) return;
                if(typeof this.mainImg ==='undefined') return alert('未绑定图片对象');
                var oldload = this.mainImg.onload, me=this;
                if(!!$markImgSrc){
                    outer.markImg=new Image();
                    outer.markImg.onload = function(){
                        
                        me.mainImg.onload = function(){
                            typeof oldload === 'function' && oldload();
                            doMark(me.mainImg, oldload, $text, $textAngle);
                        }
                        me.mainImg.src=me.mainImg.src+'?'+randStr();
                    }
                    outer.markImg.src=$markImgSrc+'?'+randStr();
                }else{
                    me.mainImg.onload = function(){
                        typeof oldload === 'function' && oldload();
                        doMark(me.mainImg, oldload, $text, $textAngle);
                    }
                    me.mainImg.src=me.mainImg.src+'?'+randStr();
                }
                
            }

        }
    };
}
var obj = new WaterMark('text.png', 'Hellow world, 不错');
//obj.setImage(image).create();
//obj.setImage(image2).create();
//obj.setImage(image3).create();

$(function(){
    $('#container img').each(function(){
        obj.setImage(this).create();
    });
});
二、上面的代码只能处理本域的图片,对于跨域图片应该做些特殊处理。首先,将目标图片的crossOrigin属性设置成*或者 Anonymous。然后,我们还要在目标图片的服务器上做些文章(如果没有权限修改目标图片所在的web服务配置,那就只能歇菜。),以apache为图片服务器为例,我们需要在web目录或者图片目录下添加一个.htaccess文件,其内容为:
<IfModule mod_setenvif.c>
    <IfModule mod_headers.c>
        <FilesMatch "\.(cur|gif|ico|jpg|jpe?g|png|svgz?|webp)$">
            SetEnvIf Origin ":" IS_CORS
            Header set Access-Control-Allow-Origin "*" env=IS_CORS
        </FilesMatch>
    </IfModule>
</IfModule>
设置好之后,就可以将此域名下的图片进行处理了。

三、前端加水印应用场景有限,为了使本文有更多的干货,特附上php给图片加水印的代码:
/**
*@author yiqingpeng @2016-09-27
*功能:给jpg图片加文本水印。
*本类也可通过继承重载createImgSource方法可扩展成针对png,tmp图像类型加水印
*/
class WaterMark{
    protected $imgfile;
    protected $text;
    protected $imgSource;
    protected $fontSize=30;
    protected $fontColor=array(255,0,0);//array(r,g,b)
    
    public function __construct($imgfile, $text){
        $this->imgfile = $imgfile;
        $this->text = $text;
        $this->createImgSource();
    }
    
    public function create(){
        $this->addText();
    }
    
    protected function createImgSource(){
        try{
            $this->imgSource=imagecreatefromjpeg($this->imgfile);
            return true;
        }catch(Exception $e){
            return false;
        }
    }
    
    public function setFontSize($fontSize){
        $this->fontSize = (int)$fontSize;
        return $this;
    }
    
    public function setFontColor(array $rgb){
        $this->fontColor = $rgb;
        return $this;
    }
    
    protected function addText(){
        try{
            $fontColor=imagecolorallocate($this->imgSource, $this->fontColor[0], $this->fontColor[1], $this->fontColor[2]);
            $fontAngle = 0;
            $imgWidth = imagesx($this->imgSource);
            $imgHeight = imagesy($this->imgSource);
            $fontType = 'simsun.ttc';
            $fontbbox = imagettfbbox($this->fontSize, $fontAngle, $fontType, $this->text);
            $x = $imgWidth - $fontbbox[4]-5;
            $y = $imgHeight - $fontbbox[3]-3;
            imageTTFtext($this->imgSource, $this->fontSize, $fontAngle, $x, $y, $fontColor, $fontType, $this->text);
        }catch(Exception $e){
            exit($e->getMessage());
            return false;
        }
    }
    
    public function out(){
        header("Pragma:no-cache\r\n");
        header("Cache-Control:no-cache\r\n");
        header("Expires:0\r\n");
        header("Content-type:Image/jpeg\r\n");
        imagejpeg($this->imgSource);
    }
    
    public function __destruct(){
        imagedestroy($this->imgSource);
    }
}

$wm = new WaterMark('image.jpg','中国第一no1..');
$wm->create();
$wm->out();

正在加载评论...