使用canvas进行图像编辑的实例


Posted in Javascript onAugust 29, 2017

前面的话

本文将分为几个小功能的形式来详细介绍canvas图像编辑

缩放

下面是一张分析图,假设默认情况下,图片和canvas宽高相同。图片的缩放(scale)范围为0.5到3,缩放时改变的是图片的大小和图片的坐标位置

W(宽) = canvas.width * scale
H(高) = canvas.height * scale
x坐标 = (W - canvas.width)/2;
y坐标 = (H - canvas.height)/2;

使用canvas进行图像编辑的实例

因此,代码如下

<canvas id="drawing" >
  <p>The canvas element is not supported!</p>
</canvas>
<br>
<input id="scale-range" min="0.5" max="1.5" step="0.01" type="range" >
<script>
var drawing = document.getElementById('drawing');
if(drawing.getContext){
 var context = drawing.getContext('2d');
 var slider = document.getElementById('scale-range');
 var W = 400;
 var H = 290; 
 drawing.width = W; 
 drawing.height = H;
 var image = new Image();
 image.src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg";
 image.onload = function(){
  drawImgByScale(slider.value);
  slider.onmousemove = function(){
   drawImgByScale(slider.value);
  }
 }
 function drawImgByScale(scale){
  var imgW = W * scale;
  var imgH = H * scale;
  var dx =(W - imgW)/2;
  var dy =(H - imgH)/2;
  context.clearRect(0,0,W,H);
  context.drawImage(image,dx,dy,imgW,imgH);
 }
} 
</script>

水印

利用canvas可以实现向图片添加水印的功能,先通过file控件的reader选择图片,然后使用canvas添加图片及水印,并且使用toDataURL()和a标签实现添加水印后的图片的下载功能

<canvas id="drawing" >
  <p>The canvas element is not supported!</p>
</canvas>
<div>
 <span>
  <input type="file" id="addImgHelper" >
  <button id="addImg">选择图片</button>
 </span>
 <span>
  <button id="addWaterMark" disabled>添加水印</button> 
  <span>水印文字为</span>
  <input id="waterMarkWords" type="text" value="小火柴的蓝色理想">   
 </span>
 <span>
  <button id="downloadImg" disabled>下载图片</button>
  <a id="downloadImgHelper" href="#" rel="external nofollow" download="带水印图片" ></a>  
 </span>
</div>
<script>
if(drawing.getContext){
 var cxt = drawing.getContext('2d');
 var W,H; 
 addImg.onclick = function(){
  addImgHelper.click();
 }
 addImgHelper.onchange = function(){
  addWaterMark.disabled = true;
  downloadImg.disabled = true;
  var file = addImgHelper.files[0];
  if(file && /image/.test(file.type)){
   var reader = new FileReader();
   reader.readAsDataURL(file);
   reader.onload = function(){
    var img = new Image();
    img.src= reader.result;
    img.onload = function(){
     addWaterMark.disabled = false;
     drawing.width = W = img.width;
     drawing.height = H = img.height;
     cxt.drawImage(img,0,0);
     addWaterMark.onclick = function(){
       downloadImg.disabled = false;
       cxt.clearRect(0,0,W,H);
       cxt.drawImage(img,0,0);  
       var str = waterMarkWords.value;
       cxt.font = "bold 50px Arial";
       cxt.lineWidth = '1';
       cxt.fillStyle = 'rgba(255,255,255,0.5)';
       cxt.textBaseline = "bottom";
       cxt.textAlign = 'end';
       cxt.fillText(str,W-10,H-10,W/2);  
       downloadImg.onclick = function(){
        downloadImgHelper.href = drawing.toDataURL('image/png');
        downloadImgHelper.click();    
       }  
     } 
    }
   }   
  }      
 }        
}
</script>

放大镜

下面来实现一个放大镜的效果,鼠标按下并移动时,显示当前图片区域的放大效果,抬起后效果消失。放大镜效果主要使用离屏canvas的技术,离屏canvas放置的是图片的放大版,而普通canvas则放置图片的正常版

<canvas id="drawing" >
  <p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawingOff" >
  <p>The canvas element is not supported!</p>
