从web图片裁剪出发:了解H5中的canvas
本篇内容不针对canvas文档对每个api进行逐个的详解!
本篇内容不针对canvas文档对每个api进行逐个的详解!
本篇内容不针对canvas文档对每个api进行逐个的详解!
重说三,好了,现在进入正文。在上一回《从web图片裁剪出发:了解H5中的blob》中我解释了图片在浏览器中以怎样的形式留存,并且在最后一个example中演示了选择图片、预览最后提交的过程。然而这个预览并没有起到什么卵用,因为只能预览不能处理,原图片还是原图片,预览变得可有可无。这一篇我们就在预览这一步里做点手脚,加入处理图片的功能。
我们先修改之前的example,既然要处理图片,肯定要引入canvas,所以我们把原来img这个标签去掉,取而代之的是canvas,并在js中加入对应的修改。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form name='test'>
<input type="file" name='file'>
<input type="submit" value="提交">
</form>
<canvas width="0" height="0"></canvas>
<script>
var canvas = document.querySelector('canvas'),
ctx = canvas.getContext('2d'),
preview = new Image();
document.test.file.addEventListener('change', function() {
var fr = new FileReader();
fr.onload = function() {
preview.src = this.result;
canvas.width = preview.width;
canvas.height = preview.height;
drawImage();
};
fr.readAsDataURL(this.files[0]);
})
function drawImage() {
ctx.drawImage(preview, 0, 0); //把图片绘制到canvas上
}
document.test.addEventListener('submit', function(e) {
e.preventDefault();
var formData = new FormData(),
xhr = new XMLHttpRequest(),
mime = 'image/jpeg',
dataUrl = canvas.toDataURL(mime, 0.8), //取出base64
data = atob(dataUrl.split(',')[1]),
n = data.length,
uInt8 = new Uint8Array(n),
blob;
while(n--) {
uInt8[n] = data.charCodeAt(n);
}
blob = new Blob([uInt8.buffer], {type: mime});
formData.append('file', blob, 'test.jpg');
xhr.open('post', '/upload');
xhr.send(formData);
})
</script>
</body>
</html>
之前example的canvas版实现了,现在我们加入处理图片的功能。首先我们加入裁剪的功能,裁剪的引入必须先引入橡皮筋功能,就是一个选取框。一般我们见过的选取框是这样的。

预览的样子

选取一部分的样子
我们来分析下实现这样一个功能需要做什么。首先选取框有个开始点和结束点,在鼠标按下去的时候确定开始点,在松开的时候确定结束点,在移动的时候还要不停的绘制。那么绘制一个有选取框的内容分几步呢?第一步是绘制底图,第二步是绘制阴影,第三部还是绘制底图,但是只作用于选取框内部。最后想取消选取框怎么办,我们还要有个方法重置开始点和结束点,并且只绘制底图。
我们一步一步来,首先确定开始点和结束点。
var sPoint = {},
ePoint = {};
canvas.addEventListener('mousedown', function(e) {
if(e.button === 0) {
sPoint.x = e.offsetX;
sPoint.y = e.offsetY;
sPoint.drag = true;
}
});
然后我们确定绘制阴影的的方法,并且在鼠标按下去移动的时候不停的绘制。
function drawCover() {
ctx.save();
ctx.fillStyle = 'rgba(0, 0, 0, 0.3)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.restore();
}
canvas.addEventListener('mousemove', function(e) {
if(e.button === 0 && sPoint.drag) {var nPoint = {
x: e.offsetX,
y: e.offsetY
};
ctx.save(); //clip要通过restore回复
ctx.clearRect(0, 0, canvas.width, canvas.height); //画布全清
drawImage(); //绘制底图
drawCover(); //绘制阴影
ctx.beginPath(); //开始路径
ctx.rect(sPoint.x, sPoint.y, nPoint.x - sPoint.x, nPoint.y - sPoint.y); //设置路径为选取框
ctx.clip(); //截取路径内为新的作用区域
drawImage(); //在选取框内绘制底图
ctx.restore(); //恢复clip截取的作用范围
}
});
最后我们添加松开鼠标的事件监听,松开左键为拖动结束,松开右键为复原
canvas.addEventListener('mouseup', function(e) {
if(e.button === 0) {
sPoint.drag = false;
ePoint.x = e.offsetX;
ePoint.y = e.offsetY;
}else if(e.button === 2) {
restore();
}
});
function restore() {
sPoint = {};
ePoint = {};
drawImage();
}
由于右键会出现恶心的浏览器自带菜单栏,影响体验,我们屏蔽它。
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
e.stopPropagation();
});
现在选取框有了,我们要开始截取了。新添加一个按钮,然后添加点击监听。
html代码
<form name='test'>
<input type="file" name='file'>
<button id="clip">裁剪</button>
<input type="submit" value="提交">
</form>
js代码
var clip = document.querySelector('#clip');
clip.addEventListener('click', function(e) {
e.preventDefault(); //阻止默认事件,不然会触发form的submit
if(sPoint.x !== undefined && ePoint.x !== undefined) {
var imgData = ctx.getImageData(sPoint.x, sPoint.y, ePoint.x - sPoint.x, ePoint.y - sPoint.y); //把裁剪区域的图片信息提取出来
ctx.clearRect(0, 0, canvas.width, canvas.height); //清空画布
canvas.width = Math.abs(ePoint.x - sPoint.x); //重置canvas的大小为新图的大小
canvas.height = Math.abs(ePoint.y - sPoint.y);
ctx.putImageData(imgData, 0, 0); //把提取出来的图片信息放进canvas中
preview.src = canvas.toDataURL(); //裁剪后我们用新图替换底图,方便继续处理
}else {
alert('没有选择区域');
}
});
现在我们裁剪后选择提交,会发现服务器生成的是裁剪后的图片

