vue实现上传图片添加水印(升级版)

编辑: admin 分类: javascript 发布时间: 2022-01-01 来源:互联网

vue项目实现上传图片添加水印升级版,供大家参考,具体内容如下

封装水印方法

/**
 * 添加水印
 * @param {blob} file
 * @param {string} el
 * @returns {Promise}
 */
export async function addWaterMarker(file, el = '#markImg') {
  return new Promise(async (resolve, reject) => {
    try {
      // 先压缩和旋转图片
      file = await compressor(file)
      // 将文件blob转换成图片
      let img = await blobToImg(file)

      // 创建canvas画布
      let canvas = document.createElement('canvas')
      canvas.width = img.naturalWidth
      canvas.height = img.naturalHeight
      let ctx = canvas.getContext('2d')

      // 填充上传的图片
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

      // 生成水印图片
      const markEle = document.querySelector(el)
      const markWidth = markEle.clientWidth
      const scale = canvas.width * 0.25 / markWidth
      // 先缩放水印再转成图片
      markEle.style.transform = `scale(${scale})`
      const markImg = await htmlToCanvas(markEle)

      // 填充水印
      ctx.drawImage(markImg, canvas.width - markImg.width - 15 * scale, canvas.height - markImg.height - 15 * scale, markImg.width, markImg.height)

      // 将canvas转换成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,   //此处不使用默认值window.devicePixelRatio,需跟移动端保持一致
        allowTaint: false,   //允许污染
        useCORS: true,
        backgroundColor //'transparent'  //背景色
      })
      resolve(markImg)
    } catch (error) {
      reject(error)
    }
  })
}

/**
 * 压缩和旋转图片
 * @param {blob} file
 * @param {number} quality  压缩比例
 * @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)
      }
    })
  })
}

页面中使用水印并压缩图片

<template>
  <div>
    <el-upload
      action=""
      :headers="uploadProps.headers"
      list-type="picture-card"
      :show-file-list="false"
      :http-request="fnUploadRequest"
      :on-success="handleSuccess"
      :before-upload="handleUpload"
      accept=".png,.jpg,.jpeg,.gif,.webp"
    >
      <div class="flex-center">
        <slot></slot>
      </div>
    </el-upload>
    <!-- 图片上传水印 -->
    <div id="markImg">
      <div class="logo">
        <img src="@/assets/img/icon-logo.png" />
        文本文本
      </div>
      <p>
        {{ parseTime(fileDate, '{y}-{m}-{d} {h}:{i}:{s}') }} 周{{
          parseTime(fileDate, '{a}')
        }}
      </p>
      <p>{{ executor }}</p>
    </div>
  </div>
</template>

<script>
import {
  getAccessToken,
  getRefreshToken,
  getAccessTokenTTL
} from '@/utils/auth'
import { uploadOSS } from '@/utils/ossImage'
import { parseTime, compressor, addWaterMarker } from '@/utils'

export default {
  name: 'index',
  props: {
    needWaterMark: {
      type: Boolean,
      default: false
    },
    executor: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      fileDate: new Date()
    }
  },
  created() {
    this.parseTime = parseTime
  },
  computed: {
    userAccountID() {
      return this.$store.state.user.userAccountID
    },
    uploadProps() {
      return {
        // action: `${process.env.VUE_APP_BASE_API}/api/image/upload`,
        headers: {
          // 接口可能要带token: "",
          Authorization: getAccessToken()
        },
        data: {}
      }
    }
  },
  methods: {
    // beforeUpload_u(file, fileList){
    //   // console.log(file, fileList);
    //   var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
    //   const extension = testmsg === 'png' || testmsg === 'jpg' || testmsg === 'jpeg' || testmsg === 'gif' || testmsg === 'webp'
    //   const isLimit10M = file.size / 1024 / 1024 < 10
    //   var bool = false;
    //   if(extension && isLimit10M){
    //     bool = true;
    //   } else {
    //     bool = false;
    //   }
    //   if(!extension) {
    //     this.$message.error('请上传图片格式文件!');
    //     return bool;
    //   }
    //   if(!isLimit10M) {
    //【文章原创作者:http://www.yidunidc.com/st.html转发请说明出处】     this.$message.error('上传失败,不能超过10M!');
    //     return bool;
    //   }
    //   return bool;
    // },
    // handleSuccess(res) {
    //   console.log(res);
    //   if (res.code == 0) {
    //     this.$emit('imgData', res.item);
    //     this.$message.success('上传图片成功!');
    //   } else {
    //     this.$message.error('上传图片失败!');
    //   }
    // },
    // handleError(err){
    //   this.$message.error('上传图片失败!');
    // },

    // 上传图片判断
    handleUpload(file, fileList) {
      var testmsg = file.name.substring(file.name.lastIndexOf('.') + 1)
      const extension =
        testmsg.toLowerCase() === 'png' ||
        testmsg.toLowerCase() === 'jpg' ||
        testmsg.toLowerCase() === 'jpeg' ||
        testmsg.toLowerCase() === 'gif' ||
        testmsg.toLowerCase() === 'webp'
      const isLimit10M = file.size / 1024 / 1024 < 10
      var bool = false
      if (extension && isLimit10M) {
        bool = true
      } else {
        bool = false
      }
      if (!extension) {
        this.$message.error('请上传图片格式文件!')
        return bool
      }
      if (!isLimit10M) {
        this.$message.error('上传失败,不能超过10M!')
        return bool
      }
      return bool
    },
    // 上传图片
    async fnUploadRequest(options) {
      try {
        let file = options.file // 拿到 file
        this.fileDate = file.lastModifiedDate
        // 压缩图片
        if (file.size > 512 * 1024 && file.type.includes('image/')) {
          file = await compressor(file)
        }
        // 添加水印
        if (this.needWaterMark) {
          const fileName = file.name
          file = await addWaterMarker(file, '#markImg')
          file.name = fileName
        }
        let res = await uploadOSS(file)
        // 返回的就是图片地址
        this.$emit('imgData', res)
        this.$message.success('上传图片成功!')
      } catch (e) {
        console.log(e)
        this.$message.error('上传图片失败!请重新上传')
      }
    },
    //图片上传成功回调
    handleSuccess(res) {
      // console.log(res);
      if (res) {
        this.$emit('imgData', res)
      }
    }
  }
}
</script>

<style  lang="scss" scoped>
::v-deep .el-upload,
::v-deep .el-upload--picture-card {
  // width: 120px;
  height: 24px;
  height: 0;
  border: none;
  line-height: 0;
  display: block;
  background: #f5f6fb;
}
// ::v-deep .el-upload{
//   width: 50px;
// }
.img-cont {
  width: 50px;
  height: 24px;
  background: #f5f6fb;
  .img-icon {
    color: #ccc;
  }
  .img-text {
    font-size: 12px;
    height: 24px;
    color: #000;
  }
}
#markImg {
  position: absolute;
  left: -9999999px;
  text-align: right;
  padding: 10px 15px;
  .logo {
    font-weight: 600;
    font-size: 15px;
    color: #ffffff;

    display: flex;
    height: 21px;
    align-items: center;
    justify-content: flex-end;
    img {
      height: 21px;
      margin-right: 5px;
    }
  }
  p {
    margin-top: 6px;
    color: #ffffff;
    font-size: 12px;
    font-weight: 400;
  }
}
</style>

水印方法更新版

/**
 * 压缩和旋转图片
 * @param {blob} file
 * @param {number} quality  压缩比例
 * @param {number} maxWidth
 * @returns {Promise}
 */
