前端上传图片添加水印

在最近 haoyo择校 功能中,需要上传各个高校的招生计划图片;为申明版权,故需要在上传图片时添加水印。

技术栈:

vue2.x+element-ui+more...

实现思路:

  1. 利用 element-uiupload 组件,监听http-request事件,获取到上传的文件信息。
  2. 将获取到的文件信息file, 转为base64格式。
  3. 将base64格式的图片转为canvas格式,并获取到canvas的图片对象。
  4. 给canvas图层添加水印。
  5. 将canvas图层转为图片格式(.jpg, .png….)。
  6. 将图片转为文件格式去上传。

代码示例:

入口方法

beforeUpload(file) {
  console.log(file)
  return new Promise((resolve, reject) => {
    //把文件转换为base64
    this.fileByBase64(file, async (base64) => {   // 1.调用方法1: 把文件转换为base64字符串
      // 把文件转换为Canvas
      let tempCanvas = await this.imgToCanvas(base64) // 2. 调用方法2:把base64转换为Canvas
      // 把水印写入
      const canvas = this.addWatermark(tempCanvas, '考研公众号:HaoYo') //3.调用方法3: 写入水印到Canvas
      // canvas转成img
      const img = this.convasToImg(canvas, file.type) //4. 调用方法4:把Canvas转换为image文件
      //被canvas转换为文件
      let newFile = this.base64ToFile(img.src, file.name) //5.调用方法5:被image转换为File文件
      resolve(newFile)
    })
  })
},

文件转base64

/**
 * 文件转base64
 * @param  file 文件流
 * @param  callback 回调函数
 */
fileByBase64(file, callback){
  let reader = new FileReader();
  // 传入一个参数对象即可得到基于该参数对象的文本内容
  reader.readAsDataURL(file);
  reader.onload = function (e) {
    // target.result 该属性表示目标对象的DataURL
    callback(e.target.result)
  };
},

Base64转成canvas

/**
 * Base64转成canvas
 * @param  base64
 */
async imgToCanvas(base64) {
  // 创建img元素
  const img = document.createElement('img')
  img.setAttribute('src', base64)
  await new Promise((resolve) => (img.onload = resolve))
  // 创建canvas DOM元素,并设置其宽高和图片一样
  const canvas = document.createElement('canvas')
  console.log(img.height)
  console.log(img.width)
  canvas.width = img.width
  canvas.height = img.height
  // 坐标(0,0) 表示从此处开始绘制,相当于偏移。
  canvas.getContext('2d').drawImage(img, 0, 0)
  return canvas
},

给canvas添加水印

/**
 * canvas添加水印
 * @param  canvas 对象
 * @param text 水印文字
 */
addWatermark(canvas, text) {
  const ctx = canvas.getContext('2d')
  ctx.fillStyle = '#aaa'
  ctx.textBaseline = 'middle'
  ctx.font = (ctx.canvas.width / 20) + 'px Arial'
  ctx.textAlign = 'center'
  ctx.textBaseline = 'middle'
  // ctx.rotate(45);
  // ctx.rotate((45 * Math.PI) / 180);
  ctx.fillText(text, canvas.width / 2, canvas.height / 2)
  return canvas
},

canvas转成img

/**
 * canvas转成img
 * @param {canvas对象} canvas
 */
convasToImg(canvas, type) {
  // 新建Image对象,可以理解为DOM
  let image = new Image()
  // canvas.toDataURL 返回的是一串Base64编码的URL
  // 指定格式 PNG
  image.src = canvas.toDataURL(type)
  return image
},

将img图片转为file类型的文件(用于上传)

/**
 * @param urlData  base64
 * @param fileName 文件名称
 * @returns {File}
 */
base64ToFile(urlData, fileName) {
  let arr = urlData.split(',');
  let mime = arr[0].match(/:(.*?);/)[1];
  let bytes = atob(arr[1]); // 解码base64
  let n = bytes.length
  let ia = new Uint8Array(n);
  while (n--) {
    ia[n] = bytes.charCodeAt(n);
  }
  return new File([ia], fileName, { type: mime });
},

最后图片,就开开心心的被加上水印了呀~
图片示例1
图片示例2

created_at:zhanghaoran’s blog 2022-04-25