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.
- package/README.md +56 -15
- package/dist/assets/caladea-bold.cjs +5 -0
- package/dist/assets/caladea-bold.d.cts +4 -0
- package/dist/assets/caladea-bold.d.ts +4 -0
- package/dist/assets/caladea-bold.js +4 -0
- package/dist/assets/caladea-bolditalic.cjs +5 -0
- package/dist/assets/caladea-bolditalic.d.cts +4 -0
- package/dist/assets/caladea-bolditalic.d.ts +4 -0
- package/dist/assets/caladea-bolditalic.js +4 -0
- package/dist/assets/caladea-italic.cjs +5 -0
- package/dist/assets/caladea-italic.d.cts +4 -0
- package/dist/assets/caladea-italic.d.ts +4 -0
- package/dist/assets/caladea-italic.js +4 -0
- package/dist/assets/caladea-regular.cjs +5 -0
- package/dist/assets/caladea-regular.d.cts +4 -0
- package/dist/assets/caladea-regular.d.ts +4 -0
- package/dist/assets/caladea-regular.js +4 -0
- package/dist/assets/carlito-bold.cjs +5 -0
- package/dist/assets/carlito-bold.d.cts +4 -0
- package/dist/assets/carlito-bold.d.ts +4 -0
- package/dist/assets/carlito-bold.js +4 -0
- package/dist/assets/carlito-bolditalic.cjs +5 -0
- package/dist/assets/carlito-bolditalic.d.cts +4 -0
- package/dist/assets/carlito-bolditalic.d.ts +4 -0
- package/dist/assets/carlito-bolditalic.js +4 -0
- package/dist/assets/carlito-italic.cjs +5 -0
- package/dist/assets/carlito-italic.d.cts +4 -0
- package/dist/assets/carlito-italic.d.ts +4 -0
- package/dist/assets/carlito-italic.js +4 -0
- package/dist/assets/carlito-regular.cjs +5 -0
- package/dist/assets/carlito-regular.d.cts +4 -0
- package/dist/assets/carlito-regular.d.ts +4 -0
- package/dist/assets/carlito-regular.js +4 -0
- package/dist/cff-probe.cjs +133 -0
- package/dist/cff-probe.d.cts +10 -0
- package/dist/cff-probe.d.ts +10 -0
- package/dist/cff-probe.js +132 -0
- package/dist/cmap-table.cjs +108 -0
- package/dist/cmap-table.d.cts +6 -0
- package/dist/cmap-table.d.ts +6 -0
- package/dist/cmap-table.js +107 -0
- package/dist/content-write.cjs +36 -17
- package/dist/content-write.d.cts +9 -2
- package/dist/content-write.d.ts +9 -2
- package/dist/content-write.js +35 -16
- package/dist/crypto/aes.cjs +166 -0
- package/dist/crypto/aes.d.cts +6 -0
- package/dist/crypto/aes.d.ts +6 -0
- package/dist/crypto/aes.js +163 -0
- package/dist/crypto/md5.cjs +215 -0
- package/dist/crypto/md5.d.cts +4 -0
- package/dist/crypto/md5.d.ts +4 -0
- package/dist/crypto/md5.js +214 -0
- package/dist/crypto/rc4.cjs +29 -0
- package/dist/crypto/rc4.d.cts +4 -0
- package/dist/crypto/rc4.d.ts +4 -0
- package/dist/crypto/rc4.js +28 -0
- package/dist/crypto/sha2.cjs +261 -0
- package/dist/crypto/sha2.d.cts +6 -0
- package/dist/crypto/sha2.d.ts +6 -0
- package/dist/crypto/sha2.js +258 -0
- package/dist/diagnostics.cjs +7 -0
- package/dist/diagnostics.d.cts +4 -1
- package/dist/diagnostics.d.ts +4 -1
- package/dist/diagnostics.js +7 -1
- package/dist/document.cjs +38 -2
- package/dist/document.js +38 -2
- package/dist/embedded-font-CLedn-mT.d.cts +42 -0
- package/dist/embedded-font-CbqkKgBl.d.ts +42 -0
- package/dist/embedded-font-write.cjs +92 -0
- package/dist/embedded-font-write.d.cts +22 -0
- package/dist/embedded-font-write.d.ts +22 -0
- package/dist/embedded-font-write.js +90 -0
- package/dist/embedded-font.cjs +142 -0
- package/dist/embedded-font.d.cts +2 -0
- package/dist/embedded-font.d.ts +2 -0
- package/dist/embedded-font.js +138 -0
- package/dist/encrypt.cjs +264 -0
- package/dist/encrypt.d.cts +11 -0
- package/dist/encrypt.d.ts +11 -0
- package/dist/encrypt.js +263 -0
- package/dist/filters.cjs +19 -1
- package/dist/filters.js +19 -1
- package/dist/font-registry-Cn7P9lAh.d.ts +38 -0
- package/dist/font-registry-yby02snZ.d.cts +38 -0
- package/dist/font-registry.cjs +152 -0
- package/dist/font-registry.d.cts +2 -0
- package/dist/font-registry.d.ts +2 -0
- package/dist/font-registry.js +150 -0
- package/dist/font-substitutes.cjs +13 -0
- package/dist/font-substitutes.d.cts +5 -0
- package/dist/font-substitutes.d.ts +5 -0
- package/dist/font-substitutes.js +12 -0
- package/dist/font-tables.cjs +127 -0
- package/dist/font-tables.d.cts +43 -0
- package/dist/font-tables.d.ts +43 -0
- package/dist/font-tables.js +122 -0
- package/dist/fonts.cjs +1 -0
- package/dist/fonts.d.cts +2 -1
- package/dist/fonts.d.ts +2 -1
- package/dist/fonts.js +1 -1
- package/dist/glyf.cjs +127 -0
- package/dist/glyf.d.cts +31 -0
- package/dist/glyf.d.ts +31 -0
- package/dist/glyf.js +125 -0
- package/dist/{math-hmtx.cjs → hmtx-table.cjs} +3 -3
- package/dist/{math-hmtx.d.ts → hmtx-table.d.cts} +2 -2
- package/dist/{math-hmtx.d.cts → hmtx-table.d.ts} +2 -2
- package/dist/{math-hmtx.js → hmtx-table.js} +3 -3
- package/dist/image/ccitt.cjs +488 -0
- package/dist/image/ccitt.d.cts +17 -0
- package/dist/image/ccitt.d.ts +17 -0
- package/dist/image/ccitt.js +487 -0
- package/dist/images-read.cjs +1 -4
- package/dist/images-read.js +2 -5
- package/dist/index.cjs +8 -0
- package/dist/index.d.cts +7 -4
- package/dist/index.d.ts +7 -4
- package/dist/index.js +5 -3
- package/dist/interpret.cjs +173 -38
- package/dist/interpret.d.cts +27 -10
- package/dist/interpret.d.ts +27 -10
- package/dist/interpret.js +174 -39
- package/dist/math-font-write.cjs +3 -32
- package/dist/math-font-write.js +2 -31
- package/dist/math-font.cjs +7 -5
- package/dist/math-font.js +5 -3
- package/dist/math-table.d.cts +1 -1
- package/dist/math-table.d.ts +1 -1
- package/dist/{matrix-B3c2_a2f.d.cts → matrix-BHzJESll.d.cts} +2 -1
- package/dist/{matrix-B3c2_a2f.d.ts → matrix-BHzJESll.d.ts} +2 -1
- package/dist/matrix.cjs +2 -0
- package/dist/matrix.d.cts +2 -2
- package/dist/matrix.d.ts +2 -2
- package/dist/matrix.js +2 -1
- package/dist/measure.cjs +65 -14
- package/dist/measure.d.cts +8 -1
- package/dist/measure.d.ts +8 -1
- package/dist/measure.js +64 -15
- package/dist/objects.cjs +4 -0
- package/dist/objects.d.cts +2 -1
- package/dist/objects.d.ts +2 -1
- package/dist/objects.js +4 -1
- package/dist/read.cjs +43 -4
- package/dist/read.d.cts +1 -1
- package/dist/read.d.ts +1 -1
- package/dist/read.js +43 -4
- package/dist/sfnt-V08bb5ut.d.cts +21 -0
- package/dist/sfnt-V08bb5ut.d.ts +21 -0
- package/dist/sfnt-subset.cjs +250 -0
- package/dist/sfnt-subset.d.cts +11 -0
- package/dist/sfnt-subset.d.ts +11 -0
- package/dist/sfnt-subset.js +249 -0
- package/dist/sfnt.cjs +50 -4
- package/dist/sfnt.d.cts +2 -17
- package/dist/sfnt.d.ts +2 -17
- package/dist/sfnt.js +47 -5
- package/dist/tounicode.cjs +34 -0
- package/dist/tounicode.d.cts +5 -0
- package/dist/tounicode.d.ts +5 -0
- package/dist/tounicode.js +33 -0
- package/dist/write.cjs +81 -11
- package/dist/write.d.cts +6 -0
- package/dist/write.d.ts +6 -0
- package/dist/write.js +82 -12
- package/package.json +1 -1
- package/dist/math-cmap.cjs +0 -81
- package/dist/math-cmap.d.cts +0 -6
- package/dist/math-cmap.d.ts +0 -6
- 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
|
|
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
|
-
|
|
209
|
-
|
|
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
|
|
339
|
-
|
|
340
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
208
|
-
|
|
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
|
|
338
|
-
|
|
339
|
-
|
|
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.
|
|
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": {
|
package/dist/math-cmap.cjs
DELETED
|
@@ -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;
|
package/dist/math-cmap.d.cts
DELETED
package/dist/math-cmap.d.ts
DELETED
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 };
|