JSPDF支持中文(思源黑體)采坑之旅,JSPDF中文字體亂碼解決方案


我拍個磚,通常標稱自己文章完美解決何種問題的,往往就是解決不了任何問題!

 

眾所周知,JSPDF是一個開源的,易用的,但是對中文支持非常差的PDF庫。

下面,我教大家,如何在pdf中使用思源黑體。思源黑體是開源字體。思源黑體具有很廣泛使用性,實用性,也是規避字體版權風險的重要選擇!請嚴格按照我說的做!

1、准備思源黑體的ttf文件,不要用otf文件,如下

https://github.com/be5invis/source-han-sans-ttf/releases

 

.

 

我們挑其中的SourceHanSans-Bold.ttfSourceHanSans-Normal.ttf來使用,代表一粗一細。

2、把下載的字體命名統統改為小寫,如下

 

 為什么改為小寫,見 issues2465 ,命名為大寫的統統失效~

 

 

 

在這個網站進行轉換https://rawgit.com/MrRio/jsPDF/master/fontconverter/fontconverter.html

注意,這個網站就算掛了,我們也可以在jspdf的源碼里找到轉換器 https://github.com/MrRio/jsPDF/blob/master/fontconverter/fontconverter.html

 3、於是,我們得到這2個文件

 

 PS:字體是bold字體,網站的fontStyle你就選bold,normal也是這樣!

 

用記事本(win)打開這2個文件,不要用編輯器,會異常卡,除非你內存高,mac愛什么打開什么打開,雙擊選中那串長的,ctrl+c。

 

你的項目新建font.js,內容如下

export function addfont(pdf) {

var font = 'AADSSDDT12......'     // ←就是很長那串

  pdf.addFileToVFS('bolds', font)

  return true;

}

使用方法:(我的項目是ant-design pro 4.0)

import { addfont } from '@/font/font'
//前面只是添加了字體,還要注冊字體,addfont第3個參數一定是normal,即使你add的字體是bold的,也要設置為normal
addfont(doc)
doc.addFont('bolds', 'b', 'normal')

//使用字體時,使用這句即可
doc.setFont('b');

 

坑:

1、autoTable需要使用默認字體,是一種叫做NotoSansCJKtc-Regular.ttf的字體,否則亂碼,或者你改源碼,使之兼容

 doc.addFont('NotoSansCJKtc-Regular.ttf', 'NotoSansCJKtc', 'normal');
 doc.setFont('NotoSansCJKtc');

 

2、因為字體文件太大,導致JS運行時內存溢出 JavaScript heap out of memory

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory

 

 

 

資料:https://stackoverflow.com/questions/38558989/node-js-heap-out-of-memory

解決辦法:https://lwjandmy.github.io/myblog/articles/+.+category+.+%E7%BC%96%E7%A8%8BJavaScript+.+title+.+node%20%E5%87%BA%E7%8E%B0heap%20out%20of%20memory%E9%97%AE%E9%A2%98+.+createtime+.+20181228%E4%B8%80190612+.+lastmodifiedtime+.+20181228%E4%B8%80190612+.+.html

 

 由於我用了umi,因此改umi.cmd,如下

@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\..\umi\bin\umi.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node --max-old-space-size=4096  "%~dp0\..\umi\bin\umi.js" %*
)

 

若你是用webpack,改webpack.cmd

 

3、最后不得不說句,我把字體放在前端項目,是因為我的項目要打包為electron的,若你的項目是發布到線上,最好做cdn或者考慮使用默認一種字體~!

由於字體文件實在太大,執行打包時必定觸發V8的內存限制,我使用umi打包時,8G內存直接爆了,--max-old-space-size=7000也不起作用,換成mac的16G內存一樣爆了,問題在哪?思維錯了!我們不能苛求webpack/umi能夠具有打包系統級文件的能力:如大型音視頻,字體包,壓縮文件,msi等,此時只有使用系統的文件管理能力來加持,因此,ele的原生能力就要發揮作用。

用到線程通信和node的文件讀取能力即可

https://electronjs.org/docs/api/ipc-main

// 在主進程中.
const { ipcMain } = require('electron')
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.reply('asynchronous-reply', 'pong')
})

ipcMain.on('synchronous-message', (event, arg) => {
  console.log(arg) // prints "ping"
  event.returnValue = 'pong'
})
//在渲染器進程 (網頁) 中。
const { ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong"

ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log(arg) // prints "pong"
})
ipcRenderer.send('asynchronous-message', 'ping')
 
        

所謂渲染器進程就是你的前端項目,下面說一下的處理方式

1 准備字體文件

 

 

2.由於不是項目主要部分,而是支持性部分,因此我就用了一個回調地獄   /滑稽

var fs = require("fs");
ipcMain.on('asynchronous-message', (event, arg) => {
  console.log('main', arg) // 請求的消息

  // 使用通信方式輸送字體給前端
  let filePath = path.join(__dirname, ".", "font/font.js");
  let filePath2 = path.join(__dirname, ".", "font/font2.js");
  let filePath3 = path.join(__dirname, ".", "font/font3.js");
  console.log(filePath, "filePath")

  fs.readFile(filePath, { encoding: "utf-8" }, function (err, fr) {
    //readFile回調函數
    // if (err) {
    //   console.log(err);
    // } 

    fs.readFile(filePath2, { encoding: "utf-8" }, function (err, fr2) {
      //readFile回調函數

      fs.readFile(filePath3, { encoding: "utf-8" }, function (err, fr3) {
        //readFile回調函數

        event.reply('asynchronous-reply', {
          addFont: fr,
          addFont2: fr2,
          addFont3: fr3,
        })
      })
    })
  })
})

 

前端調用

 

const { ipcRenderer } = require('electron') 

 ipcRenderer.send('asynchronous-message', 'ping')
 ipcRenderer.on('asynchronous-reply', (event, arg) => {
      // console.log('web', arg) // prints "pong"

      const {
        addFont,
        addFont2,
        addFont3
      } = arg

      this.setState({
        addFont,
        addFont2,
        addFont3
      })
})

 

使用字體

doc.addFileToVFS('bolds', this.state.addFont)
doc.addFileToVFS('normals', this.state.addFont2)

doc.addFont('bolds', 'b', 'normal')
doc.addFont('normals', 'n', 'normal')

...
doc.setFont('n');


...
doc.setFont('b');

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM