1. 程式人生 > >自適配傳資料 加水印 資料 Watermark.js

自適配傳資料 加水印 資料 Watermark.js

/**
 * 引用: import * as Watermark from '@/utils/canvas/watermark' // js外掛放置的 工具類目錄
 * demo: <input class="upload-item-input" type="file"  accept="image/*" name="file" @change="PreviewImage(e)"/>
 * 使用示例: const newFile = e.target.files[0]
 * Watermark.addWatermark(file, watermarkData, function(base64Codes) {
      // console.log('callback-base64Codes', base64Codes)
      const blob = Watermark.convertBase64UrlToBlob(base64Codes)
      const { lastModified, type } = newFile
      const watermark_file = new File([blob], imgName, { type: type, lastModified: lastModified })
      // console.log('watermark_file', watermark_file)
      that.uploadImgObj.attachImgSrc = base64Codes // 加了水印 圖片base64顯示
      // that.upload(watermark_file, imgName) // 上傳圖片
    })
 * @param file imgFile
 * @param data:[item] 水印數列
 * @param callback 回撥
 * @item { font, fillStyle, fillText, position } 單個水印
 * @font font: '20px 黑體', 水印字型設定
 * @fillStyle fillStyle: 'rgba(255,255,255,0.5)' rgba(255,255,255,0.5) or #f00
 * @fillText fillText: '我是文案'
 * @position position: { horizontal, horizontalMargin, vertical, verticalMargin } 定位位置
 * @data 傳入的示例陣列資料結構 this.watermarkData = [
 {
   font: '20px 黑體',
   fillStyle: '#fff',
   fillText: '2018-07-06 星期五 江西省xxxxx',
   position: {
     horizontal: 'center', // 水平方向居 (left,right,center)
     horizontalMargin: '0', // 水平方向居 margin
     vertical: 'bottom', // 垂直方向居 (top,bottom,middle)
     verticalMargin: '20' // 垂直方向居 margin
   }
 },
 {
   font: '40px 黑體',
   fillStyle: '#fff',
   fillText: '我是文案2',
   position: {
     horizontal: 'center', // 水平方向居 (left,right,center)
     horizontalMargin: '0', // 水平方向居 margin
     vertical: 'bottom', // 垂直方向居 (top,bottom,middle)
     verticalMargin: '46' // 垂直方向居 margin
   }
 }
 ]
 */
export function addWatermark(file, data, callback) {
  var ready = new FileReader()
  /* 開始讀取指定的Blob物件或File物件中的內容. 當讀取操作完成時,readyState屬性的值會成為DONE,如果設定了onloadend事件處理程式,則呼叫之.同時,result屬性中將包含一個data: URL格式的字串以表示所讀取檔案的內容.*/
  ready.readAsDataURL(file) // 呼叫reader.readAsDataURL()方法,把圖片轉成base64
  ready.onload = function() {
    var re = this.result
    canvasDataURL(re, data, callback)
  }
}

function canvasDataURL(path, data, callback) {
  const watermarkData = data
  const img = new Image()
  img.src = path
  img.onload = function() {
    const that = this
    // 預設按比例壓縮
    let w = ''
    let h = ''
    const scale = that.width / that.height
    // 如果圖片尺寸太大,當圖片原尺寸寬度大於800 時,設定新圖片 寬度為800 ,高度並等比例縮放
    if (that.width > 800) {
      w = 800
      h = w / scale
    } else {
      w = that.width
      h = that.height
    }
    // 生成canvas
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')
    // 建立屬性節點
    const anw = document.createAttribute('width')
    anw.nodeValue = w
    const anh = document.createAttribute('height')
    anh.nodeValue = h
    canvas.setAttributeNode(anw)
    canvas.setAttributeNode(anh)
    ctx.drawImage(that, 0, 0, w, h)
    // 需要加的水印陣列
    for (const f in watermarkData) {
      const item = watermarkData[f]
      // console.log('canvasDataURL()-item', item)
      ctx.font = item.font
      ctx.fillStyle = item.fillStyle
      // 計算繪製水印的位置
      // const itemHorizontalPadding = 0 || f * item. // 主要用於 多個水印之間 垂直方向的間隔
      let positionX = 0
      let positionY = 0
      let textAlign = ''
      // 水平方向
      switch (item.position.horizontal) {
        case 'left':
          positionX = item.position.horizontalMargin
          textAlign = 'left'
          break
        case 'right':
          positionX = w - item.position.horizontalMargin
          textAlign = 'right'
          break
        case 'center':
          positionX = w / 2
          textAlign = 'center'
      }
      let textBaseline = ''
      // 垂直方向
      switch (item.position.vertical) {
        case 'top':
          positionY = item.position.verticalMargin
          textBaseline = 'top'
          break
        case 'bottom':
          positionY = h - item.position.verticalMargin
          textBaseline = 'bottom'
          break
        case 'middle':
          positionY = h / 2
          textBaseline = 'middle'
      }
      ctx.textAlign = textAlign // 水平居中
      ctx.textBaseline = textBaseline // 垂直居中
      ctx.fillText(item.fillText, positionX, positionY)
    }
    // 回撥函式返回base64的值
    const base64 = canvas.toDataURL('image/jpeg', 1)
    callback(base64)
  }
}

/**
 * 將以base64的圖片url資料轉換為Blob
 * @param urlData
 * 用url方式表示的base64圖片資料
 */
export function convertBase64UrlToBlob(urlData) {
  const arr = urlData.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 Blob([u8arr], { type: mime })
}