之前做过一个在线签名的功能,具体的需求是,用户可以在线签名,可以对签名进行编辑,最终再生成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,最后导出