Loading

El-Upload组件上传图片并添加水印

背景

有的时候我们需要在上传图片中添加一些水印标识,然后上传至服务器

效果图

代码

需求:

    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',
      //       '#f00',
      //       0.8
      //     )
      //   )
      //   .then((img) => {
      //     this.$refs.demoRef.append(img)
      //     // 将base64转文件形式
      //     const watermark_file = this.dataURLtoFile(img.src, file.name)
      //     // 下载文件
      //     // this.downloadFile(watermark_file)

      //     this.transformFileToBase64(watermark_file, file)
      //   })

      // 根据图片大小自适应设置水印文字大小
      function customFn(target) {
        var context = target.getContext('2d')
        var text = 'watermark.js'
        var metrics = context.measureText(text)
        // var x = target.width / 2 - (metrics.width + 24)
        // var y = target.height / 2 + 48 * 2
        var x = 0.01 * target.width
        var y = 0.04 * target.height
        const fontSize = 0.05 * target.width

        context.translate(x, y)
        context.globalAlpha = 0.5
        context.fillStyle = '#f00'
        context.font = `700 ${fontSize}px Josefin Slab`
        // context.rotate((-45 * Math.PI) / 180)
        context.fillText(text, 0, 0)
        return target
      }
      watermark([upload_file])
        .image(customFn)
        .then((img) => {
          this.$refs.demoRef.append(img)
          const watermark_file = this.dataURLtoFile(img.src, file.name)

          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

参考文档

posted @ 2024-05-08 23:33  ^Mao^  阅读(72)  评论(0编辑  收藏  举报