当前位置: 首页 > article >正文

vue前端项目中实现电子签名功能(附完整源码)

文章目录

    • 一、具体思路
    • 二、所需依赖
    • 三、添加签名面板
      • 2.1 canvas 转base64
      • 2.2 电子签名等比例缩小
    • 四、html转cavas(原始文档)
    • 五、合成图片
    • 六、效果测试
    • 七、完整源码

一、具体思路

在vue项目中使用以下步骤思路去实现:

  1. 起初的原始文档的格式都转成图片格式来处理;

  2. 电子签名的模板转成base64

  3. 前端将文档的样式和电子签名的模板合成一张图片,进行预览

通过原始图片文档与电子签名的图片进行合并,期间需要调整签名base64的位置和缩放比例,然后添加合并到原始文档,最终形成签名后的文档。

二、所需依赖

npm i signature_pad@4.2.0

npm i html2canvas

signature_pad 签名板 https://www.npmjs.com/package/signature_pad
html2canvas html转cavas https://www.npmjs.com/package/html2canvas

三、添加签名面板

        <div class="sign-box" style="width:300px;height:200px;padding: 10px; margin:10px;background-color: rgb(221 216 216);">
            <p><span style="color: #f00;">*</span>签名版<span style="color: #f00;">*</span></p>
            <div>
                <canvas id="signCanvas"/>
            </div>
            <button type="default" @click="clear()">清除</button>
            <button type="default" @click="review()">游览</button>
            <button aria-placeholder="添加签名到文件" type="default" @click="submit()">提交</button>
        </div>
import SignaturePad from 'signature_pad'
    mounted() {
        const canvas = document.getElementById('signCanvas')
        this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' })  //penColor   笔的颜色
    },

在这里插入图片描述
发现我鼠标所在的位置跟落笔产生了偏移 需要调用一下这个 adjustSignatureImgPos这个方法

        //校正签名位置偏移
        adjustSignatureImgPos() {
            const canvas = document.getElementById('signCanvas')
            const ratio = Math.max(window.devicePixelRatio || 1, 1) // 清除画布
            canvas.width = canvas.offsetWidth * ratio
            canvas.height = canvas.offsetHeight * ratio
            canvas.getContext('2d').scale(ratio, ratio)
        },
    mounted() {
        const canvas = document.getElementById('signCanvas')
        this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' })  //penColor   笔的颜色
        this.adjustSignatureImgPos()

    },

在这里插入图片描述

2.1 canvas 转base64

this.signatureimgSrc =this.signatureExample.toDataURL('image/png')   //得到了就是base64的   

打印输入如下:
在这里插入图片描述

2.2 电子签名等比例缩小

把生成的电子签名等比例缩小

传入我们电子签名的base64,然后生成一个新元素image ,改变它的大小,然后在通过canvas转成base64,在return 出来

我们需要使用Promise去异步处理他,并拿到返回的新base64

        // 绘制的canvas 进行缩放并转为base64
        resizeImage(src) {
            return new Promise((resolve) => {
                const img = new Image()
                img.src = src
                img.onload = () => {
                const originalWidth = img.width
                const originalHeight = img.height
                const scaleFactor = 0.5 // 缩放的倍数
                const resizedWidth = originalWidth * scaleFactor
                const resizedHeight = originalHeight * scaleFactor
                const canvas = document.createElement('canvas')
                canvas.width = resizedWidth
                canvas.height = resizedHeight
                const ctx = canvas.getContext('2d')
                ctx.drawImage(img, 0, 0, resizedWidth, resizedHeight)
                const base64 = canvas.toDataURL('image/png')
                resolve(base64)
                }
            })
        },

在这里插入图片描述

效果如下:

在这里插入图片描述

四、html转cavas(原始文档)

我们需要把html编写的文档转成base64
这个我们用html2canvas 这个插件:

import html2canvas from 'html2canvas'
html2canvas(document.querySelector("#capture")).then(canvas => {
  this.htmlimgUrl = canvas.toDataURL("image/png"); // 将canvas转换成img的src流
});

五、合成图片

接下来我们需要将html文档和电子签名模板,合成一张图片

