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) } }) }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持NICE源码。