• JS VUE 用 canvas 给图片加水印


    最近写需求,遇到要给图片加水印的需求。 刚开始想的方案是给图片上覆盖一层水印照片,但是这样的话用户直接下载图片水印也会消失。
    后来查资料发现用 canvas 就可以给图片加水印,下面是处理过程。

    请添加图片描述
    首先我们要确认图片的格式,我们通过 input 上传的图片格式一般是 File (File 对象是特殊类型的 Blob)即 Blob 格式。
    这样的话,我们需要先把 Blob 文件转成 img 标签。先通过 FileReader 读取文件,通过 reader.readAsDataURL 获得文件 Base 64 编码 URL 地址,拿到 URL 后,生成 img 标签。
    在把 img 绘制到 canvas 画布上,然后在用 createPattern 叠加一层水印,在把 canvas 文件转成 Base 64 格式 url 直接显示到页面上,或者转成 Blob 格式上传给后端。

    1. Blob 文件转成 img 标签

    	// blob 文件格式转成 img 标签
        const blobToImg = (blob) => {
          return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.readAsDataURL(blob)
            reader.onload = () => {
              let img = new Image()
              img.src = reader.result
              img.addEventListener('load', () => resolve(img))
            }
          })
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    这里要注意,如果使用 addEventListener 需要先注册事件监听。

    const blobToImg = (blob) => {
          return new Promise((resolve, reject) => {
            const reader = new FileReader()
            reader.addEventListener('load', () => {
              let img = new Image()
              img.src = reader.result
              img.addEventListener('load', () => resolve(img))
            })
            reader.readAsDataURL(blob)
          })
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2. img 标签转成 canvas

     // 将img内容绘制到canvas画布
        imgToCanvas(img) {
          const canvas = document.createElement('canvas')
          canvas.width = img.width
          canvas.height = img.height
          const context = canvas.getContext('2d')
          context.drawImage(img, 0, 0)
          return canvas
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3. 在 canvas 画布上绘制水印

    水印通过 ctx.createPattern(image, repetition) 方法来进行重复绘制,由于 image 参数要是是 img 标签格式或者 canvas 文件格式,所以我们可以让 UI 老师生成一个水印的图片,或者我们用 canvas 自己画一个水印的图片进行复制。

    1. 如果我们需要直接生成图片来进行展示,那我们可以用 canvas.toDataURL() 直接从 canvas 生成图片地址。

    2. 如果需要生成 Blob 格式传给后端,那我们可以用 canvas.toBlob() 方法从 canvas 生成 Blob 文件格式,传给后端。

        // canvas画布上绘制水印
        waterMark(canvas) {
          return new Promise((resolve, reject) => {
            const ctx = canvas.getContext('2d')
            // 绘制水印 canvas
            const canvasWater = this.drawWaterCanvas('已失效')
            // 绘制重复的水印
            ctx.fillStyle = ctx.createPattern(canvasWater, 'repeat')
            ctx.fillRect(0, 0, canvas.width, canvas.height)
            // 这里我需要直接展示,所以就直接生成图片地址
            resolve(canvas.toDataURL())
            
          })
        },
        drawWaterCanvas(str) {
          const canvasWater = document.createElement('canvas')
          canvasWater.width = 400
          canvasWater.height = 400
          const ctxWater = canvasWater.getContext('2d')
          ctxWater.textAlign = 'left'
          ctxWater.textBaseline = 'middle'
          ctxWater.font = '32px Microsoft Yahei'
          ctxWater.fillStyle = 'rgba(0, 0, 0, 0.3)'
          ctxWater.rotate((-20 * Math.PI) / 180)
          ctxWater.fillText(str, 10, 80)
          return canvasWater
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    4. VUE 中实际应用

    <template>
      <div>
        <img :src="imgUrl" alt="" />
      div>
    template>
    
    <script>
    import loppy from './assets/loppy.jpg'
    
    export default {
      data() {
        return {
          imgUrl: ''
        }
      },
      created() {
        const img = new Image()
        img.src = loppy
        img.onload = async () => {
          const canvas = this.imgToCanvas(img)
          const url = await this.waterMark(canvas)
          this.imgUrl = url
        }
      },
      methods: {
        // 将img内容绘制到canvas画布
        imgToCanvas(img) {
          const canvas = document.createElement('canvas')
          canvas.width = img.width
          canvas.height = img.height
          const context = canvas.getContext('2d')
          context.drawImage(img, 0, 0)
          return canvas
        },
        // canvas画布上绘制水印并转换为blob对象
        waterMark(canvas) {
          return new Promise((resolve) => {
            const ctx = canvas.getContext('2d')
            // 绘制水印 canvas
            const canvasWater = this.drawWaterCanvas('图片已失效')
            // 绘制重复的水印
            ctx.fillStyle = ctx.createPattern(canvasWater, 'repeat')
            ctx.fillRect(0, 0, canvas.width, canvas.height)
            resolve(canvas.toDataURL())
          })
        },
        drawWaterCanvas(str) {
          const canvasWater = document.createElement('canvas')
          canvasWater.width = 500
          canvasWater.height = 500
          const ctxWater = canvasWater.getContext('2d')
          ctxWater.textAlign = 'left'
          ctxWater.textBaseline = 'middle'
          ctxWater.font = '32px Microsoft Yahei'
          ctxWater.fillStyle = 'rgba(0, 0, 0, 0.3)'
          ctxWater.rotate((-20 * Math.PI) / 180)
          ctxWater.fillText(str, 10, 200)
          ctxWater.fillText(new Date().toLocaleString(), 10, 300)
          return canvasWater
        }
      }
    }
    script>
    
    <style lang="scss" scoped>
    img {
      width: 200px;
      height: 200px;
    }
    style>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71

    在这里插入图片描述

  • 相关阅读:
    机器学习理论基础—支持向量机的推导(一)
    (200,10)和(10,)的ndarray数组怎么计算内积,得到的是什么维度?
    现有TiDB集群扩展pump/drainer作为binlog文件落地
    HTML进阶(5)- 其他元素
    自定义组件 - Message 消息提示
    工业物联网:基于数字孪生的车间物流与制造智能同步制造系统
    <input> 实现输入框只能输入数字(个人认为最好的)
    【postgresql 基础入门】表的操作,表结构查看、修改字段类型、增加删除字段、重命名表,对表的操作总是比别人棋高一着
    4.jvm入门到精通
    c++中和c语言不相同的地方
  • 原文地址:https://blog.csdn.net/alokka/article/details/133800154