写一个合并图片的方法:

传入两个参数,分别是原始图片文档和电子签名图片文档;

        //合并图片
        mergeimg(imgUrl,signatureimgSrc){
            // 创建一个 canvas 元素
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');

            // 创建两个图像对象
            const img1 = new Image();
            const img2 = new Image();

            // 设置图像的 src 属性为 Base64 编码的字符串
            img1.src = imgUrl;
            img2.src = signatureimgSrc;

            // 设置 canvas 的宽度和高度
            // 这里假设我们将图像水平排列,因此宽度是两幅图宽度之和,高度取最大值
            canvas.width = img1.width + img2.width;
            canvas.height = Math.max(img1.height, img2.height);

            // 绘制第一张图像
            ctx.drawImage(img1, 0, 0);
            // 绘制第二张图像,放置在第一张图像的右边
            ctx.drawImage(img2, 300, 500);

            // 将合并后的图像导出为 Base64 编码的字符串
            this.mergedImage = canvas.toDataURL('image/png');
        },

调用合并图片方法:

   //点击提交 进行合并图片 保存签名面板内容
   submit(){
       this.mergeimg(this.imgUrl,this.signatureimgSrcScale)
   },

六、效果测试

在这里插入图片描述

七、完整源码

<template>
    <div class="page">

        <div>
            <h3>原文档</h3>
            <h3>-----------------------</h3>
            <img :src="imgUrl">
        </div>
        
        <div class="sign-box" style="width:300px;height:200px;padding: 10px; margin:10px;background-color: rgb(221 216 216);">
            <p><span style="color: #f00;">*</span>签名版<span style="color: #f00;">*</span></p>
            <div>
                <canvas id="signCanvas"/>
            </div>
            <button type="default" @click="clear()">清除</button>
            <button type="default" @click="review()">游览</button>
            <button aria-placeholder="添加签名到文件" type="default" @click="submit()">提交</button>
        </div>

        <div>
            <h3>签名</h3>
            <img :src="signatureimgSrcScale">
        </div> 

        <div>
            <h3>签名后的文档</h3>
            <h3>-----------------------</h3>
            <img :src="mergedImage">
        </div>
    </div>
</template>

<script>
import SignaturePad from 'signature_pad'
import html2canvas from 'html2canvas'
import pdf from 'vue-pdf'

