最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - jsPDF PubSub Error – "No unicode cmap for font" - Stack Overflow

programmeradmin2浏览0评论

I'm trying to add a custom font to jsPDF. I converted my file to base64 and did the following:

doc.addFileToVFS("font/rajdhani-regular-webfont.woff", base64enc);

where base64enc is the base 64 encoded string

then I add the font as follows:

doc.addFont('font/rajdhani-regular-webfont.woff', 'rajdhani', 'normal');

doc.setFont('rajdhani');

however, I keep getting the following error

[Error] jsPDF PubSub Error – "No unicode cmap for font" – Error: No unicode cmap for font — jspdf.min.js:9068
Error: No unicode cmap for font — jspdf.min.js:9068registerTTF — jspdf.min.js:9068i — jspdf.min.js:9027:86open — jspdf.min.js:9032(anonymous function) — jspdf.min.js:6031publish — jspdf.min.js:308yt — jspdf.min.js:729:166addFont — jspdf.min.js:1286callme — freport.php:500onclick — freport.php:100
    publish (jspdf.min.js:29:5989)
    yt (jspdf.min.js:29:18435)
    addFont (jspdf.min.js:29:33701)
    callme (freport.php:500)
    onclick (freport.php:100)

I don't know why this is happening.

I'm trying to add a custom font to jsPDF. I converted my file to base64 and did the following:

doc.addFileToVFS("font/rajdhani-regular-webfont.woff", base64enc);

where base64enc is the base 64 encoded string

then I add the font as follows:

doc.addFont('font/rajdhani-regular-webfont.woff', 'rajdhani', 'normal');

doc.setFont('rajdhani');

however, I keep getting the following error

[Error] jsPDF PubSub Error – "No unicode cmap for font" – Error: No unicode cmap for font — jspdf.min.js:9068
Error: No unicode cmap for font — jspdf.min.js:9068registerTTF — jspdf.min.js:9068i — jspdf.min.js:9027:86open — jspdf.min.js:9032(anonymous function) — jspdf.min.js:6031publish — jspdf.min.js:308yt — jspdf.min.js:729:166addFont — jspdf.min.js:1286callme — freport.php:500onclick — freport.php:100
    publish (jspdf.min.js:29:5989)
    yt (jspdf.min.js:29:18435)
    addFont (jspdf.min.js:29:33701)
    callme (freport.php:500)
    onclick (freport.php:100)

I don't know why this is happening.

Share Improve this question edited Jul 31, 2020 at 15:44 Simon Bengtsson 8,1513 gold badges63 silver badges90 bronze badges asked Aug 26, 2019 at 15:46 user130996user130996 791 silver badge4 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 6

I've been struggling too but I finally found how to do it!

As mentioned here there is a font converter made by jsPDF Contributers which you can find on here.

First upload your font here and then type the name of your font. It will generate JS file which then you need to includ in your project. This can be your js folder if you wish.

And once its in your folder add this script tag to your index.html (or whichever html file you need the jsPDF for).

<script src="./fontName.js"></script>

Now that you have the font automatically added to the jsPDF Api for you with that file, you can go ahead and delete below two lines from your code.

doc.addFileToVFS("font/rajdhani-regular-webfont.woff", base64enc);
doc.addFont('font/rajdhani-regular-webfont.woff', 'rajdhani', 'normal');

Once you do that just check the file you downloaded from the converter and you should see at the very bottom, your font name on the second parameter of below code.

this.addFont('fontFile.woff', 'THIS IS FONT NAME' , '.......');

Copy that name. Lets say its "rajdhani" for this example. So you simply just put this before any text you create on the instance of jsPDF (doc).

doc.setFont('rajdhani');

You can simply test it with below

/* 
"p" for portrait page orientation
"pt" for points. default is mm
"a4" is page size 
*/
var doc = new jsPDF("p","pt","a4"); 
doc.setFont('rajdhani');
doc.text('This is a test', 20,20);
doc.save('filename.pdf');

Now you should see a pdf with 20px left 20px top margin ssaying "This is a test" with your font style.

Hope this helps :)

IMPORTANT ISSUE I HAD! WOFF and OTT are not supported (stick to ttf).. I wasted too much time on this, and this functionality should be standard. The fact they have a dodgy converter site rather than inbuilt functionality is mind-boggling (nor any mention of the file type restrictions, on their app a simple extension check), similar to @klues, but use file reader to simplify, here my angular function:

(NOTE: you may need to change to async await versions if you plan to create PDF straight away)

  this.loadFont('VIC-med', 'assets/Fonts/VIC-Medium.ttf');
  

  loadFont(fontName: string, filePath: string, weight: 'normal'| 'bold' | 'italic'| 'bolditalic' = 'normal') {
    this.http.get(filePath, { responseType: 'blob' })
      .subscribe({
        next: (blob: Blob) => {
          const fileName =  filePath.substring(filePath.lastIndexOf("/") + 1);
          const reader = new FileReader();
          reader.onloadend = () => {
            const file64 = (reader.result as string).split(',')[1];

            this.pdf.addFileToVFS(fileName, atob(file64));
            this.pdf.addFont(fileName, fontName, weight);
          };
          reader.readAsDataURL(blob);
        },
        error: (error) => {
          console.error('Error loading font:', error);
        }
      });
  }

and the same for just ES

