【vue】vue + vant实现上传图片添加水印
目录
方法1:使用HTML2canvas
说明:
优点
缺点
依赖安装
方法2:使用canvas结合vant中组件
增加水印方法
在vue组件中使用
要点
方法1:使用HTML2canvas
使用html2canvas来处理水印的生成,需要就给水印元素转换为canvas图像并叠加到上传的图片。
<template>
<div>
<van-uploader :after-read="afterRead" />
<!-- 水印元素 -->
<div id="watermark" style="display: none;">
<div style="font-size: 20px; color: rgba(0, 0, 0, 0.3); transform: rotate(-45deg); position: absolute; top: 50%; left: 50%; transform-origin: center;">
水印文本
</div>
<!-- 如果需要图片水印,可以在这里添加图片元素 -->
<img src="path/to/watermark.png" style="position: absolute; bottom: 10px; right: 10px; width: 100px; height: 100px; opacity: 0.3;" />
</div>
</div>
</template>
<script>
import { ref } from 'vue';
import html2canvas from 'html2canvas';
export default {
setup() {
const afterRead = async (file) => {
// 创建 canvas 元素
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置 canvas 尺寸为图片尺寸
const img = await new Promise((resolve) => {
const img = new Image();
img.src = file.content;
img.onload = () => resolve(img);
});
canvas.width = img.width;
canvas.height = img.height;
// 绘制原始图片
ctx.drawImage(img, 0, 0);
// 获取水印元素并转换为 canvas
const watermarkElement = document.getElementById('watermark');
const watermarkCanvas = await html2canvas(watermarkElement, {
logging: false,
scale: window.devicePixelRatio, // 高清屏支持
useCORS: true, // 启用跨域
});
// 将水印 canvas 绘制到主 canvas 上
ctx.drawImage(watermarkCanvas, 0, 0, canvas.width, canvas.height);
// 将 canvas 转换为 Blob 并替换文件内容
canvas.toBlob((blob) => {
file.file = blob;
file.content = URL.createObjectURL(blob);
}, 'image/png');
};
return {
afterRead,
};
},
};
</script>
说明:
html2canvas
配置:
logging: false
:禁用日志输出。
scale: window.devicePixelRatio
:支持高清屏。
useCORS: true
:启用跨域,确保图片资源可以被正确加载。
绘制水印:
使用 html2canvas
将水印元素转换为 canvas 图像。
将生成的水印 canvas 图像绘制到主 canvas 上。
生成最终图片:
将主 canvas 转换为 Blob,并替换上传的文件内容。
优点
-
灵活性高:可以将任何 HTML 元素转换为 canvas 图像,这意味着你可以使用 HTML 和 CSS 创建非常复杂的水印效果,比如带有图标、多行文本、不同字体和颜色等。
-
可视化设计:可以直接在页面上设计水印的样式,所见即所得,不需要通过代码去想象最终效果。
-
兼容性较好:
html2canvas
会尽可能地将页面元素渲染成与浏览器中显示一致的图像,减少了因手动绘制带来的兼容性问题。
缺点
-
依赖外部库:需要引入
html2canvas
库,增加了项目的依赖和体积。 -
性能问题:将 HTML 元素转换为 canvas 图像的过程可能会有一定的性能开销,尤其是在水印元素复杂或者页面元素较多的情况下。
-
配置复杂:可能需要调整
html2canvas
的各种配置选项,以确保生成的图像符合预期,比如设置背景色、处理透明度等。
依赖安装
cnpm install compressorjs html2canvas
方法2:使用canvas结合vant中组件
使用纯canvas操作直接绘制水印文本
vant的van-uploader组件提供了after-read事件,在其中调用水印处理函数
增加水印方法
/**
* 添加水印
* @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,
allowTaint: false,
useCORS: true,
backgroundColor,
});
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);
},
});
});
}
在vue组件中使用
<template>
<div>
<van-uploader
v-model="fileList"
multiple
:after-read="afterRead"
:before-read="beforeRead"
/>
<!-- 水印内容 -->
<div id="markImg" style="display: none;">
<div style="font-size: 14px; color: rgba(255, 255, 255, 0.3);">
水印文字
</div>
</div>
</div>
</template>
<script>
import { addWaterMarker, compressor } from '@/utils/watermark';
import Compressor from 'compressorjs';
export default {
data() {
return {
fileList: [], // vant 中图片上传的双向绑定
};
},
methods: {
// 上传前处理
async beforeRead(file) {
return new Promise(async (resolve, reject) => {
if (Array.isArray(file)) {
if (file.length > 5) {
this.$toast('一次最多上传5张,请分批次上传!');
reject();
return;
}
let blobs = [];
for (const f of file) {
// 大于 512k 的图片则先压缩
if (f.size > 512 * 1024 && f.type.includes('image/')) {
f = await this.compressor(f);
}
// 添加水印
let blob = await addWaterMarker(f);
blob.name = f.name;
blobs.push(blob);
}
resolve(blobs);
} else {
// 大于 512k 的图片则先压缩
if (file.size > 512 * 1024 && file.type.includes('image/')) {
file = await this.compressor(file);
}
const blob = await addWaterMarker(file);
blob.name = file.name;
resolve(blob);
}
});
},
// 上传后处理
async afterRead(file) {
// 处理上传逻辑
console.log('上传成功', file);
},
// 压缩图片
async compressor(file) {
return new Promise((resolve) => {
new Compressor(file, {
quality: 0.6,
success: resolve,
error(err) {
console.log(err.message);
},
});
});
},
},
};
</script>
要点
addWaterMarker
:添加水印的核心方法,负责将水印内容绘制到图片上。
beforeRead
:在图片上传前处理,包括压缩和添加水印。
afterRead
:图片上传后的处理逻辑。使用了
html2canvas
将水印内容转换为图片。使用了
compressorjs
对图片进行压缩。
码字不易,各位大佬点点赞呗