本文正在参与「金石方案 . 分割6万现金大奖」

写在开头

哈喽,各位倔友们又见面了,本章咱们继续来共享一个实用小技巧,给图片加水印功用,水印功用的目的是为了保护网站或作者版权,防止内容被他人运用或白嫖。

可是网络中,是没有绝对安全的,咱们只能尽可能去完善安全机制,像水印功用也只能是防君子,防不了小人。

下面小编画了一张增加水印的简易流程图

运用canvas给上传的整张图片增加平铺的水印

制作图片

接下来,进入文章主题,既然是要给图片增加水印,那么咱们先来把图片制作到 canvas 上,详细如下:

<template>
  <div>
    <input type="file" @change="upload" /><br /><br />
    <canvas id="canvas" />
  </div>
</template>
<script>
export default {
  methods: {
    upload(e) {
      const file = e.target.files[0];
      if (!file) return;
      const filePath = window.URL.createObjectURL(file); // 创建文件的暂时途径: blob:http://localhost:8081/0cd115e2-9d4a-4c67-a86b-77e84d6f61db
      const img = new Image();
      img.src = filePath;
      img.onload = () => {
        this.addWaterMark(img);
      }
    },
    addWaterMark(img) {
      // const canvas = document.createElement('canvas');
      const canvas = document.getElementById('canvas');
      const imgWidth = img.width;
      const imgHeight = img.height;
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0); // 制作图片
    }
  },
};
</script>
<style scoped>
#canvas {
  border: 1px solid red;
}
</style>
运用canvas给上传的整张图片增加平铺的水印

整体代码不难,为了便利演示,小编直接把 canvas 放在 template 中,但真实运用场景下你能够运用 document.createElement('canvas') 来创建 Dom 并在运用完毕后删除相关 DOM,这样才是比较好的办法唷。(✪✪)

还有便是运用 ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) API 来制作图片。

作为一名前端人员小编期望你对 canvas 多多少少要有一点了解哦,不能说通晓,可是基础知识咱们要把握哦。

制作水印

把图片制作到 canvas 后,接下来咱们来把水印也给整上。

<script>
export default {
  methods: {
    upload(e) { ... },
    addWaterMark(img) {
      const canvas = document.getElementById('canvas');
      const imgWidth = img.width;
      const imgHeight = img.height;
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      // 画笔款式
      ctx.textAlign = 'left';
      ctx.textBaseline = 'top';
      ctx.font = '12px Microsoft Yahei';
      ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
      ctx.fillText('橙或人', 0, 0);
      ctx.fillText('2022年11月22日 09:22:30', 0, 20);
    }
  },
};
</script>
运用canvas给上传的整张图片增加平铺的水印

上图左上角能看到咱们很简单就把水印加上了,当然,这还达不到产品司理的要求,咱们需要把水印平铺开来,防止他人轻易经过截图就把水印清除了。

制作平铺水印

而这个平铺进程也很简单,只需循环去改动 ctx.fillText(text, x, y);xy 就行了,且来看看小编是如何来做的:

<script>
export default {
  methods: {
    upload(e) { ... },
    addWaterMark(img) {
        const canvas = document.getElementById('canvas');
        const imgWidth = img.width;
        const imgHeight = img.height;
        canvas.width = imgWidth;
        canvas.height = imgHeight;
        const ctx = canvas.getContext('2d');
        ctx.drawImage(img, 0, 0);
        // 画笔款式
        ctx.textAlign = 'left';
        ctx.textBaseline = 'top';
        ctx.font = '12px Microsoft Yahei';
        ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
        // ctx.fillText('橙或人', 0, 0);
        // ctx.fillText('2022年11月22日 09:22:30', 0, 20);
        // 平铺水印
        const name = '橙或人';
        const date = '2022年11月22日 09:22:30';
        const height = 120;
        const width = 200;
        let i = 0;
        let j = 0;
        const waterMarkerWidth = ctx.measureText(name).width;
        ctx.rotate(-20 * Math.PI / 180);
        for (i = 0; i <= imgWidth / (waterMarkerWidth) + 100; i++) {
          for (j = 0; j <= imgHeight / (height - 20) + 100; j++) {
            const x = i * (waterMarkerWidth + width) - 100;
            if (j === 0) {
              ctx.fillText(name, x, -height, imgWidth);
              ctx.fillText(date, x, -height + 20, imgWidth);
            }
            ctx.fillText(name, x, j * height, imgWidth);
            ctx.fillText(date, x, j * height + 20, imgWidth);
          }
        }
    }
  },
};
</script>
运用canvas给上传的整张图片增加平铺的水印
运用canvas给上传的整张图片增加平铺的水印

咱们先不细看代码详细细节进程,上面小编放了两张图片,图中能够看出,水印是平铺开来了,可是作用可能有点差强人意。由于这里在制作进程中需要考虑的要素比较多,比如图片巨细、水印文字巨细、长短、距离、旋转视点等等。

特别是 ctx.rotate(deg); 旋转视点是比较麻烦的,它是将整个画布进行(canvas)旋转的,咱们要旋转水印,也只能经过该 API 来完成。可是由所以整个画布的旋转,这会形成 ctx.fillText(text, x, y);xy 的变化,很难到达咱们想要的作用。