loadFont(fontName: string, filePath: string, weight: 'normal'| 'bold' | 'italic'| 'bolditalic' = 'normal') {
    fetch(filePath)
      .then(response => response.blob())
      .then(blob => {
        const fileName = filePath.substring(filePath.lastIndexOf("/") + 1);
        const reader = new FileReader();
        reader.onloadend = () => {
          const file64 = (reader.result as string).split(',')[1];

          this.pdf.addFileToVFS(fileName, atob(file64));
          this.pdf.addFont(fileName, fontName, weight);
        };
        reader.readAsDataURL(blob);
      })
      .catch(error => {
        console.error('Error loading font:', error);
      });
}

Also for ES6 module users the steps are very similar.

if you are here looking for a solution on Ionic 4 angular typescript like I was, below is the solution that worked for me!

First you need to install the package via npm as below.

npm install jspdf@latest --save

After that as mentioned in my previous reply there is a font converter made by jsPDF Contributers which you can find on here. Use this to upload your font file and include it in your project somewhere easy to reference inside your TS file so it could be in the same folder as the ts file for example.

-fontname-style.js // <<--- Here (This is the file you downloaded from converter)
-custom.page.module.ts
-custom.page.html
-custom.page.scss
-custom.page.spec.ts
-custom.page.ts

Now in your custom.page.ts import the following;

import * as jsPDF from 'jspdf';
import './fontname-style.js';

//OPTIONAL (Only import if you want to use autotable)
import 'jspdf-autotable';
import { autoTable as AutoTable } from 'jspdf-autotable';

Once you do that just check the file you downloaded from the converter and you should see at the very bottom, your font name on the second parameter of below code.

this.addFont('fontFile.ttf', 'fontName' , '.......');

Now you can create a function like this inside the custom.page.ts;

//custom.ponent.ts or custom.page.ts etc.
exportPDF(){
  var doc = new jsPDF("p","pt","a4"); // You can set your own  paramaters
  doc.setFont('fontName');
  doc.text('This is a test', 20,20); // You can set your own margins
  return doc.save('filename.pdf');
}

Now you should see a pdf with 20px left 20px top margin ssaying "This is a test" with your font style :)

OPTIONAL PLUGIN - AutoTable for jsPDF

If you want to use autotable plugin for jsPDF, install the following package from npm.

npm install jspdf-autotable@latest --save

Once installed add this two imports to your custom.page.ts.

import 'jspdf-autotable';
import { autoTable as AutoTable } from 'jspdf-autotable';

You can create a data of columns and headers if you like

and inside the exportPDF() function we created before add those lines;

//custom.ponent.ts or custom.page.ts etc.
exportPDF(){
  var doc = new jsPDF("p","pt","a4");
  doc.setFont('fontName');
  doc.text('This is a test', 20,20); // <-- Remove this line
  ((doc as any).autoTable as AutoTable)({
    head: [['Name', 'Email', 'Country']], // <-- Table headers
    body: [                               // <-- Table body
            ['David', '[email protected]', 'Sweden'],
            ['Castille', '[email protected]', 'Norway'],
            // ...
          ],
    styles: { font: "fontName" } /* <-- This is for the font to work in your 
  table */
  });

  return doc.save('filename.pdf');
}

Now you should get a pdf with the table inside it using your font :)

I hope this helps to someone.

I also got Error: No unicode cmap for font when trying to add a new font in binary form without their converter like mentioned in the docs. I think the crucial line in their example is this:

const myFont = ... // load the *.ttf font file as binary string

where for me it was unclear what they mean with binary string. However looking at their converter makes it clear that binary string should be a base64 encoded string.

So for me fetching a font from remote and adding it works with this:

/**
 * load a font from remote and add it to jsPDF doc
 * @param path the path of the font, e.g. '/app/fonts/My-Font.ttf'
 * @param doc the jsPDF doc instance to install the font to
 * @return {Promise<void>}
 */
async function loadFont(path, doc) {
    let response = await fetch(path).catch((e) => console.error(e));
    if (!response) {
        return;
    }
    let fontName = path.substring(path.lastIndexOf("/") + 1);
    console.log("using font", fontName);
    let contentBuffer = await response.arrayBuffer();
    let contentString = util.arrayBufferToBase64(contentBuffer)
    if (contentString) {
        doc.addFileToVFS(fontName, contentString);
        doc.addFont(fontName, fontName, "normal");
        doc.setFont(fontName);
    }
}

For util.arrayBufferToBase64 I'm using the function from this Stackoverflow answer.

  • I used https://cloudconvert./ to convert the Woff file to Ttf.

  • Than I used the converter from the docs as stated: https://rawgit./MrRio/jsPDF/master/fontconverter/fontconverter.html

Example code:

export const exportPdf = (cols: ColumnMeta[], data: unknown[], fileName: string) => {
  const exportColumns = cols.map((col) => ({ title: col.header, dataKey: col.field }));

  import('jspdf').then((jsPDF) => {
    import('jspdf-autotable').then(() => {
      import('./seventy-two-normal.js').then(() => {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const doc = new (jsPDF as any).default('p', 'pt');
        doc.setFont('seventy-two', 'normal');
        doc.autoTable({
          columns: exportColumns,
          body: data,
          styles: { font: 'seventy-two', fontStyle: 'normal' },
        } as UserOptions);
        doc.save(fileName);
      });
    });
  });
};
发布评论

评论列表(0)

  1. 暂无评论