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

uniapp:手写签名,多张图合成一张图

要实现的内容:手写签名,协议内容。点击提交后:生成1张图片,有协议内容和签署日期和签署人。
实现的效果图如下:
在这里插入图片描述
在这里插入图片描述

1、签名页面

<template><view class="index"><u-navbar title="电子协议" :is-back="false" :border-bottom="false" title-color="#333" :background="{background:''}"><view class="page_navbar_warp"><image src="../../static/icon/0.png" mode="" class="page_navbar_commonImg" @click="$go(1,1)"></image></view></u-navbar><image src="https://www.*****/xieyi.png" mode="" class="banner"></image><view class="signBox"><view class="title">签名区</view><view style="width: 700rpx;height: 450rpx;"><l-signature disableScroll backgroundColor="rgba(255, 249, 238, .0)" ref="signatureRef" penColor="#333" :penSize="5" :openSmooth="true" ></l-signature></view></view><view class="footer"><view class="btn1 t-c" @click="onClick('undo')">撤消</view><u-button class="btn2 t-c" @click="onClick('save')" :loading="loading">提交</u-button></view></view>
</template><script>export default {data() {return {loading:false,}},methods:{onClick(type) {if(type == 'openSmooth') {this.openSmooth = !this.openSmoothreturn}if (type == 'save') {this.$refs.signatureRef.canvasToTempFilePath({success: (res) => {// 是否为空画板 无签名// 生成图片的临时路径// H5 生成的是base64let url = res.tempFilePath;console.log(res);if(res.isEmpty){this.$toast('请签名')}else{this.loading = true;this.$uploadImage('common/upload', url).then(res => {this.loading = false;if(res.code == 1){this.$go(2,'/pages/mine/canvas?signImg='+res.data.fullurl)}})}}})return}if (this.$refs.signatureRef) this.$refs.signatureRef[type]()}}}
</script><style scoped lang="scss">.index{min-height: 100vh;position: relative;.banner{display: block;width: 585rpx;height: 416rpx;margin: auto;}.signBox{border: 1rpx dashed #BF9350;width: 700rpx;height: 500rpx;margin: 32rpx auto;.title{padding-top: 32rpx;font-size: 40rpx;color: #BF9350;padding-left: 32rpx;}}.footer{position: fixed;left: 0;bottom: 0;width: 750rpx;height: 98rpx;background: #fff;box-shadow: 0rpx 3rpx 6rpx 1rpx rgba(0,0,0,0.32);padding: 0 50rpx;display: flex;align-items: center;justify-content: space-between;.btn1{width: 300rpx;height: 81rpx;border-radius: 41rpx 41rpx 41rpx 41rpx;border: 1rpx solid #BF9350;font-size: 32rpx;color: #BF9350;}.btn2{width: 300rpx;height: 81rpx;background: #BF9350;border-radius: 41rpx 41rpx 41rpx 41rpx;font-size: 32rpx;color: #fff;}}}
</style>

2、canvas页面,用来合成1张图

<template><view class="demo"><u-navbar title="电子协议" :is-back="false" :border-bottom="false" title-color="#333" :background="{background:'#FFFAF3'}"><view class="page_navbar_warp"><image src="../../static/icon/0.png" mode="" class="page_navbar_commonImg" @click="$go(1,1)"></image></view></u-navbar><canvas :style="{ width: canvasW + 'px', height: canvasH + 'px' }" canvas-id="myCanvas" id="myCanvas"></canvas><view class="footer"><view class="btn1 t-c" @click="$go(1,1)">取消</view><u-button class="btn2 t-c" @click="submit" :loading="loading" shape="circle" :ripple="true">提交</u-button></view></view>
</template>
<script>export default {components: {},data() {return {loading:false,canvasW:0, // 画布宽canvasH:0, // 画布高SystemInfo:{}, // 设备信息goodsImg: {}, // 协议图片signImg:{}, // 签名图片signW:120, // 签名图片大小bgImg:{},year:'',mon:'',date:'',tempFilePath:'',}},async onLoad(option) {var start = new Date();this.year = start.getFullYear();this.mon = start.getMonth() + 1;this.date = start.getDate();// 获取设备信息,主要获取宽度,赋值给canvasW 也就是宽度:100%this.SystemInfo = await this.getSystemInfo();// 获取协议图片,签名二维码图片信息,APP端会返回图片的本地路径(H5端只能返回原路径)this.bgImg = await this.getImageInfo('https://www.*******/xieyi.png');this.goodsImg = await this.getImageInfo('https://www.*******/bg.png');this.signImg = await this.getImageInfo(option.signImg);this.canvasW = this.SystemInfo.windowWidth; // 画布宽度// #ifdef APP-PLUSthis.canvasH = this.SystemInfo.windowHeight-94-uni.getSystemInfoSync().statusBarHeight;  // 画布高度 = 页面高度-(导航栏固定44px+footer的50px+APP内手机双跳栏的高度)// #endif// #ifdef H5this.canvasH = this.SystemInfo.windowHeight-94; // #endif// 如果主图,二维码图片,设备信息都获取成功,开始绘制海报,这里需要用setTimeout延时绘制,否则可能会出现图片不显示。if(this.goodsImg.errMsg == 'getImageInfo:ok' && this.signImg.errMsg == 'getImageInfo:ok' && this.SystemInfo.errMsg == 'getSystemInfo:ok'){uni.showToast({icon:'loading',mask:true,duration:10000,title: '加载中,请稍后',});setTimeout(()=>{var ctx = uni.createCanvasContext('myCanvas', this);// 填充背景ctx.drawImage(this.bgImg.path, 0, 0, this.canvasW, this.canvasH) // drawImage(图片路径,x,y,绘制图像的宽度,绘制图像的高度)// 绘制协议主图ctx.drawImage(this.goodsImg.path, 50, 60, this.canvasW-100, this.canvasW-180) // drawImage(图片路径,x,y,绘制图像的宽度,绘制图像的高度)// 签署日期ctx.setFontSize(16)ctx.setFillStyle('#333')ctx.fillText(`签署日期:${this.year}${this.mon}${this.date}`, 50, this.canvasH -this.signW-80);// 签署人ctx.setFontSize(14)ctx.setFillStyle('#333')ctx.fillText('签署人:', 50, this.canvasH -this.signW-40);// 签署人ctx.drawImage(this.signImg.path, 90, this.canvasH-this.signW-80, this.signW, this.signW) // drawImage(图片路径,x,y,绘制图像的宽度,绘制图像的高度,二维码的宽,高)ctx.draw(true,(ret)=>{ // draw方法 把以上内容画到 canvas 中。console.log(ret) uni.showToast({icon:'success',mask:true,title: '绘制完成',});uni.canvasToTempFilePath({ // 保存canvas为图片canvasId: 'myCanvas',quality: 1,complete: (res)=> {console.log(res)// 在H5平台下,tempFilePath 为 base64, // 图片提示跨域 H5保存base64失败,APP端正常输出临时路径if(res.tempFilePath){this.tempFilePath = res.tempFilePath;}},})});},1500)}else{console.log('err')}},methods: {submit(){this.loading = true;console.log('需要提交给后台的图片'this.tempFilePath)},// 获取图片信息getImageInfo(image) {return new Promise((req, rej) => {uni.getImageInfo({src: image,success: function(res) {req(res)},});})},// 获取设备信息getSystemInfo(){return new Promise((req, rej) => {uni.getSystemInfo({success: function (res) {req(res)}});})},},}
</script><style scoped lang="scss">.footer{position: fixed;left: 0;bottom: 0;width: 750rpx;height: 50px;box-shadow: 0rpx 3rpx 6rpx 1rpx rgba(0,0,0,0.32);padding: 0 50rpx;display: flex;align-items: center;justify-content: space-between;background: #fff;.btn1{width: 300rpx;height: 40px;border-radius: 41rpx 41rpx 41rpx 41rpx;border: 1rpx solid #BF9350;font-size: 32rpx;color: #BF9350;}.btn2{width: 300rpx;height: 40px;background: #BF9350;border-radius: 41rpx 41rpx 41rpx 41rpx;font-size: 32rpx;color: #fff;}}
</style>

备注:
1、协议页面内用的l-signature来自于uniapp插件市场
2、canvas页面灵感来自于之前写过的一篇绘制海报文章
3、页面中用到的 xieyi.png(协议内容)、bg.png(底图)、以及签名后的option.signImg(签名图),都需要后台设置允许跨域。否则H5就会报错画布污染无法生成base64。
在这里插入图片描述
这个问题在APP内不存在,只有H5会出现。

相关文章:

uniapp:手写签名,多张图合成一张图

要实现的内容&#xff1a;手写签名&#xff0c;协议内容。点击提交后&#xff1a;生成1张图片&#xff0c;有协议内容和签署日期和签署人。 实现的效果图如下&#xff1a; 1、签名页面 <template><view class"index"><u-navbar title"电子协议…...

DevExpress WPF Tree List组件,让数据可视化程度更高!(一)

DevExpress WPF Tree List组件是一个功能齐全、数据感知的TreeView-ListView混合体&#xff0c;可以把数据信息显示为REE、GRID或两者的组合&#xff0c;在数据绑定或非绑定模式下&#xff0c;具有完整的数据编辑支持。 DevExpress WPF 拥有120个控件和库&#xff0c;将帮助您…...

Linux操作系统下安装python环境

参考&#xff1a;Linux操作系统下安装python环境_linux如何下载python_秃头小猿-F的博客-CSDN博客 注意 切换用户 二、切换root用户 1.给root用户设置密码&#xff1a;命令&#xff1a;sudo passwd root输入密码&#xff0c;并确认密码。2.重新输入命令&#xff1a;su root …...

JavaScript的宏任务和微任务

宏任务和微任务 JS为微任务和宏任务简单介绍任务执行顺序例子任务执行顺序简单例子 关于new Promise实例化过程的例子 JS为微任务和宏任务简单介绍 js是单线程的&#xff0c;但是分同步异步微任务和宏任务皆为异步任务&#xff0c;它们都属于一个队列宏任务一般是&#xff1a;…...

java的空引用null和空字符串““

java中如果字符串变量指向null&#xff0c;表示空引用&#xff0c;此时对字符串求长度会抛出异常。 而""表示一个空字符串&#xff0c;对字符串求长度是可以的&#xff0c;求出来的字符串长度为0。 举例&#xff1a; package com.thb;public class Test6 {public s…...

Python+OpenCV实现自动扫雷,挑战扫雷世界记录!

目录 准备 - 扫雷软件 实现思路 - 01 窗体截取 - 02 雷块分割 - 03 雷块识别 - 04 扫雷算法实现 福利&#xff1a;文末有Python全套资料哦 我们一起来玩扫雷吧。用PythonOpenCV实现了自动扫雷&#xff0c;突破世界记录&#xff0c;我们先来看一下效果吧。 中级 - 0.74秒 …...

XtarBackup 8.0.33-28 prepare 速度提升 20 倍!

在这篇博文中&#xff0c;我们将描述 Percona XtraBackup 8.0.33-28 的改进&#xff0c;这显著减少了备份准备所需的时间&#xff0c;以便进行恢复操作。 Percona XtraBackup 中的这一改进显着缩短了新节点加入 Percona XtraDB 集群&#xff08;PXC&#xff09; 所需的时间。 …...

Blazor前后端框架Known-V1.2.8

V1.2.8 Known是基于C#和Blazor开发的前后端分离快速开发框架&#xff0c;开箱即用&#xff0c;跨平台&#xff0c;一处代码&#xff0c;多处运行。 Gitee&#xff1a; https://gitee.com/known/KnownGithub&#xff1a;https://github.com/known/Known 概述 基于C#和Blazor…...

python模拟加密爬取诸葛

用python模拟代码加密逻辑 获取arg1def get_arg1(arg):_0x4b082b [0xf, 0x23, 0x1d, 0x18, 0x21, 0x10, 0x1, 0x26, 0xa, 0x9, 0x13, 0x1f, 0x28, 0x1b, 0x16, 0x17, 0x19, 0xd,0x6, 0xb, 0x27, 0x12, 0x14, 0x8, 0xe, 0x15, 0x20, 0x1a, 0x2, 0x1e, 0x7, 0x4, 0x11, 0x5, 0x3…...

安全学习DAY13_WEB应用源码获取

信息打点-WEB应用-源码获取 文章目录 信息打点-WEB应用-源码获取小节概述-思维导图资产架构-源码获取&#xff08;后端&#xff09;后端-开源后端-闭源-源码泄露源码泄露原因源码泄露方式集合网站备份压缩包git&#xff0c;svn源码泄露DS_Store文件泄露composer.json 泄露资源搜…...

Selenium+Java环境搭建(测试系列6)

目录 前言&#xff1a; 1.浏览器 1.1下载Chrome浏览器 1.2查看Chrome浏览器版本 1.3下载Chrome浏览器的驱动 2.配置系统环境变量path 3.验证是否成功 4.出现的问题 结束语&#xff1a; 前言&#xff1a; 这节中小编给大家讲解一下有关于Selenium Java环境的搭建&…...

Shell编程学习-If条件语句

示例1&#xff1a;使用传参的方式实现两个整数的比较&#xff1a; #!/bin/bash # read -p "Please input second number: " num1 num2if [ $num1 -lt $num2 ]thenecho "$num1 is less than $num2."exit fiif [ $num1 -eq $num2 ]thenecho "$num1 is …...

Android getDrawable()和getColor()

Android getDrawable() 1.过时代码 虽然过时&#xff0c;但是不妨碍使用 context.getResources().getDrawable(R.drawable.xxx) 2.建议代码 context.getDrawable(R.drawable.xxx) 有API限制 3.最新代码 ContextCompat.getDrawable(getContext(), R.drawable.xxx); 有A…...

Android Calendar

1.字符串日期比较大小 public static boolean compareDate(String pre, String last) {SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd");try {Date lastDate sdf.parse(last);Calendar lastCal Calendar.getInstance();lastCal.setTime(lastDate);Date …...

C# PaddleDetection 目标检测 ( yolov3_darknet)

效果 项目 VS2022.net4.8OpenCvSharp4Sdcb.PaddleDetection 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using Sdcb.PaddleDetection; using Sdcb.PaddleInference; using System; using System.Drawing; using System.Windows.Forms; using YamlDotNet;namespa…...

matlab多线程,parfor循环进度,matlab互斥锁

一. 内容简介 matlab多线程&#xff0c;parfor循环进度&#xff0c;matlab互斥锁 二. 软件环境 2.1 matlab 2022b 2.2代码链接 https://gitee.com/JJW_1601897441/csdn 三.主要流程 3.1 matlab多线程 有好几种&#xff0c;最简单的&#xff0c;最好理解的就是parfor&am…...

建木使用进阶-创建密钥管理

阿丹&#xff1a; 第一次我们进入建木&#xff0c;第一件事情就是配置我们相关的密钥。 解读&#xff1a; 在建木中我们可以进行创建密钥来对我们服务器等密码进行方便的管理。 注意&#xff1a; 登录的时候账号为&#xff1a;admin 密码为&#xff1a;123456 这是初始…...

多模态第2篇:MMGCN代码配置

一、Windows环境 1.创建并激活虚拟环境 #创建虚拟环境命名为mmgcn&#xff0c;指定python版本为3.8 conda create -n mmgcn python3.8 #激活虚拟环境 conda activate mmgcn2.安装pytorch #torch2.0.0 cu118 pip install torch2.0.0cu118 torchvision0.15.1cu118 torchaudio…...

DHCP部署与安全详解

文章目录 一、DHCP是什么&#xff1f;二、DHCP相关概念三、DHCP优点四、DHCP原理1. 客户机发送DHCP Discovery广播包&#xff08;发现谁是DHCP服务器&#xff09;2. 服务器响应DHCP Offer广播包3. 客户机发送DHCP Request广播包4. 服务器发送DHCP ACK广播包 五、DHCP续约六、部…...

华为数通HCIP-PIM原理与配置

组播网络概念 组播网络由组播源&#xff0c;组播组成员与组播路由器组成。 组播源的主要作用是发送组播数据。 组播组成员的主要作用是接收组播数据&#xff0c;因此需要通过IGMP让组播网络感知组成员位置与加组信息。 组播路由器的主要作用是将数据从组播源发送到组播组成员。…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

云启出海,智联未来|阿里云网络「企业出海」系列客户沙龙上海站圆满落地

借阿里云中企出海大会的东风&#xff0c;以**「云启出海&#xff0c;智联未来&#xff5c;打造安全可靠的出海云网络引擎」为主题的阿里云企业出海客户沙龙云网络&安全专场于5.28日下午在上海顺利举办&#xff0c;现场吸引了来自携程、小红书、米哈游、哔哩哔哩、波克城市、…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...