</canvas>
<script>
if(drawing.getContext){
 var cxt = drawing.getContext('2d');
 var cxtOff = drawingOff.getContext('2d');
 var W,H; 
 var scale = 1.5; 
 var img = new Image();
 img.src="http://sandbox.runjs.cn/uploads/rs/26/ddzmgynp/chunfen.jpg";
 img.onload = function(){
  W = img.width;
  H = img.height;
  drawing.width = W/scale;
  drawing.height = H/scale;
  drawingOff.width = W;
  drawingOff.height = H;
  cxt.drawImage(img,0,0,W/scale,H/scale);
  cxtOff.drawImage(img,0,0);
  drawing.onmousedown = function(e){
   e = e || event;
   var x0 = this.offsetLeft;
   var y0 = this.offsetTop; 
   drawMagnifier(e);
   drawing.onmousemove = function(e){
    drawMagnifier(e);
   }
   document.onmouseup = function(e){
    cxt.clearRect(0,0,W/scale,H/scale);
    cxt.drawImage(img,0,0,W/scale,H/scale);
    drawing.onmousemove = null;
   }    
   function drawMagnifier(e){
    cxt.clearRect(0,0,W/scale,H/scale);
    cxt.drawImage(img,0,0,W/scale,H/scale);
    var x = (e.clientX-x0);
    var y = (e.clientY-y0);    
    var r = 40;
    var dx = x - r;
    var dy = y - r;
    var sx = x*scale - r;
    var sy = y*scale - r;
    cxt.save();
    cxt.beginPath();
    cxt.arc(x,y,r,0,Math.PI*2);
    cxt.lineWidth = 4;
    cxt.strokeStyle = '#069';
    cxt.stroke();
    cxt.clip();
    cxt.drawImage(drawingOff,sx,sy,2*r,2*r,dx,dy,2*r,2*r);
    cxt.restore();     
   }
  }
 } 
}
</script>

滤镜

下面利用canvas的getImageData()方法,获取原始图像数据,通过对图像数据进行修改,然后输出修改后的图像数据

<canvas id="drawing1" >
  <p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawing2" >
  <p>The canvas element is not supported!</p>
</canvas>
<br>
<button id="noGreen">无绿色</button>
<button id="noBlue">无蓝色</button>
<button id="toGrey">灰度</button>
<button id="toBlackWhite">黑白</button>
<button id="reverse">反色</button>
<script>
if(drawing1.getContext){
 var cxt1 = drawing1.getContext('2d');
 var cxt2 = drawing2.getContext('2d');
 var img = new Image();
 img.src="chunfen.jpg";
 img.onload = function(){
  cxt1.drawImage(img,0,0);
  function filter(fn){
   var imageData = cxt1.getImageData(0,0,img.width,img.height); 
   cxt2.clearRect(0,0,drawing2.width,drawing2.height); 
   var data = imageData.data;
   for(var i = 0, len = data.length; i < len; i+=4){
    fn(data,i)
   }
   imageData.data = data;
   cxt2.putImageData(imageData,0,0); 
  }
  function fnNoGreen(data,i){
   data[i+1] = 0;
  }
  function fnNoBlue(data,i){
   data[i+2] = 0;
  } 
  function fnReverse(data,i){
   var red = data[i];
   var green = data[i+1];
   var blue = data[i+2];
   var alpha = data[i+3];
   data[i] = 255 - red;
   data[i+1] = 255 - green;
   data[i+2] = 255 - blue;
  }    
  function fnToGrey(data,i){
   var red = data[i];
   var green = data[i+1];
   var blue = data[i+2];
   var alpha = data[i+3];
   var average = Math.floor((red+green+blue)/3);
   data[i] = data[i+1] = data[i+2] = average;   
  }  
  function fnToBlackWhite(data,i){
   var red = data[i];
   var green = data[i+1];
   var blue = data[i+2];
   var alpha = data[i+3];
   var average = Math.floor((red+green+blue)/3);
   if(average > 255/2){
    var result = 255;
   }else{
    var result = 0;
   }
   data[i] = data[i+1] = data[i+2] = result;    
  }
  toGrey.onclick = function(){
   filter(fnToGrey);
  }
  noGreen.onclick = function(){
   filter(fnNoGreen);
  } 
  noBlue.onclick = function(){
   filter(fnNoBlue);
  } 
  toBlackWhite.onclick = function(){
   filter(fnToBlackWhite);
  }
  reverse.onclick = function(){
   filter(fnReverse);
  } 
 }
}
</script>

马赛克效果

【普通模糊效果】

普通模糊效果不仅需要使用当前像素点,还需要使用周围的像素点,并把这些像素点都赋予平均值

