用canvas实现图片滤镜效果

 
<html>
<head>
    <style type="text/css">



    form, input {width: 73px;height: 27px;}
    form {
        position: relative;
        float: left;
        margin: 0 10px 0 0;
    }
    #up-button{
        position: absolute;
        right: 0;
        top: 0;
        cursor: pointer;
        opacity: 0;
        filter: alpha(opacity=0);
        outline: none;
    }
    #button{
    }
    iframe {display: none;}
</style>

</head>
<body>
<div class="bt">
    <form id="uf">
        <input type="file" name="file" id="up-button"/>
        <input type="button" id="button" value="upload"/>
        <input type="button" id="download" value="download"/>
    </form>

    <span><input type="radio" value="spread" id="spread" name="filter"/><label for="spread">油画效果</label></span>
    <span><input type="radio" id="gray" name="filter"/><label for="gray">灰度效果</label></span>
    <span><input type="radio" id="comic" name="filter"/><label for="comic">连环画效果</label></span>
    <span><input type="radio" id="old" name="filter"/><label for="old">怀旧效果</label></span>
    <span><input type="radio" id="negatives" name="filter"/><label for="negatives">底片效果</label></span>
    <span><input type="radio" id="black" name="filter"/><label for="black">黑白效果</label></span>
    <span><input type="radio" id="cameo" name="filter"/><label for="cameo">浮雕效果</label></span>
</div>
<br>
  <canvas id="cv">fuck ie</canvas>
  <canvas id="myCanvas" >Gray Filter</canvas>
  
  <script>


  /**
   * 获取mimeType
   * @param  {String} type the old mime-type
   * @return the new mime-type
   */
  var _fixType = function(type) {
      type = type.toLowerCase().replace(/jpg/i, 'jpeg');
      var r = type.match(/png|jpeg|bmp|gif/)[0];
      return 'image/' + r;
  };

  /**
   * 在本地进行文件保存
   * @param  {String} data     要保存到本地的图片数据
   * @param  {String} filename 文件名
   */
  var saveFile = function(data, filename){
      var save_link = document.createElementNS('http://www.w3.org/1999/xhtml', 'a');
      save_link.href = data;
      save_link.download = filename;
     
      var event = document.createEvent('MouseEvents');
      event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
      save_link.dispatchEvent(event);
  };
     

  document.getElementById("download").onclick=function()
  {
	//图片导出为 png 格式
	  var type = 'png';
	  var imgData = canvas.toDataURL(type);
	  // 加工image data,替换mime type
	  imgData = imgData.replace(_fixType(type),'image/octet-stream');  
	  // 下载后的问题名
	  var filename = 'bloglaotou_' + (new Date()).getTime() + '.' + type;
	  // download
	  saveFile(imgData,filename);
	     

  }
