jsPDF中的自定义字体?

33

在 jsPDF 中是否可以包含自定义字体?

使用基本库,如果我控制台输出 'doc.getFontList()',我会得到:

Courier, Helvetica, Times, courier, helvetica, times

但是,假如我想使用 'Comic Sans'(虽然我不会这么做),这可以实现吗?

更好的是,我能否使用一个本地存储的并在网站上使用 @font-face 声明的字体?


你可以在这里尝试使用提供的详细问题和答案。 - Flippowitsch
9个回答

29

我发现这可以通过修改jsPDF.js来公开现有的addFont方法实现。

jsPDF.js中,查找:

//---------------------------------------
// Public API

添加以下内容:

    API.addFont = function(postScriptName, fontName, fontStyle) {
      addFont(postScriptName, fontName, fontStyle, 'StandardEncoding');
    };

为了更加清晰,我把这个方法放到了其他字体方法的附近 - API.setFont, API.setFontSize, API.setFontType等。

现在在你的代码中,使用:

doc.addFont('ComicSansMS', 'Comic Sans', 'normal');
doc.setFont('Comic Sans');
doc.text(50,50,'Hello World');

这对我来说有效,使用@font-face字体在加载jsPDF之前包含在CSS中,以及系统字体。可能有更好的方法使用jsPDF的插件框架来做到这一点,但是这个快速而粗糙的解决方案至少应该让您开始。

请注意,doc.getFontList()不会显示添加的字体:

// TODO: iterate over fonts array or return copy of fontmap instead in case more are ever added.

