一起给图片盖个章吧

2,079 阅读1分钟

上来先放一张成果图

背景

有一天突然想着给图片加水印的事情,就想着来实现一下.

环境

使用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]是你拖入的文件

成果

看完点个赞吧