pdf-codec 1.4.2 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/README.md +56 -15
  2. package/dist/assets/caladea-bold.cjs +5 -0
  3. package/dist/assets/caladea-bold.d.cts +4 -0
  4. package/dist/assets/caladea-bold.d.ts +4 -0
  5. package/dist/assets/caladea-bold.js +4 -0
  6. package/dist/assets/caladea-bolditalic.cjs +5 -0
  7. package/dist/assets/caladea-bolditalic.d.cts +4 -0
  8. package/dist/assets/caladea-bolditalic.d.ts +4 -0
  9. package/dist/assets/caladea-bolditalic.js +4 -0
  10. package/dist/assets/caladea-italic.cjs +5 -0
  11. package/dist/assets/caladea-italic.d.cts +4 -0
  12. package/dist/assets/caladea-italic.d.ts +4 -0
  13. package/dist/assets/caladea-italic.js +4 -0
  14. package/dist/assets/caladea-regular.cjs +5 -0
  15. package/dist/assets/caladea-regular.d.cts +4 -0
  16. package/dist/assets/caladea-regular.d.ts +4 -0
  17. package/dist/assets/caladea-regular.js +4 -0
  18. package/dist/assets/carlito-bold.cjs +5 -0
  19. package/dist/assets/carlito-bold.d.cts +4 -0
  20. package/dist/assets/carlito-bold.d.ts +4 -0
  21. package/dist/assets/carlito-bold.js +4 -0
  22. package/dist/assets/carlito-bolditalic.cjs +5 -0
  23. package/dist/assets/carlito-bolditalic.d.cts +4 -0
  24. package/dist/assets/carlito-bolditalic.d.ts +4 -0
  25. package/dist/assets/carlito-bolditalic.js +4 -0
  26. package/dist/assets/carlito-italic.cjs +5 -0
  27. package/dist/assets/carlito-italic.d.cts +4 -0
  28. package/dist/assets/carlito-italic.d.ts +4 -0
  29. package/dist/assets/carlito-italic.js +4 -0
  30. package/dist/assets/carlito-regular.cjs +5 -0
  31. package/dist/assets/carlito-regular.d.cts +4 -0
  32. package/dist/assets/carlito-regular.d.ts +4 -0
  33. package/dist/assets/carlito-regular.js +4 -0
  34. package/dist/cff-probe.cjs +133 -0
  35. package/dist/cff-probe.d.cts +10 -0
  36. package/dist/cff-probe.d.ts +10 -0
  37. package/dist/cff-probe.js +132 -0
  38. package/dist/cmap-table.cjs +108 -0
  39. package/dist/cmap-table.d.cts +6 -0
  40. package/dist/cmap-table.d.ts +6 -0
  41. package/dist/cmap-table.js +107 -0
  42. package/dist/content-write.cjs +36 -17
  43. package/dist/content-write.d.cts +9 -2
  44. package/dist/content-write.d.ts +9 -2
  45. package/dist/content-write.js +35 -16
  46. package/dist/crypto/aes.cjs +166 -0
  47. package/dist/crypto/aes.d.cts +6 -0
  48. package/dist/crypto/aes.d.ts +6 -0
  49. package/dist/crypto/aes.js +163 -0
  50. package/dist/crypto/md5.cjs +215 -0
  51. package/dist/crypto/md5.d.cts +4 -0
  52. package/dist/crypto/md5.d.ts +4 -0
  53. package/dist/crypto/md5.js +214 -0
  54. package/dist/crypto/rc4.cjs +29 -0
  55. package/dist/crypto/rc4.d.cts +4 -0
  56. package/dist/crypto/rc4.d.ts +4 -0
  57. package/dist/crypto/rc4.js +28 -0
  58. package/dist/crypto/sha2.cjs +261 -0
  59. package/dist/crypto/sha2.d.cts +6 -0
  60. package/dist/crypto/sha2.d.ts +6 -0
  61. package/dist/crypto/sha2.js +258 -0
  62. package/dist/diagnostics.cjs +7 -0
  63. package/dist/diagnostics.d.cts +4 -1
  64. package/dist/diagnostics.d.ts +4 -1
  65. package/dist/diagnostics.js +7 -1
  66. package/dist/document.cjs +38 -2
  67. package/dist/document.js +38 -2
  68. package/dist/embedded-font-CLedn-mT.d.cts +42 -0
  69. package/dist/embedded-font-CbqkKgBl.d.ts +42 -0
  70. package/dist/embedded-font-write.cjs +92 -0
  71. package/dist/embedded-font-write.d.cts +22 -0
  72. package/dist/embedded-font-write.d.ts +22 -0
  73. package/dist/embedded-font-write.js +90 -0
  74. package/dist/embedded-font.cjs +142 -0
  75. package/dist/embedded-font.d.cts +2 -0
  76. package/dist/embedded-font.d.ts +2 -0
  77. package/dist/embedded-font.js +138 -0
  78. package/dist/encrypt.cjs +264 -0
  79. package/dist/encrypt.d.cts +11 -0
  80. package/dist/encrypt.d.ts +11 -0
  81. package/dist/encrypt.js +263 -0
  82. package/dist/filters.cjs +19 -1
  83. package/dist/filters.js +19 -1
  84. package/dist/font-registry-Cn7P9lAh.d.ts +38 -0
  85. package/dist/font-registry-yby02snZ.d.cts +38 -0
  86. package/dist/font-registry.cjs +152 -0
  87. package/dist/font-registry.d.cts +2 -0
  88. package/dist/font-registry.d.ts +2 -0
  89. package/dist/font-registry.js +150 -0
  90. package/dist/font-substitutes.cjs +13 -0
  91. package/dist/font-substitutes.d.cts +5 -0
  92. package/dist/font-substitutes.d.ts +5 -0
  93. package/dist/font-substitutes.js +12 -0
  94. package/dist/font-tables.cjs +127 -0
  95. package/dist/font-tables.d.cts +43 -0
  96. package/dist/font-tables.d.ts +43 -0
  97. package/dist/font-tables.js +122 -0
  98. package/dist/fonts.cjs +1 -0
  99. package/dist/fonts.d.cts +2 -1
  100. package/dist/fonts.d.ts +2 -1
  101. package/dist/fonts.js +1 -1
  102. package/dist/glyf.cjs +127 -0
  103. package/dist/glyf.d.cts +31 -0
  104. package/dist/glyf.d.ts +31 -0
  105. package/dist/glyf.js +125 -0
  106. package/dist/{math-hmtx.cjs → hmtx-table.cjs} +3 -3
  107. package/dist/{math-hmtx.d.ts → hmtx-table.d.cts} +2 -2
  108. package/dist/{math-hmtx.d.cts → hmtx-table.d.ts} +2 -2
  109. package/dist/{math-hmtx.js → hmtx-table.js} +3 -3
  110. package/dist/image/ccitt.cjs +488 -0
  111. package/dist/image/ccitt.d.cts +17 -0
  112. package/dist/image/ccitt.d.ts +17 -0
  113. package/dist/image/ccitt.js +487 -0
  114. package/dist/images-read.cjs +1 -4
  115. package/dist/images-read.js +2 -5
  116. package/dist/index.cjs +8 -0
  117. package/dist/index.d.cts +7 -4
  118. package/dist/index.d.ts +7 -4
  119. package/dist/index.js +5 -3
  120. package/dist/interpret.cjs +173 -38
  121. package/dist/interpret.d.cts +27 -10
  122. package/dist/interpret.d.ts +27 -10
  123. package/dist/interpret.js +174 -39
  124. package/dist/math-font-write.cjs +3 -32
  125. package/dist/math-font-write.js +2 -31
  126. package/dist/math-font.cjs +7 -5
  127. package/dist/math-font.js +5 -3
  128. package/dist/math-table.d.cts +1 -1
  129. package/dist/math-table.d.ts +1 -1
  130. package/dist/{matrix-B3c2_a2f.d.cts → matrix-BHzJESll.d.cts} +2 -1
  131. package/dist/{matrix-B3c2_a2f.d.ts → matrix-BHzJESll.d.ts} +2 -1
  132. package/dist/matrix.cjs +2 -0
  133. package/dist/matrix.d.cts +2 -2
  134. package/dist/matrix.d.ts +2 -2
  135. package/dist/matrix.js +2 -1
  136. package/dist/measure.cjs +65 -14
  137. package/dist/measure.d.cts +8 -1
  138. package/dist/measure.d.ts +8 -1
  139. package/dist/measure.js +64 -15
  140. package/dist/objects.cjs +4 -0
  141. package/dist/objects.d.cts +2 -1
  142. package/dist/objects.d.ts +2 -1
  143. package/dist/objects.js +4 -1
  144. package/dist/read.cjs +43 -4
  145. package/dist/read.d.cts +1 -1
  146. package/dist/read.d.ts +1 -1
  147. package/dist/read.js +43 -4
  148. package/dist/sfnt-V08bb5ut.d.cts +21 -0
  149. package/dist/sfnt-V08bb5ut.d.ts +21 -0
  150. package/dist/sfnt-subset.cjs +250 -0
  151. package/dist/sfnt-subset.d.cts +11 -0
  152. package/dist/sfnt-subset.d.ts +11 -0
  153. package/dist/sfnt-subset.js +249 -0
  154. package/dist/sfnt.cjs +50 -4
  155. package/dist/sfnt.d.cts +2 -17
  156. package/dist/sfnt.d.ts +2 -17
  157. package/dist/sfnt.js +47 -5
  158. package/dist/tounicode.cjs +34 -0
  159. package/dist/tounicode.d.cts +5 -0
  160. package/dist/tounicode.d.ts +5 -0
  161. package/dist/tounicode.js +33 -0
  162. package/dist/write.cjs +81 -11
  163. package/dist/write.d.cts +6 -0
  164. package/dist/write.d.ts +6 -0
  165. package/dist/write.js +82 -12
  166. package/package.json +1 -1
  167. package/dist/math-cmap.cjs +0 -81
  168. package/dist/math-cmap.d.cts +0 -6
  169. package/dist/math-cmap.d.ts +0 -6
  170. package/dist/math-cmap.js +0 -80