运用canvas给上传的整张图片增加平铺的水印
运用canvas给上传的整张图片增加平铺的水印

尽管也能经过复杂的计算来得到正确的坐标方位,可是会比较麻烦,小编是个怕麻烦的人,不想一个小需求写太多复杂的东西,这不符合我”程序和人一个能跑就行”的理念。(✪✪)

可是,秉着有头有尾的原则,仍是在网上寻找了很久,仍是想看看有没有相关比较完善的算法逻辑进程,可惜无果。

(如果你有比较好的做法,欢迎你在谈论给小编共享一下,感谢非常感谢)

运用canvas给上传的整张图片增加平铺的水印

那么,这就完毕了吗?

当然还没有-.-。

运用 ctx.createPattern 制作平铺水印

经小编摸鱼得知,canvas 还有一个 ctx.createPattern API 能够用于制作重复的内容,就和背景图片的 background-repeat: 'repeat' 特点作用一样。

那么这不就简单多了,还瞎整啥,且继续来看代码:

<script>
export default {
  methods: {
    upload(e) { ... },
    addWaterMark(img) {
      const canvas = document.getElementById('canvas');
      const imgWidth = img.width;
      const imgHeight = img.height;
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      // 平铺水印
      const canvasWater = document.createElement('canvas');
      const waterMarkSize = 200; // 水印巨细
      canvasWater.width = waterMarkSize;
      canvasWater.height = waterMarkSize;
      const ctxWater = canvasWater.getContext('2d');
      ctxWater.textAlign = 'left';
      ctxWater.textBaseline = 'top';
      ctxWater.font = '12px Microsoft Yahei';
      ctxWater.fillStyle = 'rgba(255, 255, 255, 0.3)';
      ctxWater.rotate(-20 * Math.PI/180);
      ctxWater.fillText('橙或人', 60, 80);
      ctxWater.fillText('2022年11月22日 09:22:30', 10, 100);
      ctx.fillStyle = ctx.createPattern(canvasWater, 'repeat'); // 制作重复的水印
      ctx.fillRect(0, 0, canvas.width, canvas.height);
    }
  },
};

运用canvas给上传的整张图片增加平铺的水印

运用canvas给上传的整张图片增加平铺的水印

上面咱们经过创建一个新的 canvas 用来专门制作水印,然后把它交给本来 canvasctx.createPattern() 办法,该办法能够接纳七种类型的参数,然后重复制作出来。

运用canvas给上传的整张图片增加平铺的水印

运用这种办法来平铺水印,相比上一种办法,就比较简单一些了,是人能看得懂的代码了,也能满意产品需求了。

运用canvas给上传的整张图片增加平铺的水印

输出文件

最后,咱们把 canvas 再转换 file 目标就功德圆满了。

<script>
export default {
  methods: {
    upload(e) { 
      const file = e.target.files[0];
      if (!file) return;
      const filePath = window.URL.createObjectURL(file); 
      const img = new Image();
      img.src = filePath;
      img.onload = () => {
        const newFile = this.addWaterMark(img, file.name);
        console.log(newFile);
      }
    },
    addWaterMark(img, fileName) {
      const canvas = document.getElementById('canvas');
      const imgWidth = img.width;
      const imgHeight = img.height;
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      const ctx = canvas.getContext('2d');
      ctx.drawImage(img, 0, 0);
      // 平铺水印
      const canvasWater = document.createElement('canvas');
      const waterMarkSize = 200; // 水印巨细
      canvasWater.width = waterMarkSize;
      canvasWater.height = waterMarkSize;
      const ctxWater = canvasWater.getContext('2d');
      ctxWater.textAlign = 'left';
      ctxWater.textBaseline = 'top';
      ctxWater.font = '12px Microsoft Yahei';
      ctxWater.fillStyle = 'rgba(255, 255, 255, 0.3)';
      ctxWater.rotate(-20 * Math.PI/180);
      ctxWater.fillText('橙或人', 60, 80);
      ctxWater.fillText('2022年11月22日 09:22:30', 10, 100);
      ctx.fillStyle = ctx.createPattern(canvasWater, 'repeat'); 
      ctx.fillRect(0, 0, canvas.width, canvas.height);
      const base64 = canvas.toDataURL('image/jpeg', 0.8)
      return this.dataURLtoBlob(base64, fileName)
    }
  },
  // base64转文件目标
  dataURLtoBlob(dataurl, name) {
    const arr = dataurl.split(',')
    const mime = arr[0].match(/:(.*?);/)[1]
    const bstr = atob(arr[1])
    let n = bstr.length
    const u8arr = new Uint8Array(n)
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n)
    }
    return new File([u8arr], name, {
      type: mime
    })
  }
};

运用canvas给上传的整张图片增加平铺的水印



至此,本篇文章就写完啦,撒花撒花。

运用canvas给上传的整张图片增加平铺的水印

期望本文对你有所帮助,如有任何疑问,期待你的留言哦。
老样子,点赞+谈论=你会了,保藏=你通晓了。