export default {
    components: {
        pdf
    },
    data() {
        return {
            imgUrl: '../../static/file.png',
            signatureimgSrc: null,
            htmlimgUrl: null,
            signatureExample: null,
            mergedImage: null,
            signatureimgSrcScale: null
        }
    },
    mounted() {
        const canvas = document.getElementById('signCanvas')
        this.signatureExample = new SignaturePad(canvas, { penColor: 'rgb(0, 0, 0)' })  //penColor   笔的颜色
        this.adjustSignatureImgPos()

    },
    created() {

    },
    methods: {
        //校正签名位置偏移
        adjustSignatureImgPos() {
            const canvas = document.getElementById('signCanvas')
            const ratio = Math.max(window.devicePixelRatio || 1, 1) // 清除画布
            canvas.width = canvas.offsetWidth * ratio
            canvas.height = canvas.offsetHeight * ratio
            canvas.getContext('2d').scale(ratio, ratio)
        },
        //html页面内容转为base64
        html2base64(){
          html2canvas(document.querySelector("#capture")).then(canvas => {
            this.htmlimgUrl = canvas.toDataURL("image/png"); // 将canvas转换成img的src流
          });
        },
        //合并图片
        mergeimg(imgUrl,signatureimgSrc){
            // 创建一个 canvas 元素
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');

            // 创建两个图像对象
            const img1 = new Image();
            const img2 = new Image();

            // 设置图像的 src 属性为 Base64 编码的字符串
            img1.src = imgUrl;
            img2.src = signatureimgSrc;

            // 等待两张图像都加载完毕
            // await Promise.all([this.loadImage(img1), this.loadImage(img2)]);

            // 设置 canvas 的宽度和高度
            // 这里假设我们将图像水平排列,因此宽度是两幅图宽度之和,高度取最大值
            canvas.width = img1.width + img2.width;
            canvas.height = Math.max(img1.height, img2.height);

            // 绘制第一张图像
            ctx.drawImage(img1, 0, 0);
            // 绘制第二张图像,放置在第一张图像的右边
            ctx.drawImage(img2, 300, 500);

            // 将合并后的图像导出为 Base64 编码的字符串
            this.mergedImage = canvas.toDataURL('image/png');
        },
        loadImage(img) {
            return new Promise((resolve, reject) => {
                img.onload = resolve;
                img.onerror = reject;
            });
        },

        //点击清除按钮 清除签名面板内容        
        clear(){
            //清除签名面板的方法
            this.signatureExample.clear()
        },
        async review(){
            this.signatureimgSrc =this.signatureExample.toDataURL('image/png')
            this.signatureimgSrcScale =await this.resizeImage(this.signatureExample.toDataURL('image/png'))

            console.log("======== this.signatureimgSrc==========", this.signatureimgSrc)

        },
        //点击提交 进行合并图片 保存签名面板内容
        submit(){
            this.mergeimg(this.imgUrl,this.signatureimgSrcScale)
        },
        // 绘制的canvas 进行缩放并转为base64
        resizeImage(src) {
            return new Promise((resolve) => {
                const img = new Image()
                img.src = src
                img.onload = () => {
                const originalWidth = img.width
                const originalHeight = img.height
                const scaleFactor = 0.5 // 缩放的倍数
                const resizedWidth = originalWidth * scaleFactor
                const resizedHeight = originalHeight * scaleFactor
                const canvas = document.createElement('canvas')
                canvas.width = resizedWidth
                canvas.height = resizedHeight
                const ctx = canvas.getContext('2d')
                ctx.drawImage(img, 0, 0, resizedWidth, resizedHeight)
                const base64 = canvas.toDataURL('image/png')
                resolve(base64)
                }
            })
        },

    }
}
</script>
<style>
.page{
    display: flex;
    flex-direction: row;
    margin: 10px;
    text-align: center;
    background: #fff;
    padding: 10px;
}
</style>

上述代码只是平常练习使用,如需使用在正式项目中,请自行修改完善!!!

在这里插入图片描述


人生从来没有真正的绝境。只要一个人的心中还怀着一粒信念的种子,那么总有一天,他就能走出困境,让生命重新开花结果。



http://www.kler.cn/a/451828.html

相关文章:

  • 最新的强大的文生视频模型Pyramid Flow 论文阅读及复现
  • 重温设计模式-外观模式和适配器模式的异同
  • 【Python】基础语法介绍
  • 【论文复现】农作物病害分类(Web端实现)
  • sqoop的参数有哪些?
  • Spring Boot 应用开发入门(一)
  • 物联网:全面概述、架构、应用、仿真工具、挑战和未来方向
  • 字符编码(四)
  • 谷歌开发者工具 -来源/源码篇
  • 【网络云计算】2024第51周-每日【2024/12/20】小测-理论-周测-解析
  • MySQL-MVCC(多版本并发控制)
  • 洛谷 P11242 碧树 C语言
  • openGauss系列_Centos 7.6 使用 PTK v0.5 安装部署 MogDB v3.0.3 一主两备级联集群
  • YOLOv9-0.1部分代码阅读笔记-plots.py
  • P7——pytorch马铃薯病害识别
  • 使用envoyfilter添加请求头
  • windows nacos安装配置
  • 反应力场的生成物、反应路径分析方法
  • unity弹出新的类似独立场景窗口独立运行一般怎么实现?
  • 【文档搜索引擎】搜索模块的完整实现
  • docker 部署HivisionIDPhotos实现证件照制作
  • springboot/ssm太原学院商铺管理系统Java代码编写web在线购物商城
  • dolphinscheduler服务RPC负载均衡源码解析(二)基于多种不同算法的负载均衡策略实现源码解析
  • 一文掌握如何编写可重复执行的SQL
  • Day55 图论part05
  • 【uniapp】支付宝付款成功后怎么调回自定义页面