El-Upload元件上傳圖片並新增水印

^Mao^發表於2024-05-08

背景

有的時候我們需要在上傳圖片中新增一些水印標識,然後上傳至伺服器

效果圖

程式碼

需求:

    1. 點選直接預覽圖片,而不需要使用dialog
    1. 上傳圖片新增水印後才預覽圖片
    • 上傳圖片檔案新增水印。使用watermarkjs庫轉換
    • 將新增水印的圖片轉換成base64,更新預覽圖片的內容,否則預覽的圖片還是舊的
    • 儲存新增水印後的檔案
    • 自行上傳伺服器....
<template>
  <div class="app">
    <el-upload
      action=""
      list-type="picture-card"
      :multiple="true"
      :on-change="handleUploadChange"
      :auto-upload="false"
    >
      <i slot="default" class="el-icon-plus"></i>
      <div slot="file" slot-scope="{ file }">
        <img class="el-upload-list__item-thumbnail" :src="file.url" alt="" />

        <span class="el-upload-list__item-actions">
          <span
            class="el-upload-list__item-preview"
            @click="handlePictureCardPreview(file)"
          >
            <i class="el-icon-zoom-in"></i>
            <!-- <el-image
              style="width: 100px; height: 100px"
              :src="dialogImageUrl"
              :preview-src-list="[dialogImageUrl]"
            >
            </el-image> -->
          </span>
          <span class="el-upload-list__item-delete" @click="handleRemove(file)">
            <i class="el-icon-delete"></i>
          </span>
        </span>
      </div>
    </el-upload>
    <!-- 
      預覽圖片方式1:使用dialog方式
    <el-dialog :visible.sync="dialogVisible">
      <img width="100%" :src="dialogImageUrl" alt="" />
    </el-dialog> -->

    <!-- 預覽圖片方式2:使用image-viewer -->
    <el-image-viewer
      v-if="imgViewerVisible"
      :url-list="imgList"
      :on-close="closeImgViewer"
    />
    <div class="demo" ref="demoRef"></div>
  </div>
</template>

<script>
import watermark from 'watermarkjs'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'

export default {
  components: {
    ElImageViewer,
  },
  data() {
    return {
      dialogImageUrl: '',
      dialogVisible: false,
      imgViewerVisible: false,
      imgList: [],
    }
  },
  methods: {
    handlePictureCardPreview(file) {
      // this.dialogImageUrl = file.url
      // this.dialogVisible = true
      this.imgViewerVisible = true
      this.imgList = [file.url]

      // 解決預覽放大後滾動滑鼠頁面跟著滾動的問題
      const m = (e) => {
        e.preventDefault()
      }
      document.body.style.overflow = 'hidden'
      document.addEventListener('touchmove', m, false) // 禁止頁面滑動
    },
    closeImgViewer() {
      this.imgViewerVisible = false
      const m = (e) => {
        e.preventDefault()
      }
      document.body.style.overflow = 'auto'
      document.removeEventListener('touchmove', m, true)
    },

    handleRemove(file) {
      console.log(file)
    },
    handleUploadChange(file, fileList) {
      // console.log('file:', file)
      // console.log('fileList:', fileList)
      const upload_file = file.raw

      // 1. 新增單個水印
      // watermark([upload_file])
      //   .image(
      //     watermark.text.upperRight(
      //       'watermark.js',
      //       '48px Josefin Slab',
      //       '#fff',
      //       0.5,
      //       48
      //     )
      //   )
      //   .then((img) => {
      //     img.style.width = '300px'
      //     img.style.height = 'auto'
      //     this.$refs.demoRef.append(img)
      //   })

      // 2. 新增多個水印
      // watermark([upload_file])
      //   .image(
      //     watermark.text.upperRight(
      //       '呵呵呵',
      //       '48px Josefin Slab',
      //       '#fff',
      //       0.5,
      //       48
      //     )
      //   )
      //   .render()
      //   .image(
      //     watermark.text.upperLeft(
      //       '哈哈哈',
      //       '48px Josefin Slab',
      //       '#fff',
      //       0.5,
      //       48
      //     )
      //   )
      //   .then((img) => {
      //     img.style.width = '300px'
      //     img.style.height = 'auto'
      //     this.$refs.demoRef.append(img)
      //   })

      // 3. 自定義新增水印位置,比如:設定在右上角
      // @param {HTMLCanvasElement} canvas
      // @param {TextMetrics} metrics
      // @param {CanvasRenderingContex2D} context - context of the canvas
      // 設定水印的x座標
      var x = function (canvas, metrics, context) {
        // 微調,比如:-20  根據實際調整
        return canvas.width - metrics.width - 20
      }
      // 設定水印的y座標
      var y = function (canvas, metrics, context) {
        return metrics.hangingBaseline + 10
      }
      watermark([upload_file])
        .image(
          watermark.text.atPos(
            x,
            y,
            '上傳時間:2024-05-08 22:40:10',
            '48px sans-serif',
            '#fff',
            0.8
          )
        )
        .then((img) => {
          // img.style.width = '300px'
          // img.style.height = 'auto'
          this.$refs.demoRef.append(img)
          // 將base64轉檔案形式
          const watermark_file = this.dataURLtoFile(img.src, file.name)
          // 下載檔案
          // this.downloadFile(watermark_file)

          this.transformFileToBase64(watermark_file, file)
        })
    },
    // 將base64轉檔案
    dataURLtoFile(dataurl, filename) {
      var arr = dataurl.split(','),
        mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]),
        n = bstr.length,
        u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], filename, { type: mime })
    },
    // 下載檔案
    downloadFile(file) {
      let aTag = document.createElement('a') //建立一個a標籤
      aTag.download = file.name
      let href = URL.createObjectURL(file) //獲取url
      aTag.href = href
      aTag.click()
      URL.revokeObjectURL(href) //釋放url
    },
    // 將水印檔案轉換成base64,然後修改原有file物件的url,這樣保證預覽時圖片的url是帶有水印的
    transformFileToBase64(watermark_file, file) {
      return new Promise((resolve, reject) => {
        // 讀取檔案
        const reader = new FileReader()
        //readAsDataURL()方法: 讀取檔案內容,結果用data:url的字串形式表示
        reader.readAsDataURL(watermark_file)
        // 讀取成功回撥
        reader.onload = () => {
          file.url = reader.result
        }
      })
    },
  },
}
</script>

<style lang="less" scoped></style>

第三方庫watermarkjs

連結:https://brianium.github.io/watermarkjs/docs.html#image

參考文件

  • FileReader()讀取檔案、圖片上傳預覽
    https://www.cnblogs.com/libo-web/p/15766987.html
  • Element-ui中 使用圖片檢視器(el-image-viewer) 預覽圖片
    https://juejin.cn/post/7084856145277354020

相關文章