//  1.灰度效果
//计算公式 .299 * r + .587 * g + .114 * b;
// calculate gray scale value
function gray(canvasData)
{
 for ( var x = 0; x < canvasData.width; x++) {
     for ( var y = 0; y < canvasData.height; y++) {

       // Index of the pixel in the array
       var idx = (x + y * canvasData.width) * 4;
       var r = canvasData.data[idx + 0];
       var g = canvasData.data[idx + 1];
       var b = canvasData.data[idx + 2];
       var gray = .299 * r + .587 * g + .114 * b;
            
        // assign gray scale value
        canvasData.data[idx + 0] = gray; // Red channel
        canvasData.data[idx + 1] = gray; // Green channel
        canvasData.data[idx + 2] = gray; // Blue channel
        canvasData.data[idx + 3] = 255; // Alpha channel
        // add black border
        if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
        {
          canvasData.data[idx + 0] = 0;
          canvasData.data[idx + 1] = 0;
          canvasData.data[idx + 2] = 0;
        }
     }
 }
 return canvasData;
}


 

     
//2.怀旧效果   
function old(canvasData)
{
for ( var x = 0; x < canvasData.width; x++) {
 for ( var y = 0; y < canvasData.height; y++) {

   // Index of the pixel in the array
   var idx = (x + y * canvasData.width) * 4;
   var r = canvasData.data[idx + 0];
   var g = canvasData.data[idx + 1];
   var b = canvasData.data[idx + 2];

   var dr=.393*r+.769*g+.189*b;
   var dg=.349*r+.686*g+.168*b;
   var db=.272*r+.534*g+.131*b;
   var scale=Math.random()*0.5 + 0.5;
   var fr=scale*dr+(1-scale)*r;
   scale=Math.random()*0.5 + 0.5;
   var fg=scale*dg+(1-scale)*g;
   scale=Math.random()*0.5 + 0.5;
   var fb=scale*db+(1-scale)*b;
   canvasData.data[idx + 0] = fr; // Red channel
   canvasData.data[idx + 1] = fg; // Green channel
   canvasData.data[idx + 2] = fb; // Blue channel
   canvasData.data[idx + 3] = 255; // Alpha channel 
   // add black border
   if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
   {
     canvasData.data[idx + 0] = 0;
     canvasData.data[idx + 1] = 0;
     canvasData.data[idx + 2] = 0;
   }
 }
}
return canvasData;
}



//3 底片效果
//算法原理:将当前像素点的RGB值分别与255之差后的值作为当前点的RGB值,即
//R = 255 – R;G = 255 – G;B = 255 – B;
function negatives(canvasData)
{
for ( var x = 0; x < canvasData.width; x++) {
 for ( var y = 0; y < canvasData.height; y++) {

   // Index of the pixel in the array
   var idx = (x + y * canvasData.width) * 4;
   var r = canvasData.data[idx + 0];
   var g = canvasData.data[idx + 1];
   var b = canvasData.data[idx + 2];
   var fr=255-r;
   var fg=255-g;
   var fb=255-b;
   canvasData.data[idx + 0] = fr; // Red channel
   canvasData.data[idx + 1] = fg; // Green channel
   canvasData.data[idx + 2] = fb; // Blue channel
   canvasData.data[idx + 3] = 255; // Alpha channel 
   // add black border
   if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
   {
     canvasData.data[idx + 0] = 0;
     canvasData.data[idx + 1] = 0;
     canvasData.data[idx + 2] = 0;
   }
 }
}
return canvasData;
}

 
  
//4 黑白效果
//求RGB平均值Avg = (R + G + B) / 3,如果Avg >= 100,则新的颜色值为R=G=B=255;
//如果Avg < 100,则新的颜色值为R=G=B=0;255就是白色,0就是黑色;
//至于为什么用100作比较,这是一个经验值吧,设置为128也可以,可以根据效果来调整。
function black(canvasData)
{
for ( var x = 0; x < canvasData.width; x++) {
 for ( var y = 0; y < canvasData.height; y++) {

   // Index of the pixel in the array
   var idx = (x + y * canvasData.width) * 4;
   var r = canvasData.data[idx + 0];
   var g = canvasData.data[idx + 1];
   var b = canvasData.data[idx + 2];
   if((r+g+b)>=300)
   {
   	fr=fg=fb=255;
   }
   else
   {
   	fr=fg=fb=0;
   }
   canvasData.data[idx + 0] = fr; // Red channel
   canvasData.data[idx + 1] = fg; // Green channel
   canvasData.data[idx + 2] = fb; // Blue channel
   canvasData.data[idx + 3] = 255; // Alpha channel
   // add black border
   if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
   {
     canvasData.data[idx + 0] = 0;
     canvasData.data[idx + 1] = 0;
     canvasData.data[idx + 2] = 0;
   }
 }
}
return canvasData;
}

 

