Chrome 103支援使用本地字型,純前端匯出PDF優化

2022-11-24 18:00:18

在前端匯出PDF,解決中文亂碼一直是一個頭疼的問題。要解決這個問題,需要將ttf等字型檔案內容註冊到頁面PDF生成器中。但是之前網頁是沒有許可權直接獲取客戶機器字型檔案,這時就需要從伺服器下載字型檔案或者提示使用者選擇字型檔案上傳到頁面。對於動輒數十兆(M)的中文字型檔案,網路不好時並不是一個好的解決方案。

Chrome 103

提高頁面效能的一種方法是對當前的使用資源經行提示。例如,預載入檔案或連線到不同的伺服器。

<link as="font" crossorigin="anonymous"
      href="..." rel="preload">
<link as="font" crossorigin="anonymous"
      href="..." rel="preload">
<link href="https://web-dev.imgix.net"
      rel="preconnect">

但是在伺服器傳送頁面內容之前,瀏覽器是無法對提示採取行動。

伺服器需要幾百毫秒才能生成一個請求頁面,在瀏覽器開始接收頁面內容之前,伺服器是不進行任何處理的。但是在這個等待的過程中,伺服器是需要一些固定子資源,例如 CSS 檔案、JavaScript 和影象內容,這個時候伺服器可以立即響應新的 HTTP 103 Early Hints 狀態程式碼,並詢問瀏覽器預載入那些子資源,以提供高座效率。

一旦伺服器生成了頁面,它就可以用正常的 HTTP 200 響應傳送它。當頁面進入時,瀏覽器已經開始載入所需的資源。作為一個新 HTTP 狀態程式碼,所以它需要更新我們伺服器。

本地字型存取

Web 上的字型一直是一個挑戰,尤其是允許使用者建立自己的圖形和設計的應用程式就是一個難點。現在應用程式只能使用網路字型,但無法獲得使用者在其計算機上安裝的字型列表;而且,無法存取完整的字型表資料,如果我們需要實現自己的自定義文字堆疊,就很複雜。

而在新版本中,這個問題得到了很好解決。Chrome 103版本中新的字型API可以讓web應用獲取到使用者在本地電腦上安裝的所有字型資訊,同時還可以獲取到字型內容。

呼叫window.queryLocalFonts(),會返回使用者安裝字型的陣列。

const pickedFonts = await self.queryLocalFonts();
for (const fontData of pickedFonts) {
  console.log(fontData.postscriptName);
  console.log(fontData.fullName);
  console.log(fontData.family);
  console.log(fontData.style);
}

處於安全性的考慮,獲取字型資訊需要獲取到使用者的授權。當第一呼叫queryLocalFonts時,Chrome會彈出許可權申請:

許可權同意後,就可以獲取所有安裝字型的資訊

使用navigator.permissions.query可以檢查許可權

async function requestPremission(){
  const { state } = await navigator.permissions.query({
    name: "local-fonts"
  });
  console.log(state)
  if (state === 'granted') {
    query();
  } else if (state === 'prompt') {
    alert("請授予許可權!")
    query();
  }
  else{
    alert("沒有許可權獲取字型")
  }
}

使用本地字型匯出PDF

接下來我們介紹如何使用本地字型進行PDF匯出。
選擇需要使用的字型內容,註冊到PDF生成工具中

使用blob 方法可以獲取字型檔案內容
let currentFont = fontList[fontListSelect.value];
const blob = await currentFont.blob();

使用字型名稱註冊

//將Blob 物件轉換成 ArrayBuffer
var reader = new FileReader();
reader.onload = function (e) {
  var fontrrayBuffer = reader.result;
  var fonts = GC.Spread.Sheets.PDF.PDFFontsManager.getFont(currentFont.family) || {};
  fonts[fontType] = fontrrayBuffer;
  GC.Spread.Sheets.PDF.PDFFontsManager.registerFont(currentFont.family, fonts);
}
reader.readAsArrayBuffer(blob);

接下來匯出含有本地字型的PDF:

這裡需要注意,使用本地字型風險也是不可避免的,如果使用者沒有安裝對應字型,在網頁中瀏覽器會使用其他字型進行渲染,倒是PDF依舊會有出現亂碼的風險。解決方法是需要從伺服器中下載目標字型或使用其他字型作為替代。

拓展閱讀

React + Springboot + Quartz,從0實現Excel報表自動化

電子試算表也能做購物車?簡單三步就能實現

使用純前端類Excel表格控制元件SpreadJS構建企業現金流量表