各位开发者朋友们!上次给大家分享了 PDF 批注功能的实现思路,相信大家对项目有了更深入的理解。今天,咱们接着深挖 基于 Vue3 的在线 PDF 编辑 1.0 项目诞生记 中剩余的核心功能 —— 保存和下载,看看它们背后的技术细节。
基于 fabric-Canvas 的保存功能:便捷的数据生成
在这个项目里,保存功能借助 fabric-Canvas 变得简单高效。利用其内置方法,能轻松生成用于保存批注信息的 JSON 数据。代码如下:
const save = (fabricCanvasObj: any) => {
let fabricJsonObj: any = {};
for (let key in fabricCanvasObj) {
const jsonObj = fabricCanvasObj[key].toJSON();
if (jsonObj.objects.length > 0) {
fabricJsonObj[key] = jsonObj;
}
}
return fabricJsonObj;
};
这段代码遍历 fabricCanvasObj 中的每个画布实例,调用toJSON方法获取其包含批注信息的 JSON 数据。若画布上有批注(即jsonObj.objects.length > 0),就将该画布的 JSON 数据存入fabricJsonObj,最后返回这个包含所有有效批注信息的对象。
保存得数据:
基于 pdf-lib 的下载功能:融合 PDF 与批注的魔法
下载功能则由pdf-lib库来 “大显身手”。实现过程中,先把批注所在的canvas转化为图片格式,再借助pdf-lib的embedPng方法,将原始 PDF 和批注图片合并为一个新的 PDF 文件。具体代码如下:
const down = async (pdfUrl: string, fabricCanvasObj: any) => {
const response = await fetch(pdfUrl);
const pdfData = await response.arrayBuffer();
const pdfDoc = await PDFDocument.load(pdfData);
const pages = pdfDoc.getPages();
for (let key in fabricCanvasObj) {
const jsonObj = fabricCanvasObj[key].toJSON();
if (jsonObj.objects.length > 0) {
const dataURL = fabricCanvasObj[key].toDataURL({
format: 'png',
quality: 1
});
const currentPageIndex: number = parseInt(key.split("_")[1], 10);
const page = pages[currentPageIndex];
const annotImage = await pdfDoc.embedPng(dataURL);
const { width, height } = page.getSize();
page.drawImage(annotImage, {
x: 0,
y: 0,
width: width,
height: height,
opacity: 1,
});
}
}
const modifiedPdfBytes = await pdfDoc.save();
const blob = new Blob([modifiedPdfBytes], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
return url;
};
代码首先通过fetch获取原始 PDF 数据,用PDFDocument.load加载为 PDF 文档对象。接着遍历fabricCanvasObj,对于有批注的画布,将其转化为 PNG 格式的dataURL。根据画布 ID 解析出对应的 PDF 页面索引,获取该页面并使用embedPng嵌入批注图片,按照页面尺寸绘制。最后保存修改后的 PDF 文档,生成 Blob 对象并创建 URL 返回,完成带批注 PDF 的下载准备。
批注后下载得PDF
目前,1.0 版本的功能已全部为大家分享完毕。下周,我们将开启 2.0 版本的筹备工作,计划添加缩放、图片插入等实用功能。欢迎各位开发者前往 项目仓库或者 gitee仓库 获取源码研究,也希望大家在评论区畅所欲言,一起探讨功能优化方向,携手完善项目生态!