目錄
方法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);// 獲取水印元素并轉換為 canvasconst 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 轉換成 blobcanvas.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-uploaderv-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
對圖片進行壓縮。
碼字不易,各位大佬點點贊唄