裁剪的功能完成了,我们在来实现第二个功能:灰度。如果说裁剪的功能在于clip的用法,那么灰度的实现是基于getImageData返回的对象的认识。这个对象中有一个属性叫data,这是一个数组,以4个为一组,分别存储了一个像素red、green、blue、opacity四个数据。也就是当你的canvas尺寸为1*1时,它的ImageData.data元素为4个。
废话不多说,直接给出实现的代码。
html代码
<form name='test'>
<input type="file" name='file'>
<button id="clip">裁剪</button>
<button id="grey">灰度</button>
<input type="submit" value="提交">
</form>
js代码
var grey = document.querySelector('#grey');
grey.addEventListener('click', function(e) {
e.preventDefault();
var startX = 0, startY = 0, width = canvas.width, height = canvas.height;
ctx.clearRect(0, 0, canvas.width, canvas.height); //一如既往的先清空画布,不然会处理含有选取框的图片内容
drawImage(); //绘制底图
var imgData = ctx.getImageData(startX, startY, width, height); //把整个底图的图片内容取出来
for(var i = 0; i < imgData.data.length;) {
var red = imgData.data[i],
green = imgData.data[i+1],
blue = imgData.data[i+2],
opacity = imgData.data[i+3], //不处理,可以省去这一行,占位说明这一位是透明度
average = (red + green + blue) / 3; //所谓灰度其实是取三种颜色的平均值
imgData.data[i] = imgData.data[i+1] = imgData.data[i+2] = average; //三个颜色设为一样即是对应的灰色
i += 4;
}
ctx.putImageData(imgData, startX, startY, 0, 0, width, height); //把处理过的imagedata放回canvas中
preview.src = canvas.toDataURL(); //保存图片信息方便再进行处理
});
选择灰度并提交,我们看服务器上生成的图片

最后我们结合裁剪和灰度,一起处理一张图片再提交。

