实现效果图
图片添加水印的步骤
- 获取图片路径,将图片转换为canvas
- canvas画布上绘制文字水印
- 预览:水印绘制完成后,将canvas转换为图片格式
- 下载:水印绘制完成后,将canvas下载为图片
1.获取图片路径,将图片转换为canvas
async function imgToCanvas(url) {
const img = document.createElement("img");
img.src = url;
img.setAttribute("crossOrigin", "anonymous");
await new Promise((resolve) => (img.onload = resolve));
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
return canvas;
}
2.canvas画布上绘制文字水印
const drawWaterMark = ({ canvas, textArray, fontFamily = "microsoft yahei", fontSize, fontcolor = "#dadbdc", rotate = 30, textAlign = "left", density = 2.0 }) => {
const ctx = canvas.getContext("2d");
let imgWidth = canvas.width;
let imgHeight = canvas.height;
ctx.font = `${fontSize}px ${fontFamily}`;
ctx.lineWidth = 1;
ctx.fillStyle = fontcolor;
ctx.textAlign = textAlign;
ctx.textBaseline = "middle";
const maxPx = Math.max(imgWidth, imgHeight);
const stepPx = Math.floor(maxPx / density);
let arrayX = [0];
while (arrayX[arrayX.length - 1] < maxPx / 2) {
arrayX.push(arrayX[arrayX.length - 1] + stepPx);
}
arrayX.push(
...arrayX.slice(1, arrayX.length).map((el) => {
return -el;
})
);
for (let i = 0; i < arrayX.length; i++) {
for (let j = 0; j < arrayX.length; j++) {
ctx.save();
ctx.translate(imgWidth / 2, imgHeight / 2);
ctx.rotate((Math.PI / 120) * -rotate);
if (textArray.length > 3) {
textArray = textArray.slice(0, 3);
}
textArray.forEach((el, index) => {
let offsetY = fontSize * index + 2;
ctx.fillText(el, arrayX[i], arrayX[j] + offsetY);
});
ctx.restore();
}
}
};
3.水印绘制完成后,将canvas转换为图片格式
export function canvasToImg({canvas, maxWidth = "100%", maxHeight = "100%"}) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
image.style.maxHeight = maxHeight;
image.style.maxWidth = maxWidth;
return image;
}
4.水印绘制完成后,将canvas下载为图片
export function downloadCanves(canvas, filename = "下载") {
let base64 = canvas.toDataURL("image/png");
let blob = dataURItoBlob(base64);
const a = document.createElement("a");
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
完整代码总结
1、在utils.js 封装添加水印的通用方法,将以上方法export导出
export async function imgToCanvas(url) {
const img = document.createElement("img");
img.src = url;
img.setAttribute("crossOrigin", "anonymous");
await new Promise((resolve) => (img.onload = resolve));
const canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext("2d").drawImage(img, 0, 0);
return canvas;
}
export const drawWaterMark = ({ canvas, textArray, fontFamily = "microsoft yahei", fontSize, fontcolor = "#dadbdc", rotate = 30, textAlign = "left", density = 2.0 }) => {
const ctx = canvas.getContext("2d");
let imgWidth = canvas.width;
let imgHeight = canvas.height;
ctx.font = `${fontSize}px ${fontFamily}`;
ctx.lineWidth = 1;
ctx.fillStyle = fontcolor;
ctx.textAlign = textAlign;
ctx.textBaseline = "middle";
const maxPx = Math.max(imgWidth, imgHeight);
const stepPx = Math.floor(maxPx / density);
let arrayX = [0];
while (arrayX[arrayX.length - 1] < maxPx / 2) {
arrayX.push(arrayX[arrayX.length - 1] + stepPx);
}
arrayX.push(
...arrayX.slice(1, arrayX.length).map((el) => {
return -el;
})
);
for (let i = 0; i < arrayX.length; i++) {
for (let j = 0; j < arrayX.length; j++) {
ctx.save();
ctx.translate(imgWidth / 2, imgHeight / 2);
ctx.rotate((Math.PI / 120) * -rotate);
if (textArray.length > 3) {
textArray = textArray.slice(0, 3);
}
textArray.forEach((el, index) => {
let offsetY = fontSize * index + 2;
ctx.fillText(el, arrayX[i], arrayX[j] + offsetY);
});
ctx.restore();
}
}
};
export function canvasToImg({canvas, maxWidth = "100%", maxHeight = "100%"}) {
var image = new Image();
image.src = canvas.toDataURL("image/png");
image.style.maxHeight = maxHeight;
image.style.maxWidth = maxWidth;
return image;
}
export function downloadCanves(canvas, filename = "下载") {
let base64 = canvas.toDataURL("image/png");
let blob = dataURItoBlob(base64);
const a = document.createElement("a");
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = filename;
a.click();
window.URL.revokeObjectURL(url);
}
2、在页面import 导入方法并调用
<template>
<!-- 水印图片预览 -->
<div class="content">
<div class="imageBox" id="imageBox"></div>
<el-button type="primary" @click="downFile" style="margin-top: 10px; width: 100px">下 载</el-button>
</div>
</template>
<script>
import { drawWaterMark, imgToCanvas, canvasToImg, downloadCanves } from "@/utils/fileUtils.js";
export default {
data() {
return {
fileUrl:"XXXX.jpg",
fontSize: 50,
objmsg: {
canvas: null,
textArray: ["水印图片", "2022-01-01"],
fontFamily: "fangsong",
fontSize: 30,
fontcolor: "#fff",
rotate: 30,
textAlign: "center",
density: 3.0,
},
};
},
mounted() {
this.drawWaterMarkFn();
},
methods: {
async drawWaterMarkFn() {
const tempCanvas = await imgToCanvas(this.fileUrl);
this.objmsg.canvas = tempCanvas
drawWaterMark(this.objmsg);
const waterImage = await canvasToImg({
canvas: tempCanvas,
maxWidth: "650px",
maxHeight: "650px",
});
var Box = document.getElementById("imageBox");
Box.appendChild(waterImage);
},
async downFile() {
const tempCanvas = await imgToCanvas(this.fileUrl);
this.objmsg.canvas = tempCanvas
await drawWaterMark(this.objmsg);
downloadCanves(tempCanvas, "水印图片下载");
},
},
};
</script>
<style lang="scss" scoped>
.waterMakerinfo {
.content {
text-align: center;
::v-deep .imageBox {
max-height: 650px;
min-height: 500px;
.img {
width: 100%;
height: 100%;
}
}
}
::v-deep {
.el-dialog__footer {
text-align: right !important;
position: absolute;
width: 200px;
top: unset;
right: 20px;
bottom: 0px;
padding: 10px !important;
padding-left: 20px !important;
background-color: transparent !important;
z-index: 99;
}
}
}
</style>