如何利用js实现水印效果(基于vant的van-upload实现)
页面代码
<Uploader
v-model="imageList"
:before-read="beforeUpload"
:max-count="1"
:after-read="onUploadImage"
@delete="deleteImage">
<Button type="primary">
<img class="add-upload" src="@/assets/img/doctor/add.png" />
</Button>
</Uploader>
为图片添加水印的函数
//画布添加水印
const drawWaterMark = (ctx, imgWidth, imgHeight, wmConfig) => {
let fontSize;
if (imgWidth >= 3456) {
fontSize = 200;
} else if (imgWidth >= 2700) {
fontSize = 120;
} else if (imgWidth >= 2000) {
fontSize = 104;
} else if (imgWidth >= 1436) {
fontSize = 80;
} else if (imgWidth >= 800) {
fontSize = 48;
} else if (imgWidth >= 500) {
fontSize = 30;
} else {
fontSize = 20;
}
console.log(imgWidth, imgHeight, fontSize);
ctx.fillStyle = "white";
ctx.font = `${fontSize}px ${wmConfig.font}`;
ctx.lineWidth = 1;
ctx.fillStyle = "rgba(255,255,255,0.6)";
ctx.textAlign = "left";
ctx.textBaseline = "middle";
//文字坐标
const maxPx = Math.max(imgWidth, imgHeight);
const stepPx = Math.floor(maxPx / wmConfig.density);
let arrayX = [0]; //初始水印位置 canvas坐标 0 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;
})
);
console.log(arrayX);
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 / 5);
if (wmConfig.textArray.length > 3) {
wmConfig.textArray = wmConfig.textArray.slice(0, 3);
}
wmConfig.textArray.forEach((el, index) => {
let offsetY = fontSize * index + 2;
ctx.fillText(el, arrayX[i], arrayX[j] + offsetY);
});
ctx.restore();
}
}
};
//返回添加了水印的base64图片数据
export const base64AddWaterMaker = (base64Img, wmConfig) => {
if (wmConfig.textArray.length === 0) {
console.error("****没有水印内容*****");
return base64Img;
}
return new Promise((resolve, reject) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
const img = new Image();
let resultBase64 = null;
img.crossOrigin = "*";
img.onload = function () {
canvas.width = img.width;
canvas.height = img.height;
//canvas绘制图片,0 0 为左上角坐标原点
ctx.drawImage(img, 0, 0);
//写入水印
drawWaterMark(ctx, img.width, img.height, wmConfig);
resultBase64 = canvas.toDataURL("image/png");
if (!resultBase64) {
reject();
} else {
resolve(resultBase64);
}
};
img.src = base64Img;
});
};
在beforeRead中调用添加水印的方法,方便上传
//图片上传前添加水印
addImageWaterMarker(e, index) {
return new Promise(async (resolve, reject) => {
let wmConfig = {
font: "microsoft yahei", //字体
textArray: ["仅限于平台认证使用"], //水印文本内容,允许数组最大长度3 即:3行水印
density: 2, //密度 建议取值范围1-5 值越大,水印越多,可能会导致水印重叠等问题,慎重!!!
};
let fileData = await this.fileToBase64Async(e);
let resultBase64 = await base64AddWaterMaker(fileData, wmConfig);
this.dealImage(resultBase64, 600, async (base64) => {
resultBase64 = base64;
let file = this.dataURLtoFile(resultBase64, e.name);
console.log("..........file", file);
this.imgIndex = index;
resolve(file);
}); //压缩图片
});
},
对生成的base64数据进行压缩,以达到减少带宽的目的
//压缩base64方法
dealImage(base64, w, callback) {
var newImage = new Image();
var quality = 0.6; //压缩系数0-1之间
newImage.src = base64;
newImage.setAttribute("crossOrigin", "Anonymous"); //url为外域时需要
var imgWidth, imgHeight;
newImage.onload = function () {
imgWidth = this.width;
imgHeight = this.height;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
if (Math.max(imgWidth, imgHeight) > w) {
if (imgWidth > imgHeight) {
canvas.width = w;
canvas.height = (w * imgHeight) / imgWidth;
} else {
canvas.height = w;
canvas.width = (w * imgWidth) / imgHeight;
}
} else {
canvas.width = imgWidth;
canvas.height = imgHeight;
quality = 0.6;
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
var base64 = canvas.toDataURL("image/jpeg", quality); //压缩语句
callback(base64); //必须通过回调函数返回,否则无法及时拿到该值
};
},