用canvas给图片换个角度

47 阅读2分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第4天,点击查看活动详情

前言

工作中很多地方需要对图片进行处理,我们在前端开发中经常用到Canvas对图片进行处理, CanvasAPI(画布)是在HTML5中新增的标签用于在网页实时生成图像,并且可以操作图像内容,基本上它是一个可以用JavaScript操作的位图(bitmap)。今天我们就用Canvas开发一个对图像旋转角度并且导出的功能。

开始

我们先创建一个canvas

document.createElement('canvas')

使用getContext() 方法获取canvas对象,getContext() 方法返回一个用于在画布上绘图的环境。

canvas.getContext('2d')

我们直接创建一个方法rotateImg,方便后续调用,

 function rotateImg(src, edg) {
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')
          }

接下来我们要获取图片宽高、画布大小、图片旋转象限以及裁剪坐标,以上这些操作需要在image.onload中进行,因为要确保图片已经完成加载完成, 在image.onload之前我们需要创建image,即new Image()。

在创建 Image 对象后,如果没有给它的 width 和 height 属性赋值,那它的 width 和 height 的默认值都为0。有可能你会问,我将 Image对象插入到 HTML页面中并且已经显示出来了,那为什么 width 和 height 还是0呢?其实大家都忽略了一个最重要的问题,就是 HTML代码的加载 和 图片的加载 所用的时间。

HTML代码的加载 和 图片的加载是同时的,虽然 图片已经进行过预加载,但是尽管这样 加载的速度 相比较 HTML 代码的加载速度 还是要慢一些的。

因此,就需要用 Image对象中的 onload事件来解决这个问题了。

function rotateImg(src, edg) {
          const canvas = document.createElement('canvas')
          const ctx = canvas.getContext('2d')
          let imgW// 图片宽度
          let imgH// 图片高度
          let size// canvas初始大小
          if (edg % 90 != 0) {
            console.error('旋转角度必须是90的倍数!')
          }
          (edg < 0) && (edg = (edg % 360) + 360)
          const quadrant = (edg / 90) % 4 // 旋转象限
          const coor = { sx: 0, sy: 0, ex: 0, ey: 0 } // 裁剪坐标
          const image = new Image()
          image.crossOrigin = 'anonymous'
          image.src = src
          image.onload = function() {
            imgW = image.width
            imgH = image.height
            size = imgW > imgH ? imgW : imgH
            canvas.width = size * 2
            canvas.height = size * 2
          }
        }

下面我们就用switch判断选中的角度,并对应的进行设置裁剪坐标

function rotateImg(src, edg) {
...
    switch (quadrant) {
          case 0:
          coor.sx = size
          coor.sy = size
          coor.ex = size + imgW
          coor.ey = size + imgH
            break
          case 1:
            coor.sx = size - imgH
            coor.sy = size
            coor.ex = size
            coor.ey = size + imgW
            break
          case 2:
            coor.sx = size - imgW
            coor.sy = size - imgH
            coor.ex = size
            coor.ey = size
            break
          case 3:
            coor.sx = size
            coor.sy = size - imgW
            coor.ex = size + imgH
            coor.ey = size + imgW
            break
       }
    ctx.translate(size, size)
    ctx.rotate(edg * Math.PI / 180)
    ctx.drawImage(image, 0, 0)
}

然后用getImageData来获取canvas画布上指定矩形区域的像素数据。

注意:getImageData按照从左到右,从上到下的顺序去存储像素点信息的

在getImageData之后我们需要通过 putImageData() 将图像数据放回画布

最后用toDataURL将canvas对象转换为base64位编码

最最后导出,我们就创建一个a标签,模拟点击进行导出

const a = document.createElement('a')
      a.href = img.src
      a.download=''
      a.click()

结束