function fnToBlur(n){
   cxt2.clearRect(0,0,drawing2.width,drawing2.height); 
   var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height); 
   var tempImageData = imageData;
   var data = imageData.data;
   var tempData = tempImageData.data;
   var blurR = n;
   var totalnum = (2*blurR + 1)*(2*blurR + 1);
   for(var i = blurR; i < drawing2.height - blurR; i++){
    for(var j = blurR; j < drawing2.width - blurR; j++){
     var totalr = 0, totalg = 0, totalb = 0;
     for(var dx = -blurR; dx <= blurR; dx++){
      for(var dy = -blurR; dy <= blurR; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       totalr += tempData[p*4+0];
       totalg += tempData[p*4+1];
       totalb += tempData[p*4+2];
      }
     }
     var p = i*drawing2.width + j;
     data[p*4+0] = totalr / totalnum;
     data[p*4+1] = totalg / totalnum;
     data[p*4+2] = totalb / totalnum;
    }
   }
   imageData.data = data;
   cxt2.putImageData(imageData,0,0); 
  }

【马赛克效果】

马赛克效果则是把一块区域的值,全部都赋予平均值

function fnToMosaic(n){
   cxt2.clearRect(0,0,drawing2.width,drawing2.height); 
   var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height); 
   var tempImageData = imageData;
   var data = imageData.data;
   var tempData = tempImageData.data;
   var size = n;
   var totalnum = size*size;
   for(var i = 0; i < drawing2.height; i+=size){
    for(var j = 0; j < drawing2.width; j+=size){
     var totalr = 0, totalg = 0, totalb = 0;
     for(var dx = 0; dx < size; dx++){
      for(var dy = 0; dy < size; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       totalr += tempData[p*4+0];
       totalg += tempData[p*4+1];
       totalb += tempData[p*4+2];
      }
     }
     var p = i*drawing2.width + j;
     var resr = totalr / totalnum;
     var resg = totalg / totalnum;
     var resb = totalb / totalnum;
     for(var dx = 0; dx < size; dx++){
      for(var dy = 0; dy < size; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       data[p*4+0]= resr;
       data[p*4+1]= resg;
       data[p*4+2]= resb;
      }
     }
    }
   }
   imageData.data = data;
   cxt2.putImageData(imageData,0,0); 
  }

下面是一个实例

<canvas id="drawing1" >
  <p>The canvas element is not supported!</p>
</canvas>
<canvas id="drawing2" >
  <p>The canvas element is not supported!</p>
</canvas>
<br>
<button id="toLightBlur">轻度模糊</button>
<button id="toHeavyBlur">重度模糊</button>
<button id="toLightMosaic">轻度马赛克</button>
<button id="toHeavyMosaic">重度马赛克</button>
<script>
if(drawing1.getContext){
 var cxt1 = drawing1.getContext('2d');
 var cxt2 = drawing2.getContext('2d');
 var img = new Image();
 img.src="chunfen.jpg";
 img.onload = function(){
  cxt1.drawImage(img,0,0);
  toLightBlur.onclick = function(){
   fnToBlur(1);
  }
  toHeavyBlur.onclick = function(){
   fnToBlur(3);
  }  
  toLightMosaic.onclick = function(){
   fnToMosaic(4);
  } 
  toHeavyMosaic.onclick = function(){
   fnToMosaic(9);
  }   
  function fnToBlur(n){
   cxt2.clearRect(0,0,drawing2.width,drawing2.height); 
   var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height); 
   var tempImageData = imageData;
   var data = imageData.data;
   var tempData = tempImageData.data;
   var blurR = n;
   var totalnum = (2*blurR + 1)*(2*blurR + 1);
   for(var i = blurR; i < drawing2.height - blurR; i++){
    for(var j = blurR; j < drawing2.width - blurR; j++){
     var totalr = 0, totalg = 0, totalb = 0;
     for(var dx = -blurR; dx <= blurR; dx++){
      for(var dy = -blurR; dy <= blurR; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       totalr += tempData[p*4+0];
       totalg += tempData[p*4+1];
       totalb += tempData[p*4+2];
      }
     }
     var p = i*drawing2.width + j;
     data[p*4+0] = totalr / totalnum;
     data[p*4+1] = totalg / totalnum;
     data[p*4+2] = totalb / totalnum;
    }
   }
   imageData.data = data;
   cxt2.putImageData(imageData,0,0); 
  }
  function fnToMosaic(n){
   cxt2.clearRect(0,0,drawing2.width,drawing2.height); 
   var imageData = cxt1.getImageData(0,0,drawing2.width,drawing2.height); 
   var tempImageData = imageData;
   var data = imageData.data;
   var tempData = tempImageData.data;
   var size = n;
   var totalnum = size*size;
   for(var i = 0; i < drawing2.height; i+=size){
    for(var j = 0; j < drawing2.width; j+=size){
     var totalr = 0, totalg = 0, totalb = 0;
     for(var dx = 0; dx < size; dx++){
      for(var dy = 0; dy < size; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       totalr += tempData[p*4+0];
       totalg += tempData[p*4+1];
       totalb += tempData[p*4+2];
      }
     }
     var p = i*drawing2.width + j;
     var resr = totalr / totalnum;
     var resg = totalg / totalnum;
     var resb = totalb / totalnum;
     for(var dx = 0; dx < size; dx++){
      for(var dy = 0; dy < size; dy++){
       var x = i + dx;
       var y = j + dy;
       var p = x*drawing2.width + y;
       data[p*4+0]= resr;
       data[p*4+1]= resg;
       data[p*4+2]= resb;
      }
     }
    }
   }
   imageData.data = data;
   cxt2.putImageData(imageData,0,0); 
  }  
 }
}
</script>

