如何在@react-pdf/pdfkit中添加使用自定义字体并解决browser build报错
解决@react-pdf/pdfkit浏览器环境自定义字体报错问题
报错原因
fontkit.openSync unavailable for browser build报错的根本原因是:@react-pdf/pdfkit 的浏览器构建版本移除了 Node 环境专属的同步文件读取API,你直接传入本地文件路径字符串的注册方式只适用于 Node 服务端场景,浏览器环境无法直接读取本地文件系统路径,需要先将字体文件加载为二进制数据再注册。
解决步骤
1. 调整字体存储位置
将所有 .ttf 字体文件存放在项目的 public/fonts 目录下,保证浏览器可以通过公共路径直接请求到字体资源。
2. 新增字体预加载工具函数
// 加载字体为ArrayBuffer格式 const loadFontBuffer = async (fontFileName) => { const res = await fetch(`/fonts/${fontFileName}`); return await res.arrayBuffer(); };
3. 修正原有生成PDF的逻辑
修正两个核心问题:一是用Promise.all等待所有字体加载注册完成再渲染内容,二是注册字体时传入二进制数据而非路径。
import utils from "./utils"; const SVGtoPDF = require("svg-to-pdfkit"); const PDFDocument = require("@react-pdf/pdfkit").default; const { Base64Encode } = require("base64-stream"); const generatePDF = async (width, height, canvas, fonts) => { const canvasSvg = canvas.toSVG(); return await new Promise(async (resolve, reject) => { try { const doc = new PDFDocument({ bufferPages: true, size: [width * 0.75, height * 0.75], }); // 等待所有字体加载并注册完成 const fontConfigList = utils.getFont(fonts); await Promise.all(fontConfigList.map(async (font) => { // 提取字体文件名 const fontFileName = font.path.split("/").pop(); const fontBuffer = await loadFontBuffer(fontFileName); doc.registerFont(font.family, fontBuffer); })); // 注册完成后再调用字体渲染文本 doc.font("Pacifico").text("Hello Message"); let finalString = ""; const stream = doc.pipe(new Base64Encode()); SVGtoPDF(doc, canvasSvg, 0, 0); stream.on("data", (chunk) => (finalString += chunk)); stream.on("end", () => { resolve(finalString); }); doc.end(); } catch (err) { reject(err); } }); }; export default generatePDF;
可选优化方案
如果字体文件体积较小,可以提前将 .ttf 文件转为 Base64 字符串,直接将 Base64 传入 registerFont 即可,不需要额外的异步加载逻辑:
// Pacifico字体的Base64字符串,注意前面要加data:font/ttf;base64,前缀 const PACIFICO_FONT_BASE64 = "data:font/ttf;base64,xxxxxx......"; doc.registerFont("Pacifico", PACIFICO_FONT_BASE64);
内容的提问来源于stack exchange,提问作者Ajil Paul
相关产品推荐
相关产品推荐