package/dist/write.cjs CHANGED
@@ -2,20 +2,24 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  const require_afm_widths = require("./afm-widths-BoeTOK2r.cjs");
3
3
  const require_util_base64 = require("./util/base64.cjs");
4
4
  const require_bytes_writer = require("./bytes/writer.cjs");
5
- const require_bytes_flate = require("./bytes/flate.cjs");
6
5
  const require_objects = require("./objects.cjs");
6
+ const require_bytes_flate = require("./bytes/flate.cjs");
7
7
  const require_util_abort = require("./util/abort.cjs");
8
- const require_fonts = require("./fonts.cjs");
9
8
  const require_image_jpeg_info = require("./image/jpeg-info.cjs");
10
9
  const require_image_png_decode = require("./image/png-decode.cjs");
10
+ const require_embedded_font = require("./embedded-font.cjs");
11
11
  const require_serialize = require("./serialize.cjs");
12
12
  const require_content_write = require("./content-write.cjs");
13
+ const require_embedded_font_write = require("./embedded-font-write.cjs");
14
+ const require_font_registry = require("./font-registry.cjs");
13
15
  const require_math_content_write = require("./math-content-write.cjs");
14
16
  const require_math_font = require("./math-font.cjs");
15
17
  const require_math_font_write = require("./math-font-write.cjs");