以上这篇使用canvas进行图像编辑的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
js/jQuery对象互转(快速操作dom元素)
Feb 04 Javascript
js随机生成网页背景颜色的方法
Feb 26 Javascript
JavaScript实现将数组中所有元素连接成一个字符串的方法
Apr 06 Javascript
jquery实现图片随机排列的方法
May 04 Javascript
javascript中基本类型和引用类型的区别分析
May 12 Javascript
c#程序员对TypeScript的认识过程
Jun 19 Javascript
javascript实现无缝上下滚动特效
Dec 16 Javascript
非常棒的jQuery图片轮播效果
Apr 17 Javascript
如何判断Javascript对象是否存在的简单实例
May 18 Javascript
angularjs中回车键触发某一事件的方法
Apr 24 Javascript
在vue中多次调用同一个定义全局变量的实例
Sep 25 Javascript
Element Cascader 级联选择器的使用示例
Jul 27 Javascript
jQuery实现锚点向下平滑滚动特效示例
Aug 29 #jQuery
js使用html2canvas实现屏幕截取的示例代码
Aug 28 #Javascript
JavaScript编写棋盘覆盖代码详解
Aug 28 #Javascript
Angular4开发解决跨域问题详解
Aug 28 #Javascript
JavaScript实现各种排序的代码详解
Aug 28 #Javascript
JS如何设置元素样式的方法示例
Aug 28 #Javascript
weex slider实现滑动底部导航功能
Aug 28 #Javascript
You might like
ajax在joomla中的原生态应用代码
2012/07/19 PHP
PHP使用PDO访问oracle数据库的步骤详解
2017/09/29 PHP
深入理解PHP中mt_rand()随机数的安全
2017/10/12 PHP
PHP耦合设计模式实例分析
2018/08/08 PHP
Yii框架使用PHPExcel导出Excel文件的方法分析【改进版】
2019/07/24 PHP
PHP正则之正向预查与反向预查讲解与实例
2020/04/06 PHP
jQuery1.6 使用方法二
2011/11/23 Javascript
js导航栏单击事件背景变换示例代码
2014/01/13 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
2014/03/06 Javascript
JavaScript中的prototype和constructor简明总结
2014/04/05 Javascript
详解JavaScript正则表达式中的global属性的使用
2015/06/16 Javascript
JavaScript数据结构学习之数组、栈与队列
2017/05/02 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
javascript 初学教程及五子棋小程序的简单实现
2017/07/04 Javascript
express框架中使用jwt实现验证的方法
2019/08/25 Javascript
layui 解决form表单点击无反应的问题
2019/10/25 Javascript
小程序实现tab标签页
2020/11/16 Javascript
[04:03]2014DOTA2西雅图国际邀请赛 LGD战队巡礼
2014/07/07 DOTA
在Docker上部署Python的Flask框架的教程
2015/04/08 Python
python实现字符串和日期相互转换的方法
2015/05/13 Python
python计算文本文件行数的方法
2015/07/06 Python
Python排序搜索基本算法之插入排序实例分析
2017/12/11 Python
Python图像处理之识别图像中的文字(实例讲解)
2018/05/10 Python
Python制作exe文件简单流程
2019/01/24 Python
python画微信表情符的实例代码
2019/10/09 Python
如何解决cmd运行python提示不是内部命令
2020/07/01 Python
Python importlib模块重载使用方法详解
2020/10/13 Python
美国创意之家:BulbHead
2017/07/12 全球购物
Java面试题:Java类的Main方法如果是Private将会怎么样
2016/08/18 面试题
就业推荐自我鉴定
2013/10/06 职场文书
高中语文课后反思
2014/04/27 职场文书
贷款委托书
2014/08/01 职场文书
2014国庆黄金周超市促销活动方案
2014/09/21 职场文书
企业年会祝酒词
2015/08/11 职场文书
2016年员工年度考核评语
2015/12/02 职场文书
课改心得体会范文
2016/01/25 职场文书