目录标题
- 一、前端代码
- 二、完整前后端代码
一、前端代码
- watermark.js 工具类
/**
* 添加水印 异步
* @param {图片file,在inout中的file} file
* @param {水印数组,比如名字,电话,时间,地址} watermarks
*/
function addWatermarkAndUpload(file, watermarks) {
return new Promise(((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (event) {
const img = new Image();
img.onload = function () {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// 设置canvas尺寸与图片一致
canvas.width = img.width;
canvas.height = img.height;
// 绘制图片到canvas
ctx.drawImage(img, 0, 0, img.width, img.height);
//水印大小和颜色
let fontSize = 100
ctx.font = fontSize + 'px Arial';
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
//水印起始位置,默认左下角
let x = 20
let y = 20
// 添加水印
for (let i = 0; i < watermarks.length; i++) {
y = watermarkHandle(ctx, watermarks[i], canvas.width, canvas.height, fontSize, x, y)
}
// 将带有水印的canvas转换为Blob对象
canvas.toBlob((blob) => {
if (blob) {
blob.name = file.name
resolve(blob);
} else {
reject(new Error('Failed to create blob from canvas'));
}
}, 'image/png');
};
img.src = event.target.result;
};
reader.readAsDataURL(file);
}));
}
/**
* 写入水印,默认左下角 水印过长,换行 (x,y)=(0,0) 就是左下角的位置
* @param {canvas画布对象} ctx
* @param {单个水印} watermark
* @param {图片的长宽} height
* @param {图片的长宽} width
* @param {水印字体大小} fontSize
* @param {水印位置,默认左下角} x
* @param {水印位置,默认左下角} y
*/
function watermarkHandle(ctx, watermark, width, height, fontSize, x, y) {
//添加水印
let lineHeight = fontSize + 10
let line = '';
const list = [];
for (let i = 0; i < watermark.length; i++) {
const testLine = line + watermark[i];
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth < width - fontSize && i < watermark.length - 1) {
line = testLine;
} else {
list.push(line)
line = watermark[i];
}
}
const testLine = line + list[list.length - 1];
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth < width - fontSize) {
list[list.length - 1] = list[list.length - 1] + line
} else {
list.push(line)
}
for (let i = list.length - 1; i >= 0; i--) {
ctx.fillText(list[i], x, height - y);
y += lineHeight;
}
//位置
return y;
}
- 使用
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片水印并上传示例</title>
</head>
<body>
<input type="file" id="imageFile" accept="image/*">
<button onclick="addWatermark()">添加水印并上传</button>
<script th:src="@{/js/watermark.js}"></script>
<script>
function addWatermark() {
const imageFileInput = document.getElementById('imageFile');
const file = imageFileInput.files[0];
if (!file) {
alert('请先选择图片!');
return;
}
var watermarks = []
watermarks.push("广西壮族自2心2圩街2汇11111111111111111111111112")
watermarks.push("2024-05-11 19:13:04 ")
watermarks.push("李华 130733376")
const promises = [];
for (let i = 0; i < 3; i++) {
promises.push(addWatermarkAndUpload(file, watermarks))
}
Promise.all(promises)
.then(results => {
// 当所有Promise都完成时,results数组包含所有结果
console.log(results);
// 在这里你可以一起处理所有结果
const formData = new FormData();
for (let i = 0; i < results.length; i++) {
console.log(results[i])
formData.append('files', results[i], results[i].name);
}
return formData;
})
.then(formData => {
//上传,注意上传接口多个文件
return fetch('/common/uploads', {
method: 'POST',
body: formData
});
})
.then(response => {
// 处理响应
return response.json();
})
.then(data => {
// 处理返回的数据,url
console.log(data);
//其他操作操作
})
.catch(error => {
// 处理错误
console.error('Error:', error);
})
}
</script>
</body>
</html>
二、完整前后端代码
全部代码