摘要:本文章介紹如何在 Vue 中使用 pdf.js 及基于 pdf.js 的批注開發包 Elasticpdf。簡單 5 步可完成集成部署,包括數據的云端同步,示例代碼完善且簡單,文末有集成代碼分享。
1. 工具庫介紹與 Demo
1.1 代碼包結構
ElasticPDF基于開源 pdf.js (Demo地址:https://mozilla.github.io/pdf.js/web/viewer.html),增加了多種開箱即用的 PDF 批注功能。代碼包延續了 pdf.js-dist 獨立且完全離線的結構風格,僅增加了用于支持批注的離線 Javascript 代碼,與 pdf.js-dist 一樣可以快速完美集成到任何可以運行Javascript, HTML, CSS 的項目環境中,在公網及內網環境下運行。
1.2 Elasticpdf 在線 Demo
根據不同的功能及預算需求,有兩個版本的產品可供選擇,兩者僅在最終的批注保存階段有區別,產品 Demo 地址如下:
① 批注合成版: https://demos.libertynlp.com/#/pdfjs-annotation
② 專業批注版: https://www.elasticpdf.com/demo
2. 移動至 Vue 項目
移動 pdf.js 或 Elasticpdf 代碼包到 Vue 項目的 public 文件夾下。
pdf.js 成功導入 Vue 快照
3. 導入 viewer.html
① 通過 <iframe>
導入 elasticpdf 或 pdf.js 代碼包中的 viewer.html 文件,注意路徑不要寫錯。
<!-- elasticpdf 示例 -->
<iframe @load='initialPDFEditor()' id='elasticpdf-iframe' src="elasticpdf/web/viewer.html"frameborder="0" width="100%" height="700px"></iframe><!-- pdf.js 示例 -->
<iframe @load='initialPDFEditor()' id='elasticpdf-iframe' src="pdfjs-3.2/web/viewer.html"frameborder="0" width="100%" height="700px"></iframe>
② 將 web 文件夾下 viewer.js
中 defaultUrl
默認值置空,否則在第 ① 步中導入 viewer.html
時會默認加載 compressed.tracemonkey-pldi-09.pdf
文件,影響自定義加載文件的流程。Elasticpdf 代碼包中的 viewer.js 已默認修改完成。
// 原 defaultUrl 默認值
defaultOptions.defaultUrl = {value: "compressed.tracemonkey-pldi-09.pdf",kind: OptionKind.VIEWER
};// 置空后默認值
defaultOptions.defaultUrl = {value: "",kind: OptionKind.VIEWER
};
③ 在 Vue 頁面中的 <iframe>
onLoad() 函數下調用 initialApp() 函數,由于 pdf.js 和 elasticpdf 中的函數都是在 iframe 的作用域下,因此必須在 iframe load結束可獲取 contentWindow
后再調用。
var elasticpdf_viewer = null;
function initialPDFEditor() {listenPDFEditorMessage();elasticpdf_viewer = document.getElementById('elasticpdf-iframe').contentWindow;console.log('elasticpdf_viewer', elasticpdf_viewer);var pdf_url="compressed.tracemonkey-pldi-09.pdf";elasticpdf_viewer.initialApp({'language': 'zh-cn', // 交互語言'pdf_url': pdf_url,'member_info': { //用戶信息'id': 'elasticpdf_id','name': 'elasticpdf',},});
}// 監聽 pdf 編輯等各種信息的回調
function listenPDFEditorMessage() {window.addEventListener('message', (e) => {if (e.data.source !== 'elasticpdf') {return;}// pdf 加載結束的回調,可以在此處導入服務器上儲存的批注文件if (e.data.function_name === 'pdfLoaded') {console.log('PDF加載成功');reloadData();}});
}
④ pdf.js 初始化函數如下,主要內容為調用 PDFViewerApplication.open()
打開傳入的文檔鏈接,并使用 loadPdf()
函數監聽文檔是否初始化結束,最后通過 postMessage 廣播加載狀態至 Vue 頁面。
<script type='text/javascript'>//初始化函數function initialApp(paras) {var oriUrl=paras['pdf_url'];PDFViewerApplication.open(oriUrl);interval = setInterval('loadPdf()', 1000);}//監聽文檔是否初始化完成var interval = null;function loadPdf() {if (PDFViewerApplication.pdfDocument == null) {console.info('Loading...');} else {//文檔初始化完成console.log('PDF Load successfully');clearInterval(interval);//廣播信息postPDFData("pdfLoaded", '');}}//廣播 pdf.js 操作狀態信息function postPDFData(function_name,new_content){window.parent.postMessage({"type":0,"source":"elasticpdf",'function_name':function_name,"content":new_content},'*');window.postMessage({"type":0,"source":"elasticpdf",'function_name':function_name,"content":new_content},'*');}
</script>
⑤ 需要注意的是 pdf.js 端和存放 pdf 文件的都要支持跨域,否則會報 CORS 跨域錯誤。具體來說如果服務器是通過 Java 或者 Python 等程序提供文檔,則需要在程序中允許跨域;而如果是 nginx 服務器,則在配置中可以如下設置。
location / {add_header Access-Control-Allow-Origin *;add_header Access-Control-Allow-Headers *;add_header Access-Control-Expose-Headers Accept-Ranges,Content-Range;add_header Accept-Ranges bytes;
}
對于 pdf.js 端的跨域,需要在 elasticpdf 或 pdf.js 的 viewer.js
中搜索 HOSTED_VIEWER_ORIGINS
并加入域名。
const HOSTED_VIEWER_ORIGINS = ["null", "http://mozilla.github.io", "https://mozilla.github.io"];
4. 導出 pdf 及批注數據
Elasticpdf 所生成批注數據的保存有兩種方式,我們推薦方式二。pdf.js 默認將批注寫入文檔,無法分離保存。
4.1 方式一:批注寫入PDF
將批注寫入到 pdf 中然后下載整個文檔,一般用戶可以通過Ctrl+S
快捷鍵和 UI 按鈕來完成,這種方式完全不需要后端服務的支持。
在需要保存批注后 pdf 至服務器的場景中,可以通過如下代碼實現。
// 綁定該函數至 dom 用于觸發 pdf 保存
function getPDFData() {elasticpdf_viewer.getPDFData();
}// 接收pdf數據并且上傳至服務器
window.addEventListener('message', (e) => {if (e.data.source != 'elasticpdf') {return;}// 接收pdf數據if (e.data.function_name == 'downloadPDF') {let file_name = e.data.content['file_name'];let pdf_blob = e.data.content['pdf_blob'];let pdf_base64 = e.data.content['pdf_base64'];// 接收到 pdf 數據,其中 pdf_base64 字符串數據可以快捷上傳到服務器postService('upload-pdf-data', {'file_name':file_name,'file_id':'123ddasfsdffads','file_data':pdf_base64,});}
});
4.1 方式二:批注單獨保存
針對云端同步批注的需求,單獨將批注文件導出為JSON文件,傳輸并保存于服務器,之后加載回顯后可繼續編輯批注。
這樣的方式僅需一個在線PDF原文件,只傳輸很小體積的批注(通常不到 1M 大小),可以節約很多的存儲和寬帶費用。
// 在 pdf 批注編輯后的回調函數中可以讀取所有批注文件并且上傳至服務器
window.addEventListener('message', (e) => {if (e.data.source != 'elasticpdf') {return;}// pdf 批注編輯回調,可以在此處導出批注并傳輸到服務器if (e.data.function_name == 'annotationsModified') {// 僅獲取 pdf 批注文件,不寫入到 pdf 中let this_data = elasticpdf_viewer.pdfAnnotation.outputAnnotations();let annotation_content = JSON.stringify(this_data['file_annotation']);let file_name = this_data['file_name'];postService('upload-annotation-data', {'file_name':file_name,'file_id':'123ddasfsdffads','file_annotation':annotation_content,});}
});
5. 重載 pdf 及批注數據
單獨將 pdf 批注保存至服務器后,可以在加載 pdf 文件后再次從服務器中下載批注并且重載回顯到 pdf 上繼續編輯。
// 在 pdf 加載完成后的回調中可以從服務器請求相應的批注并重載于 pdf 上。
window.addEventListener('message', (e) => {if (e.data.source != 'elasticpdf') {return;}// pdf 加載完成的回調,可以在此處導入服務器上儲存的批注文件if (e.data.function_name == 'pdfLoaded') {let file_name = 'tutorial.pdf'let annotation_content =await postService('get-annotation-data', {'file_name':'tutorial.pdf','file_id':'123ddasfsdffads',});// 批注重載回顯于當前文件elasticpdf_viewer.setPureFileAnnotation({'file_annotation': annotation_content});}
});
以上的所有與服務器的交互需要前后端協同,后端服務器需要響應程序來接收和保存數據,對于 Elasticpdf 的用戶我們有簡單的 PHP、Python 及 Java 代碼示例供參考。
前端發起請求的示例函數 postService()
代碼如下。
// 與后端服務器進行網絡通信的函數
async function postService(url, data) {var new_data = new URLSearchParams();var encrpte_data = data;new_data.append('data', encrpte_data);var base_url = "your-server-url";var posturl = base_url + url;const response = await fetch(posturl, {method: 'POST',headers: {},body: new_data, });const resp = await response.json();resp['data'] = JSON.parse(resp['data']);return resp;
}
總結
至此,pdf.js 及 elasticpdf 集成于 Vue 項目的代碼完畢,帶有 pdf.js 代碼包的 Vue 示例項目包內容已上傳至 Github(網址:https://github.com/ElasticPDF/Vue-use-pdf.js-elasticpdf),可以直接下載。Elasticpdf 客戶如有其他應用場景需求歡迎聯系我們,我們將為您提供示例代碼。
溫馨提示:本文首發于?https://www.elasticpdf.com?,轉載請注明出處:https://www.elasticpdf.com/blog/vue-pdf-annotation-plugin-library-online-api-examples-zh.html