好了,简单的两个图片处理的方式就介绍到这,至于复杂的,你可以拿到每一个像素的信息,还担心实现不了其他的功能么。
从web图片裁剪出发:了解H5中的canvas的更多相关文章
- 从web图片裁剪出发:了解H5中的Blob
刚开始做前端的时候,有个功能卡住我了,就是裁剪并上传头像.当时两个方案摆在我面前,一个是flash,我不会.另一个是通过iframe上传图片,然后再上传坐标由后端裁剪,而我最终的选择是后者.有人会疑惑 ...
- 关于H5中的Canvas API的探索
Canvas API 是H5中比较炫酷的一部分内容.可以通过它动态的生成和展示图形.图表.图像以及动画.下面我将学习一下Canvas API. 最后有书籍和源码. 一.概述: 1.基本元素: 在网页上 ...
- 用H5中的Canvas等技术制作海报
在去年的时候也实现过合成海报的功能,不过当时时间仓促,实现的比较简单. 就一个旋转功能,图片也不能拖动放大,也不能裁剪. 去年的实现可以参考<移动图片操作--上传>和<移动图片操作- ...
- H5中标签Canvas实现图像动画
一:主题部分 1.介绍 canvas可以实现画图功能,所以只要通过js的控制,就可以实现简单的动画效果. 这里主要是两个程序,一个小球来回上下弹跳,一个是吹气球. 2.弹跳程序 <!DOCTYP ...
- H5图片裁剪升级版
前段时间做了个跟裁剪相关的活动<用H5中的Canvas等技术制作海报>,这次公司要做个与奥运相关的活动,扫车牌赢奖. 于是我就在上一个活动的基础上,将代码重新封装一下,并且将计算方式写的更 ...
- H5图片裁剪升级版(手机版)
前段时间做了个跟裁剪相关的活动<用H5中的Canvas等技术制作海报>,这次公司要做个与奥运相关的活动,扫车牌赢奖. 于是我就在上一个活动的基础上,将代码重新封装一下,并且将计算方式写的更 ...
- Android大图片裁剪终极解决方案(上:原理分析)
转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...
- 使用canvas进行图片裁剪简单功能
1.html部分 使用一个input[type="file"]进行图片上传: canvas进行图片的裁剪展示 <div> <input type="fi ...
- web开发实战--图片裁剪和上传
前言: 最近的开发中, 有一个上传头像的任务. 由于头像本身的特殊性, 其一般流程为选择图片, 编辑裁剪区域, 再继而上传图片操作. 看似简单的东西, 实则是挺麻烦的一件事. 借助这次开发机会, 来具 ...
随机推荐
- C++ STL map详解
一.解释: p { margin-bottom: 0.25cm; direction: ltr; color: #00000a; line-height: 120%; text-align: just ...
- NYOJ--46--最少乘法次数
最少乘法次数 时间限制:1000 ms | 内存限制:65535 KB 难度:3 描述 给你一个非零整数,让你求这个数的n次方,每次相乘的结果可以在后面使用,求至少需要多少次乘.如24:2*2 ...
- CentOS Linux 系统 英文 改中文
CentOS Linux 系统 英文 改中文 首先,使用root用户登录Linux系统,然后进入打开终端(桌面上右键第四个选项,应该是),然后进入到etc/sysconfig目录下
- 封装sqlhelper类
using System;using System.Collections.Generic;using System.Data;using System.Data.Common;using Syste ...
- 打鼹鼠 HNOI 2004
动态规划题从题目中可以发现是一个时间递增的过程,所以只要是在后面的点都是后出现的,换句话说,在条件达成时,前面的点可以到达后面的点,求最长的一条链,非常的像LIS(最长上升子序列),只要将 f[i]& ...
- 基于 Laravel 开发 ThinkSNS+ 中前端的抉择(webpack/Vue)踩坑日记【ThinkSNS+研发日记系列】
在上一篇文章< ThinkSNS+基于Laravel master分支,从1到 0,再到0.1>,简单的介绍了 社群系统ThinkSNS+ ,这里分享在开发过程中,前端选择的心理活动. L ...
- tomcat websocket 实现网页在线即时聊天
背景介绍 近一个月完成了公司的一个项目,负责即时聊天部分 寻找了一下,决定使用websocket,要问原因的话,因为tomcat 自带相关消息收发的API,用起来方便 闲话少叙,进入实现步骤 使用工具 ...
- HTML5——css基础语法
1.了解CSS CSS是一种用来表现HTML等文件样式的计算机语言,是对HTMl文件中设置的各种标签添加各种各样的样式与表达方式,让网页更生动,更美观. 2.导入CSS的三种方式 1.行内样式表:直接 ...
- 再学python类(终结篇)
续写 初学python类,这几天吃坏东西了,拖着虚弱的身躯写的.有些乱请各位看官海涵. 声明:本人编程新手,还在学习中.所表述的东西都是基础语法之类的,分享我的学习笔记.还望多多指点,我一定虚心接受. ...
- 再说php依赖注入
前段时间,有朋友问我yii2的依赖注入是怎么个玩法,好吧, 经常看到却一直不甚理解的概念,这里我再对自己认识的依赖注入深刻的表达下我的理解,依赖注入(DI)以及控制器反转(Ioc). 依赖注入就是组件 ...