上来先放一张成果图
背景
有一天突然想着给图片加水印的事情,就想着来实现一下.
环境
使用vue-cli建了一个简单项目
思路
使用canvas技术, 先将图片导入至canvas,在canvas中加水印图片,达到盖章的效果。
实现
导入图片
// 导入图片
importImg() {
const input = document.createElement("input");
const context = this.$refs.canvas.getContext("2d"); // this.$refs.canvas是canvas的dom对象
input.type = "file";
input.click();
input.onchange = () => {
const file = input.files[0];
if (file.type.indexOf("image") == 0) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
const img = new Image();
img.src = reader.result;
img.onload = () => {
let imgW = img.width;
let imgH = img.height;
const width = this.$refs.main.offsetWidth;
const height = this.$refs.main.offsetHeight;
if (imgH > imgW) {
this.$refs.canvas.width = (imgW * height) / imgH;
this.$refs.canvas.height = height;
context.drawImage(img, 0, 0, (imgW * height) / imgH, height);
console.log((imgW * height) / imgH, height);
} else {
this.$refs.canvas.width = width;
this.$refs.canvas.height = (imgH * width) / imgW;
context.drawImage(img, 0, 0, width, (imgH * width) / imgW);
console.log(width, (imgH * width) / imgW);
}
};
};
}
};
解析: 创建一个input,type 为 file,获取选取的文件。 在读取到图片后,根据页面大小缩放一下。 FileReade解释 Image对象
盖章
import icon from "./assets/logo.png";
// 印章
addMark(e) { // addMark为canvas点击事件
const img = new Image();
img.src = icon; // icon是要盖的图片
img.onload = () => {
const context = this.$refs.canvas.getContext("2d");
context.drawImage(
img,
e.offsetX - this.markWidth / 2, // markWidth是印章的宽度
e.offsetY - this.markHeight / 2, // markHeight是印章的高度
this.markWidth,
this.markHeight
);
};
},
解析: 监听点击事件,将印章定位到对应位置
转换
// 生成图片
downImg() {
this.$refs.canvas.toBlob((blob) => {
let url = window.URL.createObjectURL(blob);
let link = document.createElement("a");
link.href = url;
link.download = "加水印";
link.target = "_blank";
link.click();
});
},
解析:将canvas转为blob,然后下载, 可通过toBlob控制图片的类型, 默认为png
注意:别转base64, 很麻烦 HTMLCanvasElement.toBlob()
加一个拖拽载入图片的效果
利用 dragover事件和drop事件加入效果 给容器添加事件
<main ref="main" @dragover.prevent="dragover" @drop.prevent="drop">
<canvas ref="canvas" @click="addMark"></canvas>
</main>
注意这里的prevent事件修饰符,是用来阻止浏览器默认打开图片的行为的,dragover函数为空函数就好
drop(e) {
if (e.dataTransfer.files[0].type.indexOf("image") === -1) return;
const reader = new FileReader();
const context = this.$refs.canvas.getContext("2d");
reader.readAsDataURL(e.dataTransfer.files[0]);
reader.onload = () => {
const img = new Image();
img.src = reader.result;
img.onload = () => {
let imgW = img.width;
let imgH = img.height;
const width = this.$refs.main.offsetWidth;
const height = this.$refs.main.offsetHeight;
if (imgH > imgW) {
this.$refs.canvas.width = (imgW * height) / imgH;
this.$refs.canvas.height = height;
context.drawImage(img, 0, 0, (imgW * height) / imgH, height);
} else {
this.$refs.canvas.width = width;
this.$refs.canvas.height = (imgH * width) / imgW;
context.drawImage(img, 0, 0, width, (imgH * width) / imgW);
}
};
};
}
解析: 操作和载入图片的操作一致, e.dataTransfer.files[0]是你拖入的文件
成果
看完点个赞吧