上来先放一张成果图
背景
有一天突然想着给图片加水印的事情,就想着来实现一下.
环境
使用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,获取选取的文件。 在读取到图片后,根据页面大小缩放一下。
盖章
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, 很麻烦
加一个拖拽载入图片的效果
利用 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]是你拖入的文件