Vue implements adding watermark to uploaded pictures

Vue implements adding watermark to uploaded pictures

This article shares the specific implementation code of adding watermarks to uploaded pictures in Vue for your reference. The specific content is as follows

1. Encapsulation and watermarking method

/**
 * Add watermark * @param {blob} file
 * @param {string} el
 * @returns {Promise}
 */
export async function addWaterMarker(file, el = '#markImg') {
  return new Promise(async (resolve, reject) => {
    try {
      // Compress and rotate the image first file = await compressor(file)
      // Convert the file blob to an image let img = await blobToImg(file)

      // Create a canvas let canvas = document.createElement('canvas')
      canvas.width = img.naturalWidth
      canvas.height = img.naturalHeight
      let ctx = canvas.getContext('2d')

      // Fill the uploaded image ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

      // Generate watermark image const markEle = document.querySelector(el)
      const markWidth = markEle.clientWidth
      const scale = canvas.width * 0.25 / markWidth
      // Scale the watermark first and then convert it to an image markEle.style.transform = `scale(${scale})`
      const markImg = await htmlToCanvas(markEle)

      // Fill watermark ctx.drawImage(markImg, canvas.width - markImg.width - 15 * scale, canvas.height - markImg.height - 15 * scale, markImg.width, markImg.height)

      //Convert canvas into blob
      canvas.toBlob(blob => resolve(blob))
    } catch (error) {
      reject(error)
    }

  })
}

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


export function htmlToCanvas(el, backgroundColor = 'rgba(0,0,0,.1)') {
  return new Promise(async (resolve, reject) => {
    try {
      const markImg = await html2canvas(el, {
        scale: 2, //The default value window.devicePixelRatio is not used here, it needs to be consistent with the mobile end allowTaint: false, //Allow pollution useCORS: true,
        backgroundColor //'transparent' //background color})
      resolve(markImg)
    } catch (error) {
      reject(error)
    }
  })
}

/**
 * Compress and rotate images * @param {blob} file
 * @param {number} quality compression ratio * @param {number} maxWidth
 * @returns {Promise}
 */
export function compressor(file, quality = 0.6, maxWidth = 750) {
  return new Promise(resolve => {
    new Compressor(file, {
      maxWidth,
      quality,
      success: resolve,
      error(err) {
        console.log(err.message)
      }
    })
  })
}

2. Use in the project

<!-- Image Upload-->
<div class="flex mt20" v-if="item.questionType === 4">
  <van-uploader
    v-model="item.imgUpload"
    multiple="true"
    lazy-loading
    :deletable="!isDisabled"
    :disabled="isDisabled"
    @delete="handleDeleteImg({ ...arguments, item })"
    :before-read="handleBeforeImgUpload"
    :after-read="handleAfterImgUpload"
    @click.native="currentItem = item"
  />
</div>
    
<script>
import {
  getTaskDetail,
  userExecute,
  submitFlow,
  rejectFlow,
} from '@/api/myTask';

import { uploadOSS } from '@/utils/oss';
import { parseTime, addWaterMarker } from '@/utils';

import { ImagePreview } from 'vant';

import Compressor from 'compressorjs';

const fileExtensions = ['xlsx', 'xls', 'docx', 'doc', 'pdf'];

const quality = 0.2; //Image compression quality export default {
  methods: {
  // Before uploading async handleBeforeImgUpload(img, detail) {
      if (!img) {
        return
      }
      return new Promise(async (resolve, reject) => {
        if (Array.isArray(img)) {
          if (img.length > 5) {
            this.$toast('Upload up to 5 photos at a time, please upload in batches!')
            reject()
          }
          let blobs = []
          for (const file of img) {
            // Images larger than 512k are compressed first if (file.size > 512 * 1024 && file.type.includes('image/')) {
              file = await this.compressor(file)
            }
            // Add watermark let blob = await addWaterMarker(file)
            blob.name = file.name
            blobs.push(blob)
          }
          resolve(blobs)
        } else {
          // Images larger than 512k should be compressed first if (img.size > 512 * 1024 && img.type.includes('image/')) {
            img = await this.compressor(img)
          }
          const blob = await addWaterMarker(img)
          blob.name = img.name
          resolve(blob)
        }
      })
    },
    
    //After uploading async handleAfterImgUpload(img, detail) {
      try {
        $loading.show()
        if (Array.isArray(img)) {
          img.forEach(async ({ file }, index) => {
            if (!file.name || !file.type.includes('image/')) {
              this.currentItem.imgUpload.splice(detail.index + index, 1)
              this.$toast('Upload failed, only photos can be uploaded!')
              // Upload completed if (index === img.length - 1) {
                $loading.hide()
              }
              return //return in forEach is equivalent to continue
            }
            if (file.size > 1024 * 1024 * 10) {
              this.currentItem.imgUpload.splice(detail.index + index, 1)
              this.$toast('The file is too large, a single file cannot exceed 10M!')
              // Upload completed if (index === img.length - 1) {
                $loading.hide()
              }
              return
            }
            try {
              const { fileName, url } = await uploadOSS(file)
              this.currentItem.answer.push({
                url,
              })
            } catch (error) {
              this.currentItem.imgUpload.splice(detail.index + index, 1)
              this.$toast('Upload failed, please try again later!')
              console.error(error)
            }
            // Upload completed if (index === img.length - 1) {
              $loading.hide()
            }
          })
        } else {
          if (!img.file.type.includes('image')) {
            this.currentItem.imgUpload.splice(detail.index, 1)
            $loading.hide()
            this.$toast('Upload failed, only photos can be uploaded!')
            return
          }
          if (img.file.size >= 1024 * 1024 * 10) {
            this.currentItem.imgUpload.splice(detail.index, 1)
            $loading.hide()
            this.$toast('The file is too large and cannot exceed 10M!')
            return
          }
          // If it is larger than 512k, compress it first let file = img.file
          const { fileName, url } = await uploadOSS(file)
          this.currentItem.answer.push({
            url,
          })
          $loading.hide()
        }
      } catch (error) {
        this.currentItem.imgUpload.splice(detail.index, 1)
        $loading.hide()
        this.$toast('Upload failed, please try again later!')
        console.error(error)
      }
    }
 }