//5 浮雕效果
//用相邻点的RGB值减去当前点的RGB值并加上128作为新的RGB值。
//由于图片中相邻点的颜色值是比较接近的,因此这样的算法处理之后,只有颜色的边沿区域,
//也就是相邻颜色差异较大的部分的结果才会比较明显,而其他平滑区域则值都接近128左右,
//也就是灰色,这样就具有了浮雕效果。
//在实际的效果中,这样处理后,有些区域可能还是会有”彩色”的一些点或者条状痕迹,所以最好再对新的RGB值做一个灰度处理。
 
function cameo(canvasData)
{
for ( var x = 0; x < canvasData.width; x++) {
 for ( var y = 0; y < canvasData.height; y++) {

   // Index of the pixel in the array
   var idx = (x + y * canvasData.width) * 4;
   var r = canvasData.data[idx + 0];
   var g = canvasData.data[idx + 1];
   var b = canvasData.data[idx + 2];
   var idx2 = (x + (y+1) * canvasData.width) * 4;
   var r2 = canvasData.data[idx2 + 0];
   var g2 = canvasData.data[idx2 + 1];
   var b2 = canvasData.data[idx2 + 2];
   var fr=r2-r+128;
   var fg=g2-g+128;
   var fb=b2-b+128;
   var gray = .299 * fr + .587 * fg + .114 * fb;
   canvasData.data[idx + 0] = gray; // Red channel
   canvasData.data[idx + 1] = gray; // Green channel
   canvasData.data[idx + 2] = gray; // Blue channel
   canvasData.data[idx + 3] = 255; // Alpha channel
   // add black border
   if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
   {
     canvasData.data[idx + 0] = 0;
     canvasData.data[idx + 1] = 0;
     canvasData.data[idx + 2] = 0;
   }
 }
}
return canvasData;
}

 
 
 
 
//6.连环画效果
//连环画的效果与图像灰度化后的效果相似,它们都是灰度图,但连环画增大了图像的对比度,使整体明暗效果更强.
//算法:
//R = |g – b + g + r| * r / 256
//G = |b – g + b + r| * r / 256;
//B = |b – g + b + r| * g / 256;
function comic(canvasData)
{
for ( var x = 0; x < canvasData.width; x++) {
 for ( var y = 0; y < canvasData.height; y++) {

   // Index of the pixel in the array
   var idx = (x + y * canvasData.width) * 4;
   var r = canvasData.data[idx + 0];
   var g = canvasData.data[idx + 1];
   var b = canvasData.data[idx + 2];

    var fr=Math.abs((g-r+g+b))*r/256;
    var fg=Math.abs((b-r+g+b))*r/256;
    var fb=Math.abs((b-r+g+b))*g/256; 
    //var fr=(g-r+g+b)*r/256;
    //var fg=(b-r+g+b)*r/256;
    //var fb=(b-r+g+b)*g/256;  
   canvasData.data[idx + 0] = fr; // Red channel
   canvasData.data[idx + 1] = fg; // Green channel
   canvasData.data[idx + 2] = fb; // Blue channel
   canvasData.data[idx + 3] = 255; // Alpha channel
            // add black border
 if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
 {
   canvasData.data[idx + 0] = 0;
   canvasData.data[idx + 1] = 0;
   canvasData.data[idx + 2] = 0;
 }

 }
}
return canvasData;
}

//9 扩散(毛玻璃)
//原理:用当前点四周一定范围内任意一点的颜色来替代当前点颜色,最常用的是随机的采用相邻点进行替代。
function spread(canvasData)
 {
     for ( var x = 0; x < canvasData.width; x++) {
         for ( var y = 0; y < canvasData.height; y++) {

           // Index of the pixel in the array
           var idx = (x + y * canvasData.width) * 4;
           var r = canvasData.data[idx + 0];
           var g = canvasData.data[idx + 1];
           var b = canvasData.data[idx + 2];

           var rand=Math.floor(Math.random()*10)%3;
           var idx2 = (x+rand + (y+rand) * canvasData.width) * 4;
           var r2 = canvasData.data[idx2 + 0];
           var g2 = canvasData.data[idx2 + 1];
           var b2 = canvasData.data[idx2 + 2];
           var fr=r2;
           var fg=g2;
           var fb=b2;
           canvasData.data[idx + 0] = fr; // Red channel
           canvasData.data[idx + 1] = fg; // Green channel
           canvasData.data[idx + 2] = fb; // Blue channel
           canvasData.data[idx + 3] = 255; // Alpha channel  
           // add black border
           if(x < 8 || y < 8 || x > (canvasData.width - 8) || y > (canvasData.height - 8)) 
           {
             canvasData.data[idx + 0] = 0;
             canvasData.data[idx + 1] = 0;
             canvasData.data[idx + 2] = 0;
           }
           
   
         }
     }
     return canvasData;
 } 


