內卷時代下的前端技術-使用JavaScript在瀏覽器中生成PDF檔案

2022-09-08 18:01:47

背景

在計量領域中,計量檢定是一種重要形式,主要用於評定計量器具的計量效能,確定其量值是否準確一致,實現手段包括計量檢驗、出具檢定證書和加封蓋印等。
在檢定證書這一環節,存在一個難點,就是無法線上預覽以及智慧生成。

1、證書管理不能滿足使用者精準列印、特殊字元或多頁列印的需求。因為在計量行業中,精密儀器較多,往往會存在一些特殊字元的應用或者會使用某些較為複雜的測量單位。
2、系統不支援批次證書更新以及批次列印等功能,在常見的場景中,出具證書是需要進行批次匯出的過程。
3、無法滿足實時預覽列印或者PDF預覽,這樣直至列印前都無法確定列印的格式、範圍等是否符合需求。
在這篇分享中,我們將幫助大家著重解決兩個問題:

1、在瀏覽器中生成PDF檔案;
2、解決中文以及特殊字元匯出PDF亂碼的問題。

在瀏覽器中生成PDF檔案。前端生成PDF檔案純依賴於使用者端的瀏覽器資源,對於不同的終端,匯出PDF的難度會比伺服器端有所增加。市面上主流的瀏覽器有三四家,例如Chrome、Safari、FireFox等,每個瀏覽器對於文字內容、CSS屬性處理都不一致,有可能某些設定在某個瀏覽器上可行,換了一個瀏覽器之後就有可能天差地別。另外,對於原生的PDF檔案來說,僅包含英文字型,不包含任何中文字型,因此當匯出的內容中含有中文字型編碼時,就會顯示亂碼,所以通常情況下,我們都需要為PDF進行字型註冊操作。

前端常見匯出PDF方法

目前常用的前端生成PDF檔案的方法大致有以下幾種。
1、HTML2Canvas的方法將HTML 轉換成圖片後,在將圖轉PDF檔案。這種方法比較適合單一頁面。
2、jsPDF 直接H5轉成PDF。

除了上述的方案之後,使用SpreadJS直接線上設計佈局,並且可以直接生成PDF檔案。 帶來的好處是什麼呢?視覺化的操作、程式碼量少並且可以適配不同的瀏覽器環境。當然也會有一定的缺點,對於字型較多的檔案,需要註冊不同的字型,字型檔案越大,佔用的頻寬就越大。另外,當檔案比較大的時候,有可能會存在效能問題,不過這個也幾乎是前端匯出PDF檔案的一個瓶頸。那麼較為理想的方案便是可以在前端(SpreadJS)設計、展示,最後交由後端來單獨匯出或者批次匯出。

在瀏覽器中生成PDF檔案

介紹了那麼多,我們還是回到本篇文章的主題,如何通過前端來生成PDF檔案。需要用到SpreadJS以及匯出PDF相關的功能,首先需要在頁面上引入相關的資源。

然後建立一個用於承載表格範例的DOM。

初始化表格控制元件並載入已設計好的表單,或者也可以通過setValue的介面實現簡單的賦值操作。

想要表單按照指定的要求匯出,可以通過程式碼設定列印相關的設定,也可以用設計器來進行設計。下面是設定列印資訊相關的程式碼。

最後,通過呼叫savePDF方法,將工作簿物件轉為blob,我們可以通過window.open來進行pdf的預覽或者通過一些儲存檔案的外掛直接將這個blob儲存為PDF檔案。

這是open之後的效果,我們可以直接通過瀏覽器匯出PDF檔案或者是呼叫瀏覽器的列印介面實現列印。(demo在附件名為PDF資料夾)

解決中文以及特殊字元匯出PDF亂碼

正如前面所說的,在國內,使用中文的報告是一件再常見不過的事,在計量檢測等相關場景,特殊字元的使用也較多。在沒註冊對應的字型之前,匯出的中文字型和特殊字型都顯示的是亂碼。因此,還需要處理匯出中文以及特殊字元PDF亂碼的問題。

前面提到了註冊字型,那我們的字型應該怎麼來?要什麼格式的字型呢?首先,先確認我們的表單需要用到哪些字型,然後去找對應字型的ttf檔案(電腦上或者是一些字型網站上都有,需注意版權問題)。找到之後將其轉為base64格式的檔案。具體如何轉,可以找一些線上的檔案轉換器,不過線上的有可能會因為字型檔案太大而崩潰,或者有能力的大佬可以自己寫一個轉換的工具。然後通過下面的方式去把我們的字型檔案儲存為一個js檔案放到我們的專案中。

初始化表單這些就和上面的操作基本一致了,下面就是關鍵的註冊字型步驟了。我們定義了一個font物件,裡面只定義了常規(normal)的字型,裡面的simkai.ttf就是我們上面的建立的字型檔案。

還有一點需要注意的是,雖然註冊了字型,但是要設定對應的中文字型。或者換過來說,你需要在表單上設定什麼字型,就去註冊對應的字型。
那我們再來看看特殊字元,註冊字型與中文字型的步驟是一致的,特殊在於為了想要在頁面上顯示特殊字元,我們需要通過css的font-face來指定一個font-family。例如建立了一個叫sunway-font的特殊字型,想要在頁面上顯示。

最後就是通過savePDF方法匯出PDF檔案,可以看到PDF的中文和特殊字元都可以正常顯示。

怎麼樣?學「廢」了嗎?不妨試試,「卷」起來。

本文所用程式碼下載地址:
https://gcdn.grapecity.com.cn/forum.php?mod=attachment&aid=MjI5OTEyfDdlNmI2YmExfDE2NjIwMjE0MTd8NjI2NzZ8OTk3MTg%3D

更多線上demo範例程式碼:https://demo.grapecity.com.cn/spreadjs/gc-sjs-samples/index.html