Thanks to Brother Long for his guidance;

3. The effects are as follows

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • How to use pictures and picture watermarks with hidden text information in Vue
  • Vue implements adding watermark effect to the page
  • Vue integrates PDF.js to implement PDF preview and add watermark steps
  • Vue implements page watermark function
  • Three ways to upload pictures using Vue
  • The Uploader of Vue+Vant on the mobile terminal realizes the functions of uploading, compressing and rotating pictures
  • Vue+elementUI implements form and image upload and verification function example
  • vue+elementUI realizes the picture upload function
  • Based on VUE, select and upload pictures and display them on the page (pictures can be deleted)
  • Vue realizes adding watermark to uploaded pictures (upgraded version)

<<:  Introduction to the use of the four major sql ranking functions ROW_NUMBER, RANK, DENSE_RANK, NTILE

>>:  Quickly solve the Chinese input method problem under Linux

Recommend

VMware ESXi installation and use record (with download)

Table of contents 1. Install ESXi 2. Set up ESXi ...

JS implements Baidu search box

This article example shares the specific code of ...

MySQL 8.0.16 installation and configuration graphic tutorial under macOS

This article shares the installation and configur...

Sliding menu implemented with CSS3

Result:Implementation code: <!DOCTYPE html>...

Detailed explanation of how to detect and prevent JavaScript infinite loops

Table of contents Preface Fix infinite loop in fo...

MySQL 5.7.18 installation and configuration tutorial under Windows

This article shares the installation and configur...

How to query data from multiple unrelated tables and paging in Mysql

Mysql multiple unrelated tables query data and pa...

How to use nginx to build a static resource server

Taking Windows as an example, Linux is actually t...

How to restore a single database or table in MySQL and possible pitfalls

Preface: The most commonly used MySQL logical bac...

mysql solves time zone related problems

Preface: When using MySQL, you may encounter time...

Installation and use tutorial of Elasticsearch tool cerebro

Cerebro is an evolution of the Elasticsearch Kopf...

Detailed explanation of the use of redux in native WeChat applet development

premise In complex scenarios, a lot of data needs...

Detailed explanation of this pointing in JS arrow function

Arrow function is a new feature in ES6. It does n...