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

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) {
    //     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)
    }
  })
}

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

(0)

相关推荐

  • vue实现上传图片添加水印

    本文实例为大家分享了vue上传图片添加水印的具体实现代码,供大家参考,具体内容如下 1.封装添加水印方法 /** * 添加水印 * @param {blob} file * @param {string} el * @returns {Promise} */ export async function addWaterMarker(file, el = '#markImg') { return new Promise(async (resolve, reject) => { try { // 先

  • vue中使用带隐藏文本信息的图片、图片水印的方法

    一.带隐藏文本信息的图片 通过RGB 分量值的小量变动,不影响对图片的识别.因此,我们可以在图片加入文字信息. 最终达到如下效果: 首先,在该组件中加入img用于显示图片 <canvas ref="canvas" v-show="0"></canvas> <img :src="imageUrl" v-if="imageUrl"/> 调用方法 encryptionImg({ width = '

  • 移动端 Vue+Vant 的Uploader 实现上传、压缩、旋转图片功能

    面向百度开发 html <van-uploader :after-read="onRead" accept="image/*"> <img src="./icon_input_add.png" /> </van-uploader> js data() { return { files: { name: "", type: "" }, headerImage: null,

  • Vue实现页面添加水印功能

    创建watermark.js文件 let watermark = {} let setWatermark = (str) => { let id = '1.23452384164.123412416'; if (document.getElementById(id) !== null) { document.body.removeChild(document.getElementById(id)); } //创建一个画布 let can = document.createElement('can

  • Vue 集成 PDF.js 实现 PDF 预览和添加水印的步骤

    实现效果 可用插件介绍 Mozilla 提供了 PDF.js和pdfjs-dist,两者的区别如下: PDF.js ,一个完整的 PDF 查看器,可以直接使用其提供的 viewer.html 查看 PDF 内容,包含完整样式和相关功能.优点是快速集成,不需要自己实现查看器的功能和样式.缺点是如果要自定义样式和功能,反而会很麻烦. pdfjs-dist ,PDF.js 的预购建版本,只包含 PDF 内容的渲染功能,需要自己实现查看器的样式和相关功能. Vue 官方插件库 Awesome Vue.j

  • 基于VUE选择上传图片并页面显示(图片可删除)

    基于VUE选择上传图片并在页面显示,图片可删除,具体内容如下 demo例子: 依赖文件:jqueryform HTML文本内容: <template> <div id="accident"> <div class="wrapper"> <i class="icon-pic"></i>相关照片 <button type="button" @click="

  • 使用Vue实现图片上传的三种方式

    项目中需要上传图片可谓是经常遇到的需求,本文将介绍 3 种不同的图片上传方式,在这总结分享一下,有什么建议或者意见,请大家踊跃提出来. 没有业务场景的功能都是耍流氓,那么我们先来模拟一个需要实现的业务场景.假设我们要做一个后台系统添加商品的页面,有一些商品名称.信息等字段,还有需要上传商品轮播图的需求. 我们就以Vue.Element-ui,封装组件为例子聊聊如何实现这个功能.其他框架或者不用框架实现的思路都差不多,本文主要聊聊实现思路. 1.云储存 常见的 七牛云,OSS(阿里云)等,这些云平

  • vue+elementUI实现图片上传功能

    本文实例为大家分享了vue+elementUI图片上传的具体代码,供大家参考,具体内容如下 1.html <el-form-item label="图片" prop="logo"> <el-upload name="file" v-if="optype==0" :action="'/upload'" accept=".jpg, .png" list-type="

  • vue实现页面添加水印效果

    最近在做项目的时候要求给页面加上水印效果,废话不多说直接上代码: export function watermark(settings) { debugger; //默认设置 var defaultSettings={ watermark_txt:"text", watermark_x:20,//水印起始位置x轴坐标 watermark_y:20,//水印起始位置Y轴坐标 watermark_rows:5,//水印行数 watermark_cols:10,//水印列数 watermar

  • vue+elementUI实现表单和图片上传及验证功能示例

    本文实例讲述了vue+elementUI实现表单和图片上传及验证功能.分享给大家供大家参考,具体如下: 最终实现需求如下图: form表单内容与重点人员图片同时上传且图片为必填项 分析弹框页需要解决的问题有: 1.表单内容的验证及必填项 2.新增和编辑用同一个组件如何处理数据 3.图片需要和信息一起传递(即不允许自动上传) 4.图片必填的验证问题 针对上述问题作出方案: 1.el-form的表单验证需要注意几个地方: a:el-form-item的prop值需要和表单标签的v-model值保持一

随机推荐