功能需求
产品要求前端在上传图片时自动给图片打上当前时间的水印
实现效果
直接上代码
这里还包含了上传视频和音频的内容,可无视
<!-- Annex.vue -->
<template>
<div class="annex">
<div class="annexTitle">
<span class="xing">*</span>
<span>附件(至少需上传一张照片):</span>
</div>
<div class="displayArea">
<div
class="displayAreaItem common"
v-for="item in annexArr[dataType]"
:key="item.id"
>
<!-- 视频 -->
<div class="mp4" v-if="item.type === 'mp4'">
<!-- <img class="displayImg" :src="item.videoImgUrl" alt="" />-->
<div class="displayImg"></div>
<img class="play" src="@/assets/play.png" alt="" />
</div>
<!-- 图片 -->
<div v-if="verifyImg.includes(item.type)" class="displayImgArea">
<img class="displayImg" :src="item.url" alt="" />
<div
v-if="showSelectType"
@click="selectType(item)"
class="displayBox"
>
{{ item.classifyName || "选择类型" }}
</div>
</div>
<!-- 音频 -->
<div class="mp3" v-if="item.type === 'wav'">
<img src="@/assets/audio.png" alt="" />
</div>
<img
@click="displayClose(item)"
class="displayClose"
src="@/assets/close.png"
alt=""
/>
</div>
</div>
<!-- 三个按钮 -->
<div class="annexContent">
<div class="operationArea">
<div class="operationItem" v-for="item in operateImg" :key="item.text">
<img @click="photographClick(item)" :src="item.imgUrl" alt="" />
<!-- 手动加载模式 -->
<input
:ref="item.ref"
style="display: none"
type="file"
@change="onChange"
:accept="item.type"
multiple
/>
<div class="operationItemText">{{ item.text }}</div>
</div>
</div>
</div>
</div>
</template>
<script>
import dayjs from "dayjs";
import { handleAddWaterMarker } from "./watermark.js";
// 无用部分省略了
methods: {
onChange(e) {
if (this.beforeUpload(e.target.files[0])) {
const fileType = e.target.files[0].type.split("/")[0];
const file = e.target.files[0];
this.getFormData(file).then(async (data) => {
const res = await upload(data); // 调用上传文件的接口upload
this.clickImg.push({
id: res.data.fileId,
fileType: fileType,
type: res.data.fileExtName,
url: res.data.fileUrl,
name: res.data.fileName,
});
});
// 这一步是将得到的数据塞进页面展示的数组里,可根据自己项目来写
this.SET_ANNEX_ARR({ type: this.dataType, data: this.clickImg });
}
},
getFormData(file) {
const content = dayjs().format("YYYY-MM-DD HH:mm:ss"); // 当前时间
const fileType = file.type.split("/")[0];
const name = file.name.split(".")[0];
let formdata = new FormData();
return new Promise((resolve) => {
if (fileType === "image") { // !!!!图片类型的文件,进行打水印
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
const img = document.createElement("img"); // 手动创建一个img标签
img.src = reader.result;
img.onload = function () {
const res = handleAddWaterMarker(img, content, name);
formdata.append("file", res);
resolve(formdata);
};
};
} else {
formdata.append("file", file);
resolve(formdata);
}
});
},
beforeUpload(file) {
const isLt1M = file.size / 1024 / 1024 < 50;
if (isLt1M) {
return true;
}
console.log("上传文件不超过50M", "warning");
return false;
},
}
</script>
打水印的最主要方法在以下:
// watermark.js
export function handleAddWaterMarker(imageCon, content, fileName) {
let canvas = document.createElement("canvas"); //创建canvas容器
canvas.width = imageCon.width; //设置canvas容器宽度
canvas.height = imageCon.height; //设置canvas容器高度
let ctx = canvas.getContext("2d"); //获取2d画笔
//在canvas画布上绘制图片 ctx.drawImage(图片, x位置, y位置, 图像宽度, 图像高度);
ctx.drawImage(imageCon, 0, 0, imageCon.width, imageCon.height);
//设置文本画笔的样式
ctx.textAlign = "right"; //设置文本对齐方式
ctx.textBaseline = "top"; //设置文本基线
ctx.font = "12px PingFang SC, PingFang SC-Regular"; //设置文本字体属性
ctx.fillStyle = "#FFFFFF"; //设置文本字体颜色
ctx.shadowBlur = 4;
ctx.shadowColor = "rgba(0,0,0,0.50)";
//在canvas画布上绘制文字 ctx.fillText(文字内容, x位置, y位置, 文本最大宽度)
ctx.fillText(
content,
// imageCon.width - (content.split("").length * 12 + 8),
imageCon.width - 8,
11,
imageCon.width
); //14为文字大小
const data = btof(canvas.toDataURL("image/png"), fileName); // canvas转base64输出
return data; // 但是我们需要的是file类型,所以需要再转一下
}
// base64转file
export function btof(data, fileName = "") {
const dataArr = data.split(",");
const byteString = atob(dataArr[1]);
const options = {
type: "image/png",
endings: "native",
};
const u8Arr = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
u8Arr[i] = byteString.charCodeAt(i);
}
return new File([u8Arr], fileName + ".png", options);
}