jsPDF添加自定义字体报No unicode cmap for font错误如何解决
问题原因
你遇到的No unicode cmap for font错误本质是字体文件在base64转码过程中被损坏,以及你对base64内容的处理逻辑有误,具体有两个核心问题:
- 用
XMLHttpRequest.responseText读取二进制字体文件时,默认会按UTF-8编码解析二进制内容,直接破坏了TTF文件的原始二进制结构,导致字体的unicode映射表(cmap)损坏无法识别。 - 你补全base64长度时是对整个DataURL(包含
data:font/ttf;base64,前缀)做补全,补全的=会污染有效编码,而且addFileToVFS要求传入的是纯base64编码,不需要DataURL前缀。
解决方案
- 修改XMLHttpRequest的响应类型,直接读取二进制Blob对象,避免编码损坏
- 提取DataURL中的纯base64内容后,再做长度补全
- 确认使用的TTF字体文件本身完整,没有被裁剪丢失cmap表
修正后的代码如下:
getBase64 = (file) => { return new Promise((resolve, reject) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { // 提取纯base64内容,去掉DataURL前缀 const base64 = (reader.result as string).split(',')[1]; resolve(base64); }; reader.onerror = error => reject(error); }); }; downLoadPDF(){ console.log("download pdf"); let x= 10,y=40, page = 1; var doc = new jsPDF("p", "mm", "a4"); doc.setFontSize(10); doc.text("Page "+page++ , 185, 6); var client = new XMLHttpRequest(); let inst = this; client.open('GET', 'assets/fonts/Roboto-Bold.ttf'); // 关键:设置响应类型为blob,直接读取二进制文件避免编码损坏 client.responseType = 'blob'; client.onloadend = async function() { const fileBlob = client.response; const base64Data = await inst.getBase64(fileBlob); // 对纯base64做长度补全 const padLength = 4 - (base64Data.length % 4); const fixedBase64 = padLength ? base64Data + '='.repeat(padLength) : base64Data; doc.addFileToVFS("Roboto-Bold.ttf", fixedBase64); doc.addFont("Roboto-Bold.ttf","Roboto-Bold","normal"); doc.setFont("Roboto-Bold","normal"); doc.text("Company Name: Avaya",x,y); y+=10; // 完成后保存PDF doc.save('output.pdf'); } client.send(); }
注意:如果修改后还是报错,请检查你项目里的
Roboto-Bold.ttf文件是否完整,可替换为官方原版字体文件重试,部分经过裁剪的子集字体可能会删除unicode cmap表导致无法被jsPDF识别。
内容的提问来源于stack exchange,提问作者amv
相关产品推荐
相关产品推荐