export function compressor(file, drew, maxWidth = 750, quality = 0.6) {
  return new Promise(resolve => {
    new Compressor(file, {
      strict: false,
      maxWidth,
      quality,
      drew,
      success: resolve,
      error(err) {
        console.log(err.message)
      }
    })
  })
}

/**
 * 添加水印
 * @param {blob} file
 * @param {string} el
 * @returns {Promise}
 */
 export async function addWaterMarker(file, el = '#brandMarkImg', direction = 'rightDown') {
  return new Promise(async (resolve, reject) => {
    try {
      const maxWidth = 750
      const img = await blobToImg(file)
      const imgWidth = img.naturalWidth > maxWidth ? maxWidth : img.naturalWidth

      // 生成水印图片
      const markEle = document.querySelector(el)
      const scale = imgWidth * 0.25 / markEle.clientWidth
      // 先缩放水印再转成图片
      markEle.style.transform = `scale(${scale})`
      const markImg = await htmlToCanvas(markEle)

      // 先压缩和旋转图片
      file = await compressor(file, (context, canvas) => {
        if(direction == 'rightDown'){
          // 填充水印 右下角
          context.drawImage(markImg, canvas.width - markImg.width - 15 * scale, canvas.height - markImg.height - 15 * scale, markImg.width, markImg.height)
        } else {
          // 填充水印 左下角
          context.drawImage(markImg, 15 * scale, canvas.height - markImg.height - 15 * scale, markImg.width, markImg.height)
        }
      }, maxWidth)
      resolve(file)
    } 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,
        allowTaint: false,   //允许污染
        useCORS: true,
        backgroundColor //'transparent'  //背景色
      })
      resolve(markImg)
    } catch (error) {
      reject(error)
    }
  })
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持hwidc。