7
谢谢您发布这个。 我使用了您的工作并提交了一个PR(https://github.com/MrRio/jsPDF/pull/475),它刚刚被合并到了jsPDF的主分支中。 这是链接:https://github.com/MrRio/jsPDF/blob/master/jspdf.js#L1595。 再次感谢! - Chip Castle
3
对于我来说,这个在Google Fonts上无法使用。没有添加任何内容,也没有显示错误。 - Eduárd Moldován
2
请注意,PDF 文件本身不包含字体,而是从浏览器字体库中读取。如果您尝试保存 PDF 文件,则使用自定义字体的部分将不可见。 - Integrating Stuff
1
jsPDF不能。然而,pdfmake - 另一个处理pdf的Javascript库 - 可以。 - Integrating Stuff
6
不起作用。请给出完整的示例以添加字体。 - Hardeep Singh
显示剩余2条评论

26

借助最新版本的jsPDF (1.5.3),这似乎变得更加容易:

如果你在文件夹jsPDF-master> fontconverter中查看,会发现一个名为fontconverter.html的文件。在浏览器中打开该文件,并使用“浏览...”按钮浏览并选择你的.ttf字体文件。

点击“Create”按钮。

enter image description here

页面将提供“下载”操作以保存一个.js文件,类似于RopaSans-Regular-normal.js。需要将其包含在生成PDF的页面中。个人建议放置在页面头部(请注意


3
兄弟,我该如何将这个应用到我的 Angular 7 项目中?我试过将脚本放在 angular.json 文件中的 scripts 部分,但它没有被执行。然后我试图将其放在 index.html 的头部部分,但还是不起作用。你能否建议另一种方式? - Celso Marigo Jr
这太有帮助了,省去了加载TTF文件和浏览器卡顿的麻烦。谢谢! - Priyanka

7

这是我正在使用的解决方案...

首先,正如其他人所提到的 - 你需要这两个库:

  1. jsPDF: https://github.com/MrRio/jsPDF
  2. jsPDF-CustomFonts-support: https://github.com/sphilee/jsPDF-CustomFonts-support

接下来 - 第二个库要求你至少提供一个名为default_vfs.js的自定义字体文件。我正在使用两种自定义字体 - Arimo-Regular.ttf 和 Arimo-Bold.ttf - 都来自Google Fonts。因此,我的default_vfs.js文件看起来像这样:

(

(function (jsPDFAPI) { 
    "use strict";
    jsPDFAPI.addFileToVFS('Arimo-Regular.ttf','[Base64-encoded string of your font]');
    jsPDFAPI.addFileToVFS('Arimo-Bold.ttf','[Base64-encoded string of your font]');
})(jsPDF.API);

显然,您的版本会因使用的字体而不同。
有很多方法可以获得字体的Base64编码字符串,但我使用了这个:https://www.giftofspeed.com/base64-encoder/
它允许您上传一个.ttf文件,并为您提供一个Base64字符串,您可以将其粘贴到default_vfs.js中。
您可以在此处查看我的字体实际文件:https://cdn.rawgit.com/stuehler/jsPDF-CustomFonts-support/master/dist/default_vfs.js 因此,一旦您的字体存储在该文件中,您的HTML应该如下所示:
    <script src="js/jspdf.min.js"></script>
    <script src="js/jspdf.customfonts.min.js"></script>
    <script src="js/default_vfs.js"></script>

最终,你的JavaScript代码看起来应该像这样:
const doc = new jsPDF({
      unit: 'pt',
      orientation: 'p',
      lineHeight: 1.2
    });

doc.addFont("Arimo-Regular.ttf", "Arimo", "normal");
doc.addFont("Arimo-Bold.ttf", "Arimo", "bold");

doc.setFont("Arimo");
doc.setFontType("normal");
doc.setFontSize(28);

doc.text("Hello, World!", 100, 100);

doc.setFontType("bold");

doc.text("Hello, BOLD World!", 100, 150);

doc.save("customFonts.pdf");

这可能对大多数人来说很明显,但在addFont()方法中,三个参数分别是:
  1. 您在default_vfs.js文件中的addFileToVFS()函数中使用的字体名称
  2. 您在JavaScript中使用的setFont()函数中的字体名称
  3. 您在JavaScript中使用的setFontType()函数中的字体样式
您可以在此处查看其工作原理:https://codepen.io/stuehler/pen/pZMdKo 希望这对您和我一样有用。

5
在查看了fontconverter.html后,我发现它只是将TTF文件打包成JS文件中的base64字符串,因此在创建文档之前,我使用了以下方法。它基本上做的是fontconverter.html生成的单独文件所做的事情,只是按需执行:
async function loadFont(src, name, style, weight) {
    const fontBytes = await fetch(src).then(res => res.arrayBuffer());
    
    var filename = src.split('\\').pop().split('/').pop();
    var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(fontBytes)));

    var callAddFont = function () {
        this.addFileToVFS(filename, base64String);
        this.addFont(filename, name, style, weight );
        };
    jsPDF.API.events.push(['addFonts', callAddFont]);
}

这样调用:

await loadFont("/css/fonts/exo-2-v9-latin-ext_latin-italic.ttf", "Exo-2", "italic", 400);
await loadFont("/css/fonts/exo-2-v9-latin-ext_latin-regular.ttf", "Exo-2", "normal", 400);
await loadFont("/css/fonts/exo-2-v9-latin-ext_latin-500.ttf", "Exo-2", "normal", 500);
await loadFont("/css/fonts/exo-2-v9-latin-ext_latin-500italic.ttf", "Exo-2", "italic", 500);

它从URL中加载字体,并将其添加到VFS和字体管理器中。 重要提示:字体名称不能包含空格。您不会收到任何警告,但生成的PDF文件要么无法打开,要么文本看起来很奇怪。

1
这实际上是我正在寻找的答案。我认为很多文件夹的答案已经过时或者只是依赖于过多的第三方工具来回答问题。 - Sebastian Schürmann
对我来说也是类似的情况,看完所有答案后,我想出了上面的代码,以便按需加载字体。我真的不知道转换器的想法是什么,因为它实际上并没有转换任何东西,只是重新打包文件,同时使其更大。直接从TTF文件中按需加载没有任何理由不这样做。 - Alexander Gräf
1
我发现在(可能)最近的库版本中,你不需要通过事件系统来进行操作。现在可以直接使用调用。这应该更容易。 - Sebastian Schürmann
@SebastianSchürmann会检查。我想避免在我的开发Web服务器上可能出现的任何时间问题,但这可能会在生产环境中引起问题,因此我使用了事件系统。 - Alexander Gräf
批准上面的单词 - 只有这个解决方案目前有效。我尝试从setFontFace获取字体,但是通过CSS加载提取面没有任何结果。 - Allen Wahlberg

4
我正在使用Angular 8,Todd的回答对我有用。

一旦你从fontconverter.html获得了.js文件,你可以像这样在typescript中导入它:

import fontref = require('path/to/font/CustomFont-normal.js')

然后,您只需要“调用”fontref即可加载字体:

makePdf() {
    let doc = new jsPDF();

    fontref;                             // 'call' .js to load font

    doc.getFontList();                   // contains a key-value pair for CustomFont

    doc.setFont("CustomFont");           // set font
    doc.setFontType("normal");
    doc.setFontSize(28);
    doc.text("Hello", 20, 20);

    window.open(doc.output('bloburl'));  // open pdf in new tab
  }

1
请注意,您可能需要更改polyfills.ts以添加import * as jsPDF from "jspdf";(window as any).jsPDF = jsPDF;jsPDF到窗口。 - PeterS

2
一些答案已经过时,因此我将链接到Rio先生自己的自述文件,该文件是截至本帖发布的最新版本。以下是来自该自述文件的段落副本,后面附有自述文件本身的链接。希望这个额外的资源有所帮助:
引用: 使用UTF-8 / TTF: PDF中的14种标准字体仅限于ASCII代码页。如果您想使用UTF-8,则必须集成提供所需字形的自定义字体。jsPDF支持.ttf文件。因此,如果您想在pdf中使用例如中文文本,则您的字体必须具有所需的中文字形。因此,请检查您的字体是否支持所需的字形,否则它将显示为空格而不是文本。
要将字体添加到jsPDF中,请使用我们的字体转换器/fontconverter/fontconverter.html。字体转换器将创建一个js文件,其中包含所提供ttf文件的内容作为base64编码字符串以及jsPDF的其他代码。您只需将此生成的js文件添加到项目中即可。然后,您可以使用setFont方法在您的代码中编写您的UTF-8编码文本。

https://github.com/MrRio/jsPDF/blob/master/README.md#use-of-utf-8--ttf


1

//使用必要的配置,请参阅文档http://raw.githack.com/MrRio/jsPDF/master/docs/jsPDF.html

import MuliSemiB64 from "../functions/MuliSemiB64";
let doc = new jsPDF({ 
    orientation: "p",
    unit: "px",
    format: "a5",
  });
doc.addFileToVFS("MULI-SEMIBOLD.TTF", MuliSemiB64());

//MuliSemiB64()是一个函数,返回Muli ttf文件的base64字符串格式,将你的字体ttf文件转换并复制该字符串,保存到一个变量中,并使用该函数返回该字符串。使用像https://www.giftofspeed.com/base64-encoder/这样的网站进行转换。

doc.addFont("MULI-SEMIBOLD.TTF", "Muli-Semi-Bold", "Semi-Bold");
doc.setFont("Muli-Semi-Bold", "Semi-Bold");
doc.text("Have Fun :*", 35, 25);

0

工作示例

这是Dave Snydner answer的改进,通过添加支持波兰字母的工作示例。

示例在这里(我没有使用SO片段,因为它会导致CORS错误...)

主要部分是:

var callAddFont = function () {
  this.addFileToVFS('Lato-Regular-normal.ttf', font);
  this.addFont('Lato-Regular-normal.ttf', 'Lato-Regular', 'normal');
};
jsPDF.API.events.push(['addFonts', callAddFont])

好像你不需要添加这个方法,因为它已经合并到库中了。所以你可以直接使用Dave更新的答案。 - Damiani

0
到目前为止,我发现最简单的方法是使用jspdf-customfonts包。 只需通过以下命令安装该软件包: npm i jspdf-customfonts 然后在index.html的head标签中添加以下文件以进行默认配置。
script src="https://unpkg.com/jspdf@latest/dist/jspdf.min.js"></script> 
<script src="dist/jspdf.customfonts.min.js"></script> 
<script src="dist/default_vfs.js"></script> 

现在您可以下载任何字体的ttf文件。然后前往this网站,选择您的字体并复制代码,就完成了!

jsPDF-CustomFonts


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接