vue实现上传图片添加水印
更新时间:2021年9月13日 16:00 点击:2347
本文实例为大家分享了vue上传图片添加水印的具体实现代码,供大家参考,具体内容如下
1、封装添加水印方法
/** * 添加水印 * @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) } }) }) }
2、项目中使用
<!-- 图片上传 --> <div class="flex mt20" v-if="item.questionType === 4"> <van-uploader v-model="item.imgUpload" multiple="true" lazy-load :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; //图片压缩质量 export default { methods: { // 上传前 async handleBeforeImgUpload(img, detail) { if (!img) { return } return new Promise(async (resolve, reject) => { if (Array.isArray(img)) { if (img.length > 5) { this.$toast('一次最多上传5张,请分批次上传!') reject() } let blobs = [] for (const file of img) { // 大于512k的图片则先压缩 if (file.size > 512 * 1024 && file.type.includes('image/')) { file = await this.compressor(file) } // 添加水印 let blob = await addWaterMarker(file) blob.name = file.name blobs.push(blob) } resolve(blobs) } else { // 大于512k的图片则先压缩 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) } }) }, // 上传后 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('上传失败,只能上传照片!') // 上传完成 if (index === img.length - 1) { $loading.hide() } return //forEach里的return相当于continue } if (file.size > 1024 * 1024 * 10) { this.currentItem.imgUpload.splice(detail.index + index, 1) this.$toast('文件太大,单个文件不能超过10M!') // 上传完成 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('上传失败,请稍后重试!') console.error(error) } // 上传完成 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('上传失败,只能上传照片!') return } if (img.file.size >= 1024 * 1024 * 10) { this.currentItem.imgUpload.splice(detail.index, 1) $loading.hide() this.$toast('文件太大,不能超过10M!') return } // 大于512k则先压缩 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('上传失败,请稍后重试!') console.error(error) } } }
感谢龙哥的指导;
3、效果如下
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。
上一篇: jQuery实现简单的轮播图效果
下一篇: 配置vue全局方法的两种方式实例
相关文章
- 这篇文章主要介绍了vue中activated的用法,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2021-01-03
基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件功能
这篇文章主要介绍了基于vue-simple-uploader封装文件分片上传、秒传及断点续传的全局上传插件,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-23- 这篇文章主要介绍了Vue基于localStorage存储信息代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-16
- 这篇文章主要介绍了vue 监听 Treeselect 选择项的改变操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01
Antd-vue Table组件添加Click事件,实现点击某行数据教程
这篇文章主要介绍了Antd-vue Table组件添加Click事件,实现点击某行数据教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-17- 这篇文章主要介绍了vue 实现动态路由的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-06
- 这篇文章主要介绍了Vue组件跨层级获取组件操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-28
- 这篇文章主要介绍了vue treeselect获取当前选中项的label实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01
- 这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-19
- 这篇文章主要给大家介绍了关于Vue中slot-scope的深入理解,这个教程非常适合初学者,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-04-17
vuejs element table 表格添加行,修改,单独删除行,批量删除行操作
这篇文章主要介绍了vuejs element table 表格添加行,修改,单独删除行,批量删除行操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-18antdesign-vue结合sortablejs实现两个table相互拖拽排序功能
这篇文章主要介绍了antdesign-vue结合sortablejs实现两个table相互拖拽排序功能,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-01-09- 最常见的多环境配置,就是开发环境配置,和生产环境配置,本文主要介绍了vue项目多环境配置的实现,感兴趣的可以了解一下...2021-07-20
- 这篇文章主要介绍了Vue 3.0 中 jsx 语法使用,帮助大家更好的理解和使用vue框架,感兴趣的朋友可以了解下...2020-11-13
vue项目页面嵌入代码块vue-prism-editor的实现
这篇文章主要介绍了vue项目页面嵌入代码块vue-prism-editor的实现,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-10-30vue Treeselect下拉树只能选择第N级元素实现代码
这篇文章主要介绍了vue Treeselect下拉树只能选择第N级元素实现代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-09-01- 这篇文章主要为大家详细介绍了vue实现同时设置多个倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-05-20
Ant design vue table 单击行选中 勾选checkbox教程
这篇文章主要介绍了Ant design vue table 单击行选中 勾选checkbox教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-25解决vue的router组件component在import时不能使用变量问题
这篇文章主要介绍了解决vue的router组件component在import时不能使用变量问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27Vue 列表页带参数进详情页的操作(router-link)
这篇文章主要介绍了Vue 列表页带参数进详情页的操作(router-link),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-13