var cv = document.getElementById('cv');
var c = cv.getContext('2d');
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var fileBtn = document.getElementById("up-button");
var img = new Image();
fileBtn.onchange = getImg;
function init() {
    cv.width = img.width;
    cv.height = img.height;
    c.drawImage(img, 0, 0);
    var f=""; 
    var filter = document.getElementsByName("filter"); 
    for(i=0;i<filter.length;i++) 
    { 
        if(filter[i].checked)
        {
        	f=filter[i].id; 
        }
           
    }
    switch(f){
	   case "gray":setGray();break;
	   case "spread":setSpread();break;
	   case "comic":setComic();break;
	   case "old":setOld();break;
	   case "negatives":setNegatives();break;
	   case "black":setBlack();break;
	   case "cameo":setCameo();break;
	   case "casting":setCasting();break;
	   case "frozen":setFrozen();break;
	   default:setGray();break;
    }
  
  };

function getImg(file) {
    var reader = new FileReader();
    reader.readAsDataURL(fileBtn.files[0]);
    reader.onload = function () {
        img.src = reader.result;
    }


}
 
 window.onload = function() {

	 img.src = 'http://bbs.blueidea.com/forum.php?mod=attachment&aid=MjEyMzA1fDJiYzQxZThkfDEzODMxMDU2NDd8NjU2ODk5fDMxMDU1MTQ%3D';
	 img.onload = init 

    // re-size the canvas deminsion
    canvas.width  = img.width;
    canvas.height = img.height;
    
    // get 2D render object
    var context = canvas.getContext("2d");
    context.drawImage(img, 0, 0);
    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  

   canvasData=gray(canvasData); 
//   canvasData=spread(canvasData);
//   canvasData=old(canvasData);
//   canvasData=frozen(canvasData);
//   canvasData=casting(canvasData);
//   canvasData=cameo(canvasData);
//   canvasData=comic(canvasData);
//   canvasData=black(canvasData);
//   canvasData=negatives(canvasData);

    context.putImageData(canvasData, 0, 0); // at coords 0,0
  };
  
  
  document.getElementById('spread').onclick=setSpread;
  function setSpread()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	    canvasData=spread(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  document.getElementById('gray').onclick=setGray;
  function setGray()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	    canvasData=gray(canvasData); 
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  document.getElementById('old').onclick=setOld;
  function setOld()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
         canvasData=old(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }


  document.getElementById('cameo').onclick=setCameo;
  function setCameo()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	    canvasData=cameo(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  document.getElementById('comic').onclick=setComic;
  function setComic()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	   canvasData=comic(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  document.getElementById('black').onclick=setBlack;
  function setBlack()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	    canvasData=black(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  document.getElementById('negatives').onclick=setNegatives;
  function setNegatives()
  {
  	    canvas.width  = img.width;
  	    canvas.height = img.height;
  	    var context = canvas.getContext("2d");
  	    context.drawImage(img, 0, 0);
  	    var canvasData = context.getImageData(0, 0, canvas.width, canvas.height);  
  	    canvasData=negatives(canvasData);
  	    context.putImageData(canvasData, 0, 0); // at coords 0,0
  }
  
</script>
</body>
</html>

延伸阅读


▶ Walkthrough007

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值