Resaving document with fontkit after adding text results in error
What were you trying to do?
I was trying to reuse already created PDFDocument by removing all pages and working with it as if it is new (the speedup, when it works, is around 30% in my case). The example would not contain removing and readding pages, because it has no effect on the error showing up as far as I tested.
How did you attempt to do it?
- Create the document;
- register fontkit;
- embed font;
- add pages, shapes, texts etc.
- save the document;
- add pages, shapes, texts etc.
- save the document.
What actually happened?
Saving the document the second time resulted in exception, the exact place and type of the error depended on the font being embedded in the document
The exceptions:
Cannot read properties of undefined (reading 'advanceWidth')
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'advanceWidth')
at CustomFontEmbedder.computeWidths (CustomFontEmbedder.js:230:40)
at CustomFontSubsetEmbedder.<anonymous> (CustomFontEmbedder.js:141:37)
at step (tslib.es6.js:100:23)
at Object.next (tslib.es6.js:81:53)
at fulfilled (tslib.es6.js:71:58)
CustomFontEmbedder.computeWidths @ CustomFontEmbedder.js:230
(anonymous) @ CustomFontEmbedder.js:141
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
fulfilled @ tslib.es6.js:71
await in fulfilled (async)
(anonymous) @ test3.html:22
Uncaught RangeError: Index out of range
Uncaught RangeError: Index out of range
at checkInt (fontkit.umd.js:1531:43)
at Uint8Array.writeUInt16BE (fontkit.umd.js:1596:21)
at TTFSubset._addGlyph (fontkit.umd.js:40914:17)
at TTFSubset.encode (fontkit.umd.js:40952:13)
at fontkit.umd.js:40692:14
at Item.run (fontkit.umd.js:2632:13)
at drainQueue (fontkit.umd.js:2597:35)
checkInt @ fontkit.umd.js:1531
writeUInt16BE @ fontkit.umd.js:1596
_addGlyph @ fontkit.umd.js:40914
encode @ fontkit.umd.js:40952
(anonymous) @ fontkit.umd.js:40692
Item.run @ fontkit.umd.js:2632
drainQueue @ fontkit.umd.js:2597
setTimeout (async)
runTimeout @ fontkit.umd.js:2509
nextTick @ fontkit.umd.js:2622
encodeStream @ fontkit.umd.js:40691
(anonymous) @ CustomFontSubsetEmbedder.js:57
CustomFontSubsetEmbedder.serializeFont @ CustomFontSubsetEmbedder.js:54
(anonymous) @ CustomFontEmbedder.js:195
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
CustomFontEmbedder.embedFontStream @ CustomFontEmbedder.js:189
(anonymous) @ CustomFontEmbedder.js:154
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
CustomFontEmbedder.embedFontDescriptor @ CustomFontEmbedder.js:149
(anonymous) @ CustomFontEmbedder.js:127
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
CustomFontEmbedder.embedCIDFontDict @ CustomFontEmbedder.js:123
(anonymous) @ CustomFontEmbedder.js:95
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
CustomFontEmbedder.embedFontDict @ CustomFontEmbedder.js:91
CustomFontEmbedder.embedIntoContext @ CustomFontEmbedder.js:88
(anonymous) @ PDFFont.js:113
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
PDFFont.embed @ PDFFont.js:108
(anonymous) @ PDFDocument.js:1321
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
PDFDocument.embedAll @ PDFDocument.js:1312
(anonymous) @ PDFDocument.js:1203
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
PDFDocument.flush @ PDFDocument.js:1200
(anonymous) @ PDFDocument.js:1258
step @ tslib.es6.js:100
(anonymous) @ tslib.es6.js:81
(anonymous) @ tslib.es6.js:74
__awaiter @ tslib.es6.js:70
PDFDocument.save @ PDFDocument.js:1241
(anonymous) @ test3.html:18
await in (anonymous) (async)
(anonymous) @ test3.html:22
(filename is test3.html, previous two are also bugs)
What did you expect to happen?
Save the document without receiving exceptions, since I haven't found any signs that I cannot save the document multiple times.
How can we reproduce the issue?
<html><head>
<script src="https://unpkg.com/[email protected]/dist/pdf-lib.js"></script>
<script src="https://unpkg.com/@pdf-lib/[email protected]/dist/fontkit.umd.js"></script>
<script>
(async() => {
const link = 'https://fonts.cdnfonts.com/s/29105/ARIAL.woff' //Cannot read properties of undefined (reading 'advanceWidth')
//const link = 'https://fonts.gstatic.com/s/roboto/v30/KFOkCnqEu92Fr1MmgVxMIzIFKw.woff2' //index out of range
const fontBytes = await fetch(link).then(res => res.arrayBuffer());
const pdfDoc = await PDFLib.PDFDocument.create();
pdfDoc.registerFontkit(window.fontkit);
const font = await pdfDoc.embedFont(fontBytes, { subset: true });
const c1 = String.fromCodePoint(1072) //cyrrilic 'а'
const c2 = String.fromCodePoint(1073) //cyrrilic 'б'
const page = pdfDoc.addPage([1,1]);
page.drawText(c1, { font });
await pdfDoc.save();
page.drawText(c2, { font });
await pdfDoc.save();
console.log('done')
})()
</script>
</head></html>
Version
pdf-lib: 1.17.1, fontkit: 1.1.1
What environment are you running pdf-lib in?
Browser
Checklist
- [X] My report includes a Short, Self Contained, Correct (Compilable) Example.
- [X] I have attached all PDFs, images, and other files needed to run my SSCCE.
Additional Notes
Browser: Chrome 114 OS: ChromeOS 114
Hi. I've got the similar error but in different scenario.
How did you attempt to do it?
- Load PDF document from a file
- Register new font
- Embed the font
- Copy the first page
- Fill in with text and image
- Add the page to the same document
- Save the document
What actually happened?
Same error reported
``` /node_modules/pdf-lib/src/core/embedders/CustomFontEmbedder.ts:231 currSection.push(currGlyph.advanceWidth * this.scale); ^ TypeError: Cannot read properties of undefined (reading 'advanceWidth') at CustomFontSubsetEmbedder.CustomFontEmbedder.computeWidths (/node_modules/pdf-lib/src/core/embedders/CustomFontEmbedder.ts:231:34) at CustomFontSubsetEmbedder.Version
pdf-lib: 1.17.1 fontkit: 1.1.1
What environment are you running pdf-lib in?
node 18.13.0
What I found
My error was caused by this line:
const [page] = await doc.copyPages(doc, [0]);
// Fill in texts and images
doc.addPage(page);
Which I attempted to duplicate the first page to the new page, fill text and image, then add the page back to the same doc.
I resolved this by
Instead of copying to the same doc, I create a new doc and copy the page to the new doc instead. Something similar to this:
const targetedDoc = await PDFDocument.create();
const [page] = await targetedDoc.copyPages(doc, [0]);
// Fill in texts and images
targetedDoc.addPage(page);
Additional info
I'll try to explain a bit into the behavior of the error.
- Errors are constantly thrown at the same data entries but I cannot detect anything wrong with the data (yet).
- Filling in 12,000 pages, with the same data entries - it always fails at the same pages, for example, 6,493rd and 10,489th.
- With the same data, if I cut the pages to 6,000 - 7,000th. The code still fails at page 6,493rd. (or 493rd page at this round)
- I use the same approach previously in other project (copying to the same doc), but it was working fine.
Hope this info might be useful for this bug.