Canvas 给图片添加水印

745 阅读1分钟

需求

每次上传图片至oss之前给图片添加logo.png水印

开发

1.获取到文件流之后,渲染到img标签

const blobToImg = function(filePath) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader()
    reader.addEventListener('load', () => {
      const img = new Image()
      img.src = reader.result
      img.addEventListener('load', () => resolve(img))
    })
    reader.readAsDataURL(filePath)
  })
}

2.将img标签内容绘制到canvas画布

const imgToCanvas = function(img) {
  const canvas = document.createElement('canvas')
  canvas.width = img.width
  canvas.height = img.height
  const ctx = canvas.getContext('2d')
  ctx.drawImage(img, 0, 0)
  return canvas
}

3.canvas画布上绘制水印并转换为Blob对象

const watermark = function(canvas) {
  return new Promise((resolve, reject) => {
    const ctx = canvas.getContext('2d')
    var eleImgCover = document.getElementById('imgCover') //水印
    for (let i = 0; i < 20; i++) {
      for (let j = 0; j < 20; j++) {
        ctx.rotate((-45 * Math.PI) / 180) // 水印初始偏转角度
        ctx.drawImage(eleImgCover, -canvas.width * 2 + i * 300, j * 250, eleImgCover.width, eleImgCover.height)
        ctx.rotate((45 * Math.PI) / 180) // 把水印偏转角度调整为原来的,不然他会一直转
      }
    }
    canvas.toBlob(blob => resolve(blob))
  })
}

4.将生成的blob文件传至oss

测试

Edge报错 Unhandled promise rejection TypeMismatchError

解决

1.一开始以为是toBlob()方法兼容问题,在MDN上看到不支持Edge和IE<10,所以按照官方给出的polyfill方法,在调用toBlob()前加入

if (!HTMLCanvasElement.prototype.toBlob) {
 Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
  value: function (callback, type, quality) {

    var binStr = atob( this.toDataURL(type, quality).split(',')[1] ),
        len = binStr.length,
        arr = new Uint8Array(len);

    for (var i=0; i<len; i++ ) {
     arr[i] = binStr.charCodeAt(i);
    }

    callback( new Blob( [arr], {type: type || 'image/png'} ) );
  }
 });
}

未果

2.因为报的是DOMException对象所以定位不到错误,只能在上面三个方法打断点,发现流文件渲染img标签时没有获取到流,log看了一下获取到的文件流,发现file:'不支持file文件类型',果断使用dataURL渲染img即可