16
18
  const require_measure = require("./measure.cjs");
19
+ const require_sfnt_subset = require("./sfnt-subset.cjs");
17
20
  //#region src/write.ts
18
21
  const MATH_FONT_RESOURCE_NAME = "MF";
22
+ const EMBEDDED_FONT_RESOURCE_PREFIX = "E";
19
23
  const FIRST_CHAR = 32;
20
24
  const LAST_CHAR = 255;
21
25
  const NOMINAL_STEM_V_REGULAR = 80;
@@ -198,15 +202,27 @@ function xrefEntry(offset, generation, inUse) {
198
202
  }
199
203
  function writePdf(doc, options = {}) {
200
204
  const compress = options.compress ?? true;
201
- const measurer = require_measure.createStandardFontMeasurer();
205
+ const registry = options.fonts;
206
+ const measurer = require_measure.createFontMeasurer(registry);
202
207
  let nextObjNum = 1;
203
208
  const catalogNum = nextObjNum++;
204
209
  const pagesNum = nextObjNum++;
205
210
  const infoNum = nextObjNum++;
206
211
  const fontNames = /* @__PURE__ */ new Set();
207
212
  const imageIds = /* @__PURE__ */ new Set();
208
- for (const page of doc.pages) for (const item of page.items) if (item.kind === "text") fontNames.add(require_fonts.resolveStandardFont(item.font.family, item.font.weight === "bold", item.font.style === "italic").standardName);
209
- else if (item.kind === "image") imageIds.add(item.imageId);
213
+ const embeddedUses = /* @__PURE__ */ new Map();
214
+ for (const page of doc.pages) for (const item of page.items) if (item.kind === "text") {
215
+ const resolved = require_font_registry.resolveFaceWithRegistry(registry, item.font);
216
+ if (resolved.kind === "embedded") {
217
+ const use = embeddedUses.get(resolved.face) ?? {
218
+ texts: [],
219
+ codePoints: /* @__PURE__ */ new Set()
220
+ };
221
+ use.texts.push(item.text);
222
+ for (const character of item.text) use.codePoints.add(character.codePointAt(0));
223
+ embeddedUses.set(resolved.face, use);
224
+ } else fontNames.add(resolved.standardName);
225
+ } else if (item.kind === "image") imageIds.add(item.imageId);
210
226
  const fontAllocs = /* @__PURE__ */ new Map();
211
227
  for (const [index, name] of [...fontNames].sort().entries()) {
212
228
  const fontNum = nextObjNum++;
@@ -240,6 +256,18 @@ function writePdf(doc, options = {}) {
240
256
  toUnicodeNum: nextObjNum++,
241
257
  resourceName: MATH_FONT_RESOURCE_NAME
242
258
  };
259
+ const embeddedAllocs = /* @__PURE__ */ new Map();
260
+ const sortedEmbeddedUses = [...embeddedUses.entries()].sort(([a], [b]) => a.postScriptName < b.postScriptName ? -1 : a.postScriptName > b.postScriptName ? 1 : 0);
261
+ for (const [index, [face, use]] of sortedEmbeddedUses.entries()) embeddedAllocs.set(face, {
262
+ type0Num: nextObjNum++,
263
+ cidFontNum: nextObjNum++,
264
+ descriptorNum: nextObjNum++,
265
+ fontFileNum: nextObjNum++,
266
+ toUnicodeNum: nextObjNum++,
267
+ resourceName: `${EMBEDDED_FONT_RESOURCE_PREFIX}${index + 1}`,
268
+ texts: use.texts,
269
+ codePoints: use.codePoints
270
+ });
243
271
  const pageAllocs = doc.pages.map(() => ({
244
272
  pageNum: nextObjNum++,
245
273
  contentsNum: nextObjNum++
@@ -318,9 +346,40 @@ function writePdf(doc, options = {}) {
318
346
  value: built.toUnicode
319
347
  });
320
348
  }
349
+ for (const [face, alloc] of embeddedAllocs) {
350
+ const subset = require_sfnt_subset.subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b));
351
+ if (subset === void 0) throw new Error(`font "${face.postScriptName}" resolved to an embeddable face, but its glyph outlines could not be subsetted -- only TrueType-outline ('glyf') fonts can be embedded, so supply a TrueType face for this family or drop it from the registry`);
352
+ const built = require_embedded_font_write.buildEmbeddedFontObjects(face, subset, require_embedded_font.collectEmbeddedGlyphs(alloc.texts, face), {
353
+ cidFontRef: require_objects.pdfRef(alloc.cidFontNum, 0),
354
+ descriptorRef: require_objects.pdfRef(alloc.descriptorNum, 0),
355
+ fontFileRef: require_objects.pdfRef(alloc.fontFileNum, 0),
356
+ toUnicodeRef: require_objects.pdfRef(alloc.toUnicodeNum, 0)
357
+ }, compress);
358
+ objects.push({
359
+ num: alloc.type0Num,
360
+ value: built.type0
361
+ });
362
+ objects.push({
363
+ num: alloc.cidFontNum,
364
+ value: built.cidFont
365
+ });
366
+ objects.push({
367
+ num: alloc.descriptorNum,
368
+ value: built.descriptor
369
+ });
370
+ objects.push({
371
+ num: alloc.fontFileNum,
372
+ value: built.fontFile
373
+ });
374
+ objects.push({
375
+ num: alloc.toUnicodeNum,
376
+ value: built.toUnicode
377
+ });
378
+ }
321
379
  const resourceEntries = /* @__PURE__ */ new Map();
322
- if (fontAllocs.size > 0 || mathFontAlloc !== void 0) {
380
+ if (fontAllocs.size > 0 || embeddedAllocs.size > 0 || mathFontAlloc !== void 0) {
323
381
  const fontEntries = new Map([...fontAllocs.values()].map((alloc) => [alloc.resourceName, require_objects.pdfRef(alloc.fontNum, 0)]));
382
+ for (const alloc of embeddedAllocs.values()) fontEntries.set(alloc.resourceName, require_objects.pdfRef(alloc.type0Num, 0));
324
383
  if (mathFontAlloc !== void 0) fontEntries.set(mathFontAlloc.resourceName, require_objects.pdfRef(mathFontAlloc.type0Num, 0));
325
384
  resourceEntries.set("Font", require_objects.pdfDict(fontEntries));
326
385
  }
@@ -335,12 +394,22 @@ function writePdf(doc, options = {}) {
335
394
  const context = {
336
395
  measurer,
337
396
  resolveFont: (font) => {
338
- const standardName = require_fonts.resolveStandardFont(font.family, font.weight === "bold", font.style === "italic").standardName;
339
- const alloc = fontAllocs.get(standardName);
340
- if (alloc === void 0) throw new Error(`font "${standardName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
397
+ const resolved = require_font_registry.resolveFaceWithRegistry(registry, font);
398
+ if (resolved.kind === "embedded") {
399
+ const alloc = embeddedAllocs.get(resolved.face);
400
+ if (alloc === void 0) throw new Error(`embedded font "${resolved.face.postScriptName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
401
+ return {
402
+ kind: "embedded",
403
+ resourceName: alloc.resourceName,
404
+ face: resolved.face
405
+ };
406
+ }
407
+ const alloc = fontAllocs.get(resolved.standardName);
408
+ if (alloc === void 0) throw new Error(`font "${resolved.standardName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
341
409
  return {
410
+ kind: "standard",
342
411
  resourceName: alloc.resourceName,
343
- standardName
412
+ standardName: resolved.standardName
344
413
  };
345
414
  },
346
415
  resolveImage: (imageId) => {
@@ -352,8 +421,9 @@ function writePdf(doc, options = {}) {
352
421
  doc.pages.forEach((page, pageIndex) => {
353
422
  require_util_abort.throwIfAborted(options.signal);
354
423
  const { pageNum, contentsNum } = pageAllocs[pageIndex];
355
- const { bytes: contentBytes, substitutions } = require_content_write.writeContentStream(page.items, context);
424
+ const { bytes: contentBytes, substitutions, missingGlyphs } = require_content_write.writeContentStream(page.items, context);
356
425
  for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
426
+ for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
357
427
  const pageFormulas = formulasByPage.get(pageIndex);
358
428
  const formulaBytes = pageFormulas === void 0 || mathFontAlloc === void 0 || mathFont === void 0 ? void 0 : require_math_content_write.writeFormulaContentStream(pageFormulas, {
359
429
  font: mathFont,
package/dist/write.d.cts CHANGED
@@ -1,3 +1,5 @@
1
+ import { r as EmbeddedFaceSubstitution } from "./embedded-font-CLedn-mT.cjs";
2
+ import { t as FontRegistry } from "./font-registry-yby02snZ.cjs";
1
3
  import { WinAnsiSubstitution } from "./winansi.cjs";
2
4
  import { PositionedFormula } from "./formula.cjs";
3
5
  import { LayoutDocument } from "document-schema.js";
@@ -8,6 +10,10 @@ interface WritePdfOptions {
8
10
  readonly onSubstitution?: (substitution: WinAnsiSubstitution, context: {
9
11
  readonly pageIndex: number;
10
12
  }) => void;
13
+ readonly onMissingGlyph?: (missing: EmbeddedFaceSubstitution, context: {
14
+ readonly pageIndex: number;
15
+ }) => void;
16
+ readonly fonts?: FontRegistry;
11
17
  readonly formulas?: readonly PositionedFormula[];
12
18
  }
13
19
  declare const NOTES_ANNOTATION_AUTHOR = "documents.js:notes";
package/dist/write.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { r as EmbeddedFaceSubstitution } from "./embedded-font-CbqkKgBl.js";
2
+ import { t as FontRegistry } from "./font-registry-Cn7P9lAh.js";
1
3
  import { WinAnsiSubstitution } from "./winansi.js";
2
4
  import { PositionedFormula } from "./formula.js";
3
5
  import { LayoutDocument } from "document-schema.js";
@@ -8,6 +10,10 @@ interface WritePdfOptions {
8
10
  readonly onSubstitution?: (substitution: WinAnsiSubstitution, context: {
9
11
  readonly pageIndex: number;
10
12
  }) => void;
13
+ readonly onMissingGlyph?: (missing: EmbeddedFaceSubstitution, context: {
14
+ readonly pageIndex: number;
15
+ }) => void;
16
+ readonly fonts?: FontRegistry;
11
17
  readonly formulas?: readonly PositionedFormula[];
12
18
  }
13
19
  declare const NOTES_ANNOTATION_AUTHOR = "documents.js:notes";
package/dist/write.js CHANGED
@@ -1,20 +1,24 @@
1
1
  import { a as winAnsiGlyphName, n as widthOfCode, t as STANDARD_METRICS } from "./afm-widths-Dxucrg7D.js";
2
2
  import { base64ToBytes } from "./util/base64.js";
3
3
  import { ByteWriter, concatBytes } from "./bytes/writer.js";
4
- import { deflate } from "./bytes/flate.js";
5
4
  import { pdfArray, pdfDict, pdfHexString, pdfName, pdfNum, pdfRef, pdfStream } from "./objects.js";
5
+ import { deflate } from "./bytes/flate.js";
6
6
  import { throwIfAborted } from "./util/abort.js";
7
- import { resolveStandardFont } from "./fonts.js";
8
7
  import { readJpegInfo } from "./image/jpeg-info.js";
9
8
  import { decodePng } from "./image/png-decode.js";
9
+ import { collectEmbeddedGlyphs } from "./embedded-font.js";
10
10
  import { writeObject } from "./serialize.js";
11
11
  import { writeContentStream } from "./content-write.js";
12
+ import { buildEmbeddedFontObjects } from "./embedded-font-write.js";
13
+ import { resolveFaceWithRegistry } from "./font-registry.js";
12
14
  import { collectUsedGlyphs, writeFormulaContentStream } from "./math-content-write.js";
13
15
  import { loadMathFont } from "./math-font.js";
14
16
  import { buildMathFontObjects } from "./math-font-write.js";
15
- import { createStandardFontMeasurer } from "./measure.js";
17
+ import { createFontMeasurer } from "./measure.js";
18
+ import { subsetSfnt } from "./sfnt-subset.js";
16
19
  //#region src/write.ts
17
20
  const MATH_FONT_RESOURCE_NAME = "MF";
21
+ const EMBEDDED_FONT_RESOURCE_PREFIX = "E";
18
22
  const FIRST_CHAR = 32;
19
23
  const LAST_CHAR = 255;
20
24
  const NOMINAL_STEM_V_REGULAR = 80;
@@ -197,15 +201,27 @@ function xrefEntry(offset, generation, inUse) {
197
201
  }
198
202
  function writePdf(doc, options = {}) {
199
203
  const compress = options.compress ?? true;
200
- const measurer = createStandardFontMeasurer();
204
+ const registry = options.fonts;
205
+ const measurer = createFontMeasurer(registry);
201
206
  let nextObjNum = 1;
202
207
  const catalogNum = nextObjNum++;
203
208
  const pagesNum = nextObjNum++;
204
209
  const infoNum = nextObjNum++;
205
210
  const fontNames = /* @__PURE__ */ new Set();
206
211
  const imageIds = /* @__PURE__ */ new Set();
207
- for (const page of doc.pages) for (const item of page.items) if (item.kind === "text") fontNames.add(resolveStandardFont(item.font.family, item.font.weight === "bold", item.font.style === "italic").standardName);
208
- else if (item.kind === "image") imageIds.add(item.imageId);
212
+ const embeddedUses = /* @__PURE__ */ new Map();
213
+ for (const page of doc.pages) for (const item of page.items) if (item.kind === "text") {
214
+ const resolved = resolveFaceWithRegistry(registry, item.font);
215
+ if (resolved.kind === "embedded") {
216
+ const use = embeddedUses.get(resolved.face) ?? {
217
+ texts: [],
218
+ codePoints: /* @__PURE__ */ new Set()
219
+ };
220
+ use.texts.push(item.text);
221
+ for (const character of item.text) use.codePoints.add(character.codePointAt(0));
222
+ embeddedUses.set(resolved.face, use);
223
+ } else fontNames.add(resolved.standardName);
224
+ } else if (item.kind === "image") imageIds.add(item.imageId);
209
225
  const fontAllocs = /* @__PURE__ */ new Map();
210
226
  for (const [index, name] of [...fontNames].sort().entries()) {
211
227
  const fontNum = nextObjNum++;
@@ -239,6 +255,18 @@ function writePdf(doc, options = {}) {
239
255
  toUnicodeNum: nextObjNum++,
240
256
  resourceName: MATH_FONT_RESOURCE_NAME
241
257
  };
258
+ const embeddedAllocs = /* @__PURE__ */ new Map();
259
+ const sortedEmbeddedUses = [...embeddedUses.entries()].sort(([a], [b]) => a.postScriptName < b.postScriptName ? -1 : a.postScriptName > b.postScriptName ? 1 : 0);
260
+ for (const [index, [face, use]] of sortedEmbeddedUses.entries()) embeddedAllocs.set(face, {
261
+ type0Num: nextObjNum++,
262
+ cidFontNum: nextObjNum++,
263
+ descriptorNum: nextObjNum++,
264
+ fontFileNum: nextObjNum++,
265
+ toUnicodeNum: nextObjNum++,
266
+ resourceName: `${EMBEDDED_FONT_RESOURCE_PREFIX}${index + 1}`,
267
+ texts: use.texts,
268
+ codePoints: use.codePoints
269
+ });
242
270
  const pageAllocs = doc.pages.map(() => ({
243
271
  pageNum: nextObjNum++,
244
272
  contentsNum: nextObjNum++
@@ -317,9 +345,40 @@ function writePdf(doc, options = {}) {
317
345
  value: built.toUnicode
318
346
  });
319
347
  }
348
+ for (const [face, alloc] of embeddedAllocs) {
349
+ const subset = subsetSfnt(face.font, [...alloc.codePoints].sort((a, b) => a - b));
350
+ if (subset === void 0) throw new Error(`font "${face.postScriptName}" resolved to an embeddable face, but its glyph outlines could not be subsetted -- only TrueType-outline ('glyf') fonts can be embedded, so supply a TrueType face for this family or drop it from the registry`);
351
+ const built = buildEmbeddedFontObjects(face, subset, collectEmbeddedGlyphs(alloc.texts, face), {
352
+ cidFontRef: pdfRef(alloc.cidFontNum, 0),
353
+ descriptorRef: pdfRef(alloc.descriptorNum, 0),
354
+ fontFileRef: pdfRef(alloc.fontFileNum, 0),
355
+ toUnicodeRef: pdfRef(alloc.toUnicodeNum, 0)
356
+ }, compress);
357
+ objects.push({
358
+ num: alloc.type0Num,
359
+ value: built.type0
360
+ });
361
+ objects.push({
362
+ num: alloc.cidFontNum,
363
+ value: built.cidFont
364
+ });
365
+ objects.push({
366
+ num: alloc.descriptorNum,
367
+ value: built.descriptor
368
+ });
369
+ objects.push({
370
+ num: alloc.fontFileNum,
371
+ value: built.fontFile
372
+ });
373
+ objects.push({
374
+ num: alloc.toUnicodeNum,
375
+ value: built.toUnicode
376
+ });
377
+ }
320
378
  const resourceEntries = /* @__PURE__ */ new Map();
321
- if (fontAllocs.size > 0 || mathFontAlloc !== void 0) {
379
+ if (fontAllocs.size > 0 || embeddedAllocs.size > 0 || mathFontAlloc !== void 0) {
322
380
  const fontEntries = new Map([...fontAllocs.values()].map((alloc) => [alloc.resourceName, pdfRef(alloc.fontNum, 0)]));
381
+ for (const alloc of embeddedAllocs.values()) fontEntries.set(alloc.resourceName, pdfRef(alloc.type0Num, 0));
323
382
  if (mathFontAlloc !== void 0) fontEntries.set(mathFontAlloc.resourceName, pdfRef(mathFontAlloc.type0Num, 0));
324
383
  resourceEntries.set("Font", pdfDict(fontEntries));
325
384
  }
@@ -334,12 +393,22 @@ function writePdf(doc, options = {}) {
334
393
  const context = {
335
394
  measurer,
336
395
  resolveFont: (font) => {
337
- const standardName = resolveStandardFont(font.family, font.weight === "bold", font.style === "italic").standardName;
338
- const alloc = fontAllocs.get(standardName);
339
- if (alloc === void 0) throw new Error(`font "${standardName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
396
+ const resolved = resolveFaceWithRegistry(registry, font);
397
+ if (resolved.kind === "embedded") {
398
+ const alloc = embeddedAllocs.get(resolved.face);
399
+ if (alloc === void 0) throw new Error(`embedded font "${resolved.face.postScriptName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
400
+ return {
401
+ kind: "embedded",
402
+ resourceName: alloc.resourceName,
403
+ face: resolved.face
404
+ };
405
+ }
406
+ const alloc = fontAllocs.get(resolved.standardName);
407
+ if (alloc === void 0) throw new Error(`font "${resolved.standardName}" was not pre-allocated -- this is a writePdf internal invariant violation`);
340
408
  return {
409
+ kind: "standard",
341
410
  resourceName: alloc.resourceName,
342
- standardName
411
+ standardName: resolved.standardName
343
412
  };
344
413
  },
345
414
  resolveImage: (imageId) => {
@@ -351,8 +420,9 @@ function writePdf(doc, options = {}) {
351
420
  doc.pages.forEach((page, pageIndex) => {
352
421
  throwIfAborted(options.signal);
353
422
  const { pageNum, contentsNum } = pageAllocs[pageIndex];
354
- const { bytes: contentBytes, substitutions } = writeContentStream(page.items, context);
423
+ const { bytes: contentBytes, substitutions, missingGlyphs } = writeContentStream(page.items, context);
355
424
  for (const substitution of substitutions) options.onSubstitution?.(substitution, { pageIndex });
425
+ for (const missing of missingGlyphs) options.onMissingGlyph?.(missing, { pageIndex });
356
426
  const pageFormulas = formulasByPage.get(pageIndex);
357
427
  const formulaBytes = pageFormulas === void 0 || mathFontAlloc === void 0 || mathFont === void 0 ? void 0 : writeFormulaContentStream(pageFormulas, {
358
428
  font: mathFont,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-codec",
3
- "version": "1.4.2",
3
+ "version": "1.6.0",
4
4
  "description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on document-schema.js's LayoutDocument pivot and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -1,81 +0,0 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_sfnt = require("./sfnt.cjs");
3
- //#region src/math-cmap.ts
4
- function parseFormat4(bytes, subtableOffset) {
5
- const segCountX2 = require_sfnt.u16(bytes, subtableOffset + 6);
6
- const segCount = segCountX2 / 2;
7
- const endCodesOffset = subtableOffset + 14;
8
- const startCodesOffset = endCodesOffset + segCountX2 + 2;
9
- const idDeltasOffset = startCodesOffset + segCountX2;
10
- const idRangeOffsetsOffset = idDeltasOffset + segCountX2;
11
- const groups = [];
12
- for (let i = 0; i < segCount; i++) {
13
- const idRangeOffsetPos = idRangeOffsetsOffset + i * 2;
14
- groups.push({
15
- endCode: require_sfnt.u16(bytes, endCodesOffset + i * 2),
16
- startCode: require_sfnt.u16(bytes, startCodesOffset + i * 2),
17
- idDelta: (() => {
18
- const raw = require_sfnt.u16(bytes, idDeltasOffset + i * 2);
19
- return raw >= 32768 ? raw - 65536 : raw;
20
- })(),
21
- idRangeOffsetPos,
22
- idRangeOffset: require_sfnt.u16(bytes, idRangeOffsetPos)
23
- });
24
- }
25
- return (codePoint) => {
26
- if (codePoint > 65535) return;
27
- for (const group of groups) {
28
- if (codePoint < group.startCode || codePoint > group.endCode) continue;
29
- if (group.idRangeOffset === 0) return codePoint + group.idDelta & 65535;
30
- const glyphIndexAddress = group.idRangeOffsetPos + group.idRangeOffset + (codePoint - group.startCode) * 2;
31
- const glyphId = require_sfnt.u16(bytes, glyphIndexAddress);
32
- return glyphId === 0 ? void 0 : glyphId + group.idDelta & 65535;
33
- }
34
- };
35
- }
36
- function parseFormat12(bytes, subtableOffset) {
37
- const numGroups = require_sfnt.u32(bytes, subtableOffset + 12);
38
- const groups = [];
39
- for (let i = 0; i < numGroups; i++) {
40
- const recordOffset = subtableOffset + 16 + i * 12;
41
- groups.push({
42
- startCharCode: require_sfnt.u32(bytes, recordOffset),
43
- endCharCode: require_sfnt.u32(bytes, recordOffset + 4),
44
- startGlyphId: require_sfnt.u32(bytes, recordOffset + 8)
45
- });
46
- }
47
- return (codePoint) => {
48
- for (const group of groups) if (codePoint >= group.startCharCode && codePoint <= group.endCharCode) return group.startGlyphId + (codePoint - group.startCharCode);
49
- };
50
- }
51
- function buildCmapLookup(font) {
52
- const cmapBytes = require_sfnt.sfntTableBytes(font, "cmap");
53
- if (cmapBytes === void 0) throw new Error("math font has no cmap table");
54
- const numTables = require_sfnt.u16(cmapBytes, 2);
55
- const subtables = [];
56
- for (let i = 0; i < numTables; i++) {
57
- const recordOffset = 4 + i * 8;
58
- const platformId = require_sfnt.u16(cmapBytes, recordOffset);
59
- const encodingId = require_sfnt.u16(cmapBytes, recordOffset + 2);
60
- const offset = require_sfnt.u32(cmapBytes, recordOffset + 4);
61
- subtables.push({
62
- platformId,
63
- encodingId,
64
- offset,
65
- format: require_sfnt.u16(cmapBytes, offset)
66
- });
67
- }
68
- const byPreference = (a) => {
69
- if (a.format === 12 && a.platformId === 3 && a.encodingId === 10) return 0;
70
- if (a.format === 12 && a.platformId === 0) return 1;
71
- if (a.format === 12) return 2;
72
- if (a.format === 4 && a.platformId === 3 && a.encodingId === 1) return 3;
73
- if (a.format === 4) return 4;
74
- return 5;
75
- };
76
- const best = subtables.filter((s) => s.format === 4 || s.format === 12).sort((a, b) => byPreference(a) - byPreference(b))[0];
77
- if (best === void 0) throw new Error("math font cmap has no format 4 or format 12 subtable");
78
- return best.format === 12 ? parseFormat12(cmapBytes, best.offset) : parseFormat4(cmapBytes, best.offset);
79
- }
80
- //#endregion
81
- exports.buildCmapLookup = buildCmapLookup;
@@ -1,6 +0,0 @@
1
- import { SfntFont } from "./sfnt.cjs";
2
- //#region src/math-cmap.d.ts
3
- type CmapLookup = (codePoint: number) => number | undefined;
4
- declare function buildCmapLookup(font: SfntFont): CmapLookup;
5
- //#endregion
6
- export { CmapLookup, buildCmapLookup };
@@ -1,6 +0,0 @@
1
- import { SfntFont } from "./sfnt.js";
2
- //#region src/math-cmap.d.ts
3
- type CmapLookup = (codePoint: number) => number | undefined;
4
- declare function buildCmapLookup(font: SfntFont): CmapLookup;
5
- //#endregion
6
- export { CmapLookup, buildCmapLookup };
package/dist/math-cmap.js DELETED
@@ -1,80 +0,0 @@
1
- import { sfntTableBytes, u16, u32 } from "./sfnt.js";
2
- //#region src/math-cmap.ts
3
- function parseFormat4(bytes, subtableOffset) {
4
- const segCountX2 = u16(bytes, subtableOffset + 6);
5
- const segCount = segCountX2 / 2;
6
- const endCodesOffset = subtableOffset + 14;
7
- const startCodesOffset = endCodesOffset + segCountX2 + 2;
8
- const idDeltasOffset = startCodesOffset + segCountX2;
9
- const idRangeOffsetsOffset = idDeltasOffset + segCountX2;
10
- const groups = [];
11
- for (let i = 0; i < segCount; i++) {
12
- const idRangeOffsetPos = idRangeOffsetsOffset + i * 2;
13
- groups.push({
14
- endCode: u16(bytes, endCodesOffset + i * 2),
15
- startCode: u16(bytes, startCodesOffset + i * 2),
16
- idDelta: (() => {
17
- const raw = u16(bytes, idDeltasOffset + i * 2);
18
- return raw >= 32768 ? raw - 65536 : raw;
19
- })(),
20
- idRangeOffsetPos,
21
- idRangeOffset: u16(bytes, idRangeOffsetPos)
22
- });
23
- }
24
- return (codePoint) => {
25
- if (codePoint > 65535) return;
26
- for (const group of groups) {
27
- if (codePoint < group.startCode || codePoint > group.endCode) continue;
28
- if (group.idRangeOffset === 0) return codePoint + group.idDelta & 65535;
29
- const glyphIndexAddress = group.idRangeOffsetPos + group.idRangeOffset + (codePoint - group.startCode) * 2;
30
- const glyphId = u16(bytes, glyphIndexAddress);
31
- return glyphId === 0 ? void 0 : glyphId + group.idDelta & 65535;
32
- }
33
- };
34
- }
35
- function parseFormat12(bytes, subtableOffset) {
36
- const numGroups = u32(bytes, subtableOffset + 12);
37
- const groups = [];
38
- for (let i = 0; i < numGroups; i++) {
39
- const recordOffset = subtableOffset + 16 + i * 12;
40
- groups.push({
41
- startCharCode: u32(bytes, recordOffset),
42
- endCharCode: u32(bytes, recordOffset + 4),
43
- startGlyphId: u32(bytes, recordOffset + 8)
44
- });
45
- }
46
- return (codePoint) => {
47
- for (const group of groups) if (codePoint >= group.startCharCode && codePoint <= group.endCharCode) return group.startGlyphId + (codePoint - group.startCharCode);
48
- };
49
- }
50
- function buildCmapLookup(font) {
51
- const cmapBytes = sfntTableBytes(font, "cmap");
52
- if (cmapBytes === void 0) throw new Error("math font has no cmap table");
53
- const numTables = u16(cmapBytes, 2);
54
- const subtables = [];
55
- for (let i = 0; i < numTables; i++) {
56
- const recordOffset = 4 + i * 8;
57
- const platformId = u16(cmapBytes, recordOffset);
58
- const encodingId = u16(cmapBytes, recordOffset + 2);
59
- const offset = u32(cmapBytes, recordOffset + 4);
60
- subtables.push({
61
- platformId,
62
- encodingId,
63
- offset,
64
- format: u16(cmapBytes, offset)
65
- });
66
- }
67
- const byPreference = (a) => {
68
- if (a.format === 12 && a.platformId === 3 && a.encodingId === 10) return 0;
69
- if (a.format === 12 && a.platformId === 0) return 1;
70
- if (a.format === 12) return 2;
71
- if (a.format === 4 && a.platformId === 3 && a.encodingId === 1) return 3;
72
- if (a.format === 4) return 4;
73
- return 5;
74
- };
75
- const best = subtables.filter((s) => s.format === 4 || s.format === 12).sort((a, b) => byPreference(a) - byPreference(b))[0];
76
- if (best === void 0) throw new Error("math font cmap has no format 4 or format 12 subtable");
77
- return best.format === 12 ? parseFormat12(cmapBytes, best.offset) : parseFormat4(cmapBytes, best.offset);
78
- }
79
- //#endregion
80
- export { buildCmapLookup };