美文网首页
canvas裁剪图片,蒙版选择框

canvas裁剪图片,蒙版选择框

作者: philoZhe | 来源:发表于2018-02-05 19:57 被阅读135次

    标签: 前端


    [toc]

    前言

    经常都会遇到一些上传图片前裁剪的需求,这个时候一般都会找到第三方的插件来完成需求。但有时(很不幸)会遇到一些难以处理的情况,例如找不到满足需求的插件或者插件太大而只用到其中一个功能,这种时候就需要自己动手实现一个裁剪工具了。

    因此了解一下如何用canvas来实现裁剪功能(其实可以做到更多)是很有必要的,那么现在就开始吧:

    原理

    分为以下几个步骤

    1. 读取本地图片文件
    2. 图片处理
    3. 输出图片

    好像有点太简略。。

    简单的例子

    下面讲一下自己的例子,功能就是读取图片,左右两个canvas,左边有个半透明蒙版选择裁剪大小,右边输出裁剪后图片。

    读取文件

    <input type="file">读取本地文件,监听onchange事件,使用Image对象来做个中转方便canvas使用

    // 这个img可以供canvas绘图
    const img = new Image() 
    input.onchange = function(e) {
        const file = e.target.files[0]
        const reader = new FileReader()
        reader.readAsDataURL(file)
        reader.onload = function(e) {
          img.src = e.target.result
        }
    }
    

    canvas图片处理

    这个例子是鼠标框选截图,因此先加上鼠标事件

    let dragging = false
    let startX, startY
    // 实现拖拽时触发事件
    canvas.addEventListener('mousedown', e => {
      dragging = true
      // canvas内部的鼠标位置
      startX = e.offsetX
      startY = e.offsetY
    }
    canvas.addEventListener('mousemove', e => {
      if (!dragging) return
      // ... 裁剪逻辑
      // ... 立即截图
      // 鼠标移出canvas也要使dragging = false
    }
    canvas.addEventListener('mouseup', e => {
      dragging = false
    })
    

    画个镂空的蒙版表示选择框,这里用到globalCompositeOperation,图片合并效果来实现蒙版,具体见MDN

    // 前面已经获取了startX, startY
    const ctx = canvas.getContext('2d')
    canvas.addEventListener('mousemove', e => {
      if (!dragging) return
      // ... 裁剪逻辑
      
      // 每帧都要清理画布,这里400是canvas的内部像素长宽,不是css的长宽
      ctx.clearRect(0, 0, 400, 400)
      
      // 绘制蒙版
      ctx.save()
      ctx.fillStyle = 'rgba(0,0,0,0.5)'
      ctx.fillRect(0, 0, 400, 400)
      // 开启镂空合并
      ctx.globalCompositeOperation = 'desination-out'
      const currentX = e.offsetX
      const currentY = e.offsetY
      ctx.fillStyle = 'white' // 什么颜色没所谓
      ctx.fillRect(startX, startY, currentX - startX, currentY - startY)
      ctx.restore()
      
      // 绘制底图
      ctx.save()
      // 将图片绘制到蒙版下方
      ctx.globalCompositeOperation = 'destination-over'
      // 参数是:图片;读取图片的起点,长宽;画在canvas上的起点,长宽;
      ctx.drawIamage(img, 0, 0, img.width, img.height, 0, 0, 400, 400)
      ctx.restore()
     
      // ...立即截图
      
      // 鼠标移出canvas也要使dragging = false
    }
    
    

    这样就实现了图片蒙版选择框,下面是截图,很简单

    canvas.addEventListener('mousemove', e => {
      if (!dragging) return
      // ... 裁剪逻辑
      
      // 立即截图
      const data = ctx.getImageData(startX, startY, currentX - startX, currentY - startY)
      // 输出在另一个canvas上
      resultCtx.clearRect(0,0,400,400)
      resultCtx.putImage(data, 0, 0)
      
      // 鼠标移出canvas也要使dragging = false
    }
    

    输出图片

    很简单,用到canvas.toBlob输出二进制数据,然后转File就可以

    const mime = 'image/jpeg' // image/png
    resultCanvas.toBlob(blob => {
      // 注意是`[blob]`
      const file = new File([blob], '图片.jpg', { type: blob.type })
      // uploadFile(file)
    }, mime, 0.9)
    

    一些哲学♂

    对实现一个功能感到不知所措的时候,很可能就是对基础的api不熟悉,就像这个例子中,如果不知道canvas有getImageData,putImageData这两个api,那么就不知道如何实现裁剪了,然后就陷入不停找插件的困境。所以,不知道怎么办时别慌,找找js的api。

    相关文章

      网友评论

          本文标题:canvas裁剪图片,蒙版选择框

          本文链接:https://www.haomeiwen.com/subject/fciizxtx.html