之前做过一个在线签名的功能,具体的需求是,用户可以在线签名,可以对签名进行编辑,最终再生成pdf的功能.
这次不聊在线签名,只谈html代码最后生成pdf导出
这个功能需要用到两个组件来配合,先把html转换成canvas,然后在使用jspdf对canvas进行转换并下载
组件名称:[html2canvas],[jspdf],代码在github上,gitee也有,搜索名字就可以查到:yylcha.smooth-signature
- 项目源码
打开SmoothSignature_CSharp版本即可,另外一个是vue版的
项目资源文件介绍
引用 html2canvas.js | jspdf.js 你copy过去也可以直接使用,这两个js是我们核心使用文件
js引用
HTML Code
<div>
<div class="singPanel" id="overtimeApp">
<table class="cssTb">
<tr>
<td>部门</td>
<td></td>
<td>姓名</td>
<td>XXX</td>
<td>职位</td>
<td>.net开发</td>
</tr>
<tr>
<td>加班事由</td>
<td colspan="5">测试</td>
</tr>
<tr>
<td>加班时间</td>
<td colspan="5">
<span>日期:__2099__年__12__月__31__日(□工作日 □双休日 □国定假日)</span>
<br />
<span>时间:从__08__点到__18__点</span><br />
<span>共计__8__小时</span>
</td>
</tr>
<tr>
<td>换算方式</td>
<td colspan="5"><span>□调休 □调休延期 □加班费</span></td>
</tr>
<tr>
<td>实际加班时数(由HR填写)</td>
<td colspan="3"></td>
<td>人力资源部签收</td>
<td></td>
</tr>
</table>
<div class="cssWorld">
<div style="float: left; width: 600px;margin-top:5px">
<div style="float: left">申请部门经理签字:</div>
<div class="dvCanvas">
<canvas style="border: 1px solid black"></canvas>
</div>
</div>
<div style="float: right; width: 200px">
2099年 12月 31日
</div>
<div hidden id="hdnSignature"></div>
</div>
</div>
<div class="cssBtn">
<button class="btn btn-primary btn-sm" type="button" id="btnClear">清空签名</button>
<button class="btn btn-primary btn-sm" type="button" id="btnUndo">撤销</button>
<button class="btn btn-primary btn-sm" type="button" id="btnGeneraCanvas">确定</button>
<button class="btn btn-primary btn-sm" type="button" id="btnHandleColor">修改字迹颜色</button>
<br />
<br />
<button class="btn btn-primary" type="button" id="btnDownLoad">生成PDF</button>
</div>
JavaScript Code
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery/dist/jquery.js"></script><script src="~/js/smooth-signature.min.js"></script>
<script src="~/js/smooth-signature.js">
</script><script src="~/js/html2canvas.js"></script><script src="~/js/jspdf.js"></script>
<script>
$(function () {
//获取定义画布
let canvas = document.querySelector("canvas");
//画布参数
let options = {
width: Math.min(window.innerWidth, 370),//宽度
height: 200,//高度
minWidth: 4,
maxWidth: 12,
// color: '#1890ff',
bgColor: "#f6f6f6",
};
//初始化smoothsignature画布
var signature = null;
if (canvas) {
signature = new SmoothSignature(canvas, options);
}
//生成pdf时间
$("#btnDownLoad").click(function () {
//需要打印的html
var html = document.getElementById("overtimeApp");
//使用html2canvas把html元素转换成canvas
//jsPDF 把canvas转换成pdf并导出
html2canvas(html).then(function (canvas) {
//获取html转成canvas的宽度和高度
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
// 创建PDF文档对象
var pdf = new jsPDF('p', 'pt', 'a4');
//通过canvas的宽高计算pdf页面的大小,自适应pdf
var scaleFactor = pdf.internal.pageSize.width / canvasWidth;
var scaleHeight = canvasHeight * scaleFactor;
// 将canvas转化为图片并添加至PDF文档
pdf.addImage(canvas.toDataURL('image/png'), 'JPEG', 20, 30, pdf.internal.pageSize.width - 40, scaleHeight);
// 下载PDF文档
pdf.save('加班申请单.pdf');
});
});
//清除签名画布
$("#btnClear").click(function () {
if (signature) {
signature.clear();
} else {
alert("画布初始化失败!");
}
});
//返回上一步
$("#btnUndo").click(function () {
if (signature) {
signature.undo();
} else {
alert("画布初始化失败!");
}
});
//把签名画布转换成image标签-未使用
$("#btnGeneraCanvas").click(function () {
if (signature) {
var pngUrl = signature.getPNG();
var blob = this.dataURLToBlob(pngUrl);
var url = window.URL.createObjectURL(blob);
$("#hdnSignature").attr(`<img src='${url}'></img>`)
} else {
alert("画布初始化失败!");
}
});
//更改笔线颜色
$("#btnHandleColor").click(function () {
if (signature) {
signature.color = "#" + Math.random().toString(16).slice(-6);
} else {
alert("画布初始化失败!");
}
});
})
//把image转换成blob
function dataURLToBlob(dataURL) {
// Code taken from https://github.com/ebidel/filer.js
const parts = dataURL.split(";base64,");
const contentType = parts[0].split(":")[1];
const raw = window.atob(parts[1]);
const rawLength = raw.length;
const uInt8Array = new Uint8Array(rawLength);
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], { type: contentType });
}
</script>
Css Code
<style>
.cssSign {
height: 200px;
width: 440px;
float: right;
}
.cssTb {
margin: auto;
width: 40%;
}
.cssWorld {
margin: auto;
width: 40%;
}
table,
td {
border: 1px solid black;
width: 500px;
}
.cssBtn {
margin-top: 300px;
text-align: center;
}
.singPanel {
width: 100%;
height: 400px;
}
</style>
问题整理
为什么不直接使用jspdf来实现html转换成pdf呢?
这个问题我试过,jspdf是支持把html直接导出成pdf的,但是会有一个问题,中文会出现乱码的
再加上原来的签名组件是一个canvas,所以我使用了这个办法,后续其他的项目应用我也都是这样处理的
它的工作原理是,帮你把html代码转换成canvas,然后jspdf把canvas转换成pdf,最后导出