专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序猿  ·  “未来 3 年内,Python 在 AI ... ·  2 天前  
程序员的那些事  ·  惊!小偷“零元购”后竟向 DeepSeek ... ·  2 天前  
程序员小灰  ·  DeepSeek做AI代写,彻底爆了! ·  3 天前  
待字闺中  ·  DeepSeek 爆火带来的大变化 ·  1 周前  
51好读  ›  专栏  ›  SegmentFault思否

Canvas 基本图片操作与处理

SegmentFault思否  · 公众号  · 程序员  · 2020-03-17 11:48

正文

本文转载于 SegmentFault 社区
社区专栏:前端进阶之路
作者:william




前言



Canvas H5 中新增的技术,主要运用在图片的处理和动画的绘制上,随着 Canvas 的使用场景越来越多,了解 Canvas 对平时开发大有裨益,这篇文章将介绍 Canvas 基本图片操作与处理。



图片上传与绘制



将图片上传并绘制到 Canva 中是最常见的 Canvas 的图片处理,这个上传与绘制的过程是怎么实现的呢?下面举个例子:

id="myCanvas">
type="file" id="file">
let upload = document.getElementById('file')
upload.onchange = (event) => {
let file = event.target.files[0]
let fileReader = new FileReader()
fileReader.onload = (e) => {
let img = new Image()
img.src = e.target.result
img.onload = () => {
let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.drawImage(img, 0, 0)
}
}
fileReader.readAsDataURL(file)
}
这个上传与绘制的过程可以总结为两步:

  • 通过 FileReader 对象将 input 上传的 file 对象转化为 base64 格式的图片
  • 创建 Image 对象,将对象绘制在 canvas

这里为什么要将 base64 格式的地址复制给 Image 对象,然后再将 Imag e 对象绘制到 Canvas 上而不是直接绘制呢?

这是因为
Canvas 上绘制时并不支持 url 作为图片源, Canvas 只支持下面几种图片源:

  • Image () 函数构造的或者任何 元素
  • 另一个 元素作为源
  • 高性能位图作为图片源

Canvas 在绘图时还有一个需要注意的点就是: Canvas 在绘制不同域名下的图片会出现跨域的错误,如图:


被污染的 Canvas ,其实就是因为图片跨域的问题的,这时需要两步走:

  • 图片服务器响应头添加 Access-Control-Allow-Origin * 或者指定域名
  • 设置 Image crossOrigin 属性:
    img.setAttribute("crossOrigin",'Anonymous')

简单示例代码:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.drawImage(img, 0, 0)
console.log(canvas.toDataURL('image/png', 1.0))
}


图片变换



1. 图片缩放


Canvas 中图片缩放的实际上是通过画布的缩放来达到的,因此默认的缩放中心是在画布原点 (0, 0) ,但是一般情况下我们做缩放时都希望图片中心是缩放中心,这里有两种办法能达到图片中心作为缩放中心的缩放效果,接下来分别来看这两种办法的示例:

第一种:

let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.translate(img.width / 2, img.height / 2)
context.scale(0.5, 0.5)
context.translate(-img.width / 2, -img.height / 2)
context.drawImage(img, 0, 0, img.width, img.height)
第一种方法就是画布平移,先将画布原点移到图像中心,然后再做画布缩放,再将画布平移还原,最后绘制图片,此时绘制的图片就是以图片中心做的缩放。

第二种:

let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
let paintWidth = img.width / 2
let paintHight = img.height / 2
let originX = 0 // 原图片X坐标
let originY = 0 // 原图片Y坐标
let paintX = originX + (img.width - paintWidth) / 2 // 缩放后的图片X坐标
let paintY = originY + (img.height - paintHight) / 2 // 缩放后的图片Y坐标
context.drawImage(img, paintX, paintY, paintWidth, paintHight)
第二种就是最直接的计算当图片以左上角作为缩放中心,缩放后的图片位置产生的位置偏移,将位置偏移加上在进行图片绘制。

2. 图片旋转


Canvas 的图片旋转和图片缩放一样,默认的旋转中心也是画布的原点 (0, 0) ,此时也需要平移画布来实现图片的中心旋转,举个例子:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.translate(img.width / 2, img.height / 2)
context.rotate(30 * Math.PI / 180)
context.translate(-img.width / 2, -img.height / 2)
context.drawImage(img, 0, 0, img.width, img.height)
}

3. 镜像变换


镜像变换可以以图片垂直中线为对称轴,左右镜像的变换叫水平镜像,或者水平中线为对称轴,上下镜像的变换叫垂直镜像,一般水平镜像用的比较多,这里就来看一个水平镜像的例子:

let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.translate(img.width / 2, img.height / 2)
context.scale(-1 , 1)
context.translate(-img.width / 2, -img.height / 2)
context.drawImage(img, 0, 0, img.width, img.height)
}
原图:



水平镜像:


镜像操作的原理其实很简单:就是将 scale 设置为负值,当 x 轴的缩放为负值时,就是水平镜像,当 y 轴的缩放为负值时就是垂直镜像。

4. 对称轴翻转


对称轴翻转指的是图片沿着左上角至右下角的对角线翻转,来看用代码 Canvas 是怎么实现的:
let img = new Image()
img.setAttribute("crossOrigin",'Anonymous')
img.src = './images/avatar.jpeg'
img.onload = () => {
let canvas = document.getElementById('myCanvas')
canvas.width = img.width
canvas.height = img.height
let context = canvas.getContext('2d')
context.translate(img.width / 2, img.height / 2)
context.scale(-1 , 1)
context.rotate(90 * Math.PI / 180)
context.translate(-img.width / 2, -img.height / 2)
context.drawImage(img, 0, 0, img.width, img.height)
}
翻转图:


实现原理:先做水平镜像,然后顺时针旋转 90 度,由于先做的水平镜像,坐标轴会被水平翻转,顺时针旋转 90 度实际是逆时针旋转 90 度。





图片灰度







请到「今天看啥」查看全文