@jasy/pdf 1.0.0-alpha.2 → 1.0.0-alpha.3

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 (139) hide show
  1. package/README.md +3 -3
  2. package/dist/api/args.d.ts +1 -1
  3. package/dist/api/args.js +2 -5
  4. package/dist/api/color.d.ts +4 -4
  5. package/dist/api/color.js +11 -17
  6. package/dist/api/content.d.ts +8 -8
  7. package/dist/api/content.js +23 -24
  8. package/dist/api/descriptor.d.ts +2 -2
  9. package/dist/api/descriptor.js +75 -31
  10. package/dist/api/index.d.ts +8 -8
  11. package/dist/api/index.js +8 -24
  12. package/dist/api/insets.js +4 -8
  13. package/dist/api/layout.d.ts +18 -16
  14. package/dist/api/layout.js +41 -52
  15. package/dist/api/structure.d.ts +60 -13
  16. package/dist/api/structure.js +132 -88
  17. package/dist/api/table.d.ts +5 -5
  18. package/dist/api/table.js +28 -24
  19. package/dist/api/text.d.ts +27 -2
  20. package/dist/api/text.js +45 -27
  21. package/dist/assets/font-data.d.ts +2 -0
  22. package/dist/assets/font-data.js +6 -0
  23. package/dist/assets/font-data.ts +7 -0
  24. package/dist/common/color.js +1 -5
  25. package/dist/constants/page-sizes.js +3 -6
  26. package/dist/constants/pdf-parts.js +1 -4
  27. package/dist/elements/container-element.d.ts +4 -4
  28. package/dist/elements/container-element.js +9 -13
  29. package/dist/elements/image-element.d.ts +18 -2
  30. package/dist/elements/image-element.js +81 -105
  31. package/dist/elements/index.d.ts +12 -11
  32. package/dist/elements/index.js +12 -29
  33. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  34. package/dist/elements/layout/default-text-style-element.js +47 -0
  35. package/dist/elements/layout/deferred-element.d.ts +3 -3
  36. package/dist/elements/layout/deferred-element.js +4 -8
  37. package/dist/elements/layout/expanded-element.d.ts +3 -3
  38. package/dist/elements/layout/expanded-element.js +10 -14
  39. package/dist/elements/layout/padding-element.d.ts +3 -3
  40. package/dist/elements/layout/padding-element.js +9 -14
  41. package/dist/elements/layout/positioned-element.d.ts +17 -4
  42. package/dist/elements/layout/positioned-element.js +29 -25
  43. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  44. package/dist/elements/layout/repeating-header-element.js +8 -12
  45. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  46. package/dist/elements/layout/sized-container-element.js +6 -11
  47. package/dist/elements/line-element.d.ts +3 -3
  48. package/dist/elements/line-element.js +5 -10
  49. package/dist/elements/page-element.d.ts +8 -6
  50. package/dist/elements/page-element.js +20 -23
  51. package/dist/elements/pdf-document-element.d.ts +10 -4
  52. package/dist/elements/pdf-document-element.js +11 -10
  53. package/dist/elements/pdf-element.d.ts +12 -3
  54. package/dist/elements/pdf-element.js +10 -19
  55. package/dist/elements/rectangle-element.d.ts +5 -5
  56. package/dist/elements/rectangle-element.js +19 -25
  57. package/dist/elements/row-element.d.ts +3 -3
  58. package/dist/elements/row-element.js +7 -11
  59. package/dist/elements/text-element.d.ts +37 -11
  60. package/dist/elements/text-element.js +64 -39
  61. package/dist/index.d.ts +3 -3
  62. package/dist/index.js +3 -19
  63. package/dist/ir/display-list.d.ts +4 -2
  64. package/dist/ir/display-list.js +1 -2
  65. package/dist/layout/box-constraints.js +2 -6
  66. package/dist/layout/fragmentation.d.ts +8 -1
  67. package/dist/layout/fragmentation.js +22 -10
  68. package/dist/platform/browser-fs.d.ts +2 -0
  69. package/dist/platform/browser-fs.js +9 -0
  70. package/dist/platform/browser-image.d.ts +5 -0
  71. package/dist/platform/browser-image.js +13 -0
  72. package/dist/platform/node-fs.d.ts +2 -0
  73. package/dist/platform/node-fs.js +10 -0
  74. package/dist/platform/node-image.d.ts +5 -0
  75. package/dist/platform/node-image.js +9 -0
  76. package/dist/renderer/container-renderer.d.ts +3 -3
  77. package/dist/renderer/container-renderer.js +12 -27
  78. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  79. package/dist/renderer/default-text-style-renderer.js +10 -0
  80. package/dist/renderer/deferred-renderer.d.ts +3 -3
  81. package/dist/renderer/deferred-renderer.js +8 -23
  82. package/dist/renderer/expanded-renderer.d.ts +3 -3
  83. package/dist/renderer/expanded-renderer.js +6 -21
  84. package/dist/renderer/image-renderer.d.ts +3 -3
  85. package/dist/renderer/image-renderer.js +77 -75
  86. package/dist/renderer/index.d.ts +10 -10
  87. package/dist/renderer/index.js +10 -26
  88. package/dist/renderer/line-renderer.d.ts +3 -3
  89. package/dist/renderer/line-renderer.js +13 -28
  90. package/dist/renderer/padding-renderer.d.ts +3 -3
  91. package/dist/renderer/padding-renderer.js +6 -21
  92. package/dist/renderer/page-renderer.d.ts +2 -2
  93. package/dist/renderer/page-renderer.js +61 -77
  94. package/dist/renderer/pdf-backend.d.ts +2 -2
  95. package/dist/renderer/pdf-backend.js +21 -19
  96. package/dist/renderer/pdf-config.js +4 -7
  97. package/dist/renderer/pdf-document-class.d.ts +5 -5
  98. package/dist/renderer/pdf-document-class.js +24 -41
  99. package/dist/renderer/pdf-document-renderer.d.ts +3 -3
  100. package/dist/renderer/pdf-document-renderer.js +71 -85
  101. package/dist/renderer/pdf-renderer.d.ts +2 -2
  102. package/dist/renderer/pdf-renderer.js +83 -93
  103. package/dist/renderer/positioned-renderer.d.ts +3 -3
  104. package/dist/renderer/positioned-renderer.js +8 -23
  105. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  106. package/dist/renderer/rectangle-renderer.js +45 -52
  107. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  108. package/dist/renderer/repeating-header-renderer.js +11 -26
  109. package/dist/renderer/row-renderer.d.ts +3 -3
  110. package/dist/renderer/row-renderer.js +12 -27
  111. package/dist/renderer/text-renderer.d.ts +6 -5
  112. package/dist/renderer/text-renderer.js +33 -42
  113. package/dist/text/line-breaker.d.ts +8 -5
  114. package/dist/text/line-breaker.js +67 -16
  115. package/dist/text/text-style.d.ts +25 -0
  116. package/dist/text/text-style.js +29 -0
  117. package/dist/utils/afm-parser.js +3 -13
  118. package/dist/utils/bytes.d.ts +24 -0
  119. package/dist/utils/bytes.js +76 -0
  120. package/dist/utils/flex-layout.d.ts +2 -2
  121. package/dist/utils/flex-layout.js +15 -20
  122. package/dist/utils/font-metrics.d.ts +1 -1
  123. package/dist/utils/font-metrics.js +1 -2
  124. package/dist/utils/font-path.js +3 -6
  125. package/dist/utils/image-helper.d.ts +6 -5
  126. package/dist/utils/image-helper.js +101 -111
  127. package/dist/utils/md5.d.ts +4 -0
  128. package/dist/utils/md5.js +80 -0
  129. package/dist/utils/pdf-object-manager.d.ts +10 -6
  130. package/dist/utils/pdf-object-manager.js +89 -94
  131. package/dist/utils/renderer-registry.js +1 -5
  132. package/dist/utils/ttf-parser.d.ts +2 -2
  133. package/dist/utils/ttf-parser.js +32 -36
  134. package/dist/utils/ttf-subsetter.d.ts +1 -1
  135. package/dist/utils/ttf-subsetter.js +40 -42
  136. package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
  137. package/dist/validators/element-validator.d.ts +2 -2
  138. package/dist/validators/element-validator.js +9 -13
  139. package/package.json +14 -2
@@ -1,57 +1,25 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.PDFObjectManager = exports.FontStyle = void 0;
37
- const page_sizes_1 = require("../constants/page-sizes");
38
- const fs = __importStar(require("fs"));
39
- const path = __importStar(require("path"));
40
- const crypto_1 = require("crypto");
41
- const zlib_1 = require("zlib");
42
- const afm_parser_1 = require("./afm-parser");
43
- const ttf_parser_1 = require("./ttf-parser");
44
- const ttf_subsetter_1 = require("./ttf-subsetter");
1
+ import { pageFormats, PageSize } from "../constants/page-sizes.js";
2
+ import { STANDARD_AFM } from "../assets/font-data.js";
3
+ import { md5, md5Hex } from "./md5.js";
4
+ import { zlibSync } from "fflate";
5
+ import { bytesFromLatin1, latin1FromBytes } from "./bytes.js";
6
+ import { AFMParser } from "./afm-parser.js";
7
+ import { TTFParser } from "./ttf-parser.js";
8
+ import { subsetTTF } from "./ttf-subsetter.js";
9
+ import { getArrayBuffer } from "./utf8-to-windows1252-encoder.js";
45
10
  // Enums come from the leaf config module (never in a cycle); the config type is
46
11
  // erased at runtime so it can come from the cyclic module safely.
47
- const pdf_config_1 = require("../renderer/pdf-config");
48
- var FontStyle;
12
+ import { ColorMode, Orientation } from "../renderer/pdf-config.js";
13
+ export var FontStyle;
49
14
  (function (FontStyle) {
50
15
  FontStyle["Normal"] = "normal";
51
16
  FontStyle["Bold"] = "bold";
52
17
  FontStyle["Italic"] = "italic";
53
18
  FontStyle["BoldItalic"] = "boldItalic";
54
- })(FontStyle || (exports.FontStyle = FontStyle = {}));
19
+ })(FontStyle || (FontStyle = {}));
20
+ // Escapes a string into a valid PDF /Name token. A raw space or delimiter in a /Name (e.g. a font
21
+ // family like "Great Vibes" or "Times New Roman") breaks the dictionary, so such chars become #XX.
22
+ const pdfName = (s) => s.replace(/[^\x21-\x7e]|[#()<>[\]{}/%]/g, (c) => "#" + c.charCodeAt(0).toString(16).toUpperCase().padStart(2, "0"));
55
23
  // Suffix appended to an embedded font's PDF /BaseFont so each style variant of a family keeps
56
24
  // a distinct name (the variants are otherwise selected by the font resource, not the name).
57
25
  const STYLE_SUFFIX = {
@@ -152,7 +120,7 @@ class FontManager {
152
120
  return `${fontName}-${fontStyle}`;
153
121
  }
154
122
  }
155
- class PDFObjectManager {
123
+ export class PDFObjectManager {
156
124
  constructor(pageSize) {
157
125
  this.objects = [];
158
126
  this.objectPositions = [];
@@ -160,7 +128,7 @@ class PDFObjectManager {
160
128
  this.fonts = new FontManager(); // Stores the fonts
161
129
  this.images = new ImageManager(); // Stores the images (object numbers and names)
162
130
  this.extGStates = new ExtGStateManager(); // Transparency states
163
- this.pageFormat = page_sizes_1.pageFormats[page_sizes_1.PageSize.A4];
131
+ this.pageFormat = pageFormats[PageSize.A4];
164
132
  this.afmParsers = [];
165
133
  // Embedded TrueType fonts, keyed by the name the user registers them under. When a font
166
134
  // name is in here the metric/emission paths take the TTF branch instead of the AFM one.
@@ -172,12 +140,13 @@ class PDFObjectManager {
172
140
  // the catalog's /Names/EmbeddedFiles + /AF. Drives ZUGFeRD's embedded factur-x.xml.
173
141
  this.attachments = [];
174
142
  // PDF header version (PDF/A-3 needs 1.7) and whether to write a trailer /ID (PDF/A needs one).
175
- // Both default to the pre-PDF/A behaviour, so a normal document stays byte-identical.
143
+ // Both default to the pre-PDF/A behavior, so a normal document stays byte-identical.
176
144
  this.pdfVersion = "1.4";
177
145
  this.documentId = false;
178
146
  this.compress = false;
147
+ this.overflowPolicy = "error";
179
148
  if (pageSize)
180
- this.pageFormat = page_sizes_1.pageFormats[pageSize];
149
+ this.pageFormat = pageFormats[pageSize];
181
150
  this.fillConfigWithStandardValues();
182
151
  }
183
152
  // Adds an object and returns its number
@@ -198,40 +167,51 @@ class PDFObjectManager {
198
167
  setCompress(on) {
199
168
  this.compress = on;
200
169
  }
170
+ // Overflow policy for unbreakable content taller than a page region (default "error"); the renderer
171
+ // seeds it into the layout-context root so packChildren can act on it.
172
+ setOverflowPolicy(policy) {
173
+ this.overflowPolicy = policy;
174
+ }
175
+ getOverflowPolicy() {
176
+ return this.overflowPolicy;
177
+ }
201
178
  // Builds a stream object body: `<< extraDict /Length n >> stream … endstream`, FlateDecode-compressed
202
179
  // when enabled AND it actually helps (tiny streams aren't inflated). Binary bytes ride as a latin1
203
180
  // string - the final encoder passes 0x00-0xFF through unchanged.
204
181
  stream(extraDict, data) {
205
182
  const head = extraDict ? extraDict + " " : "";
206
183
  if (this.compress) {
207
- const z = (0, zlib_1.deflateSync)(data);
184
+ const z = zlibSync(data);
208
185
  if (z.length < data.length) {
209
- return `<< ${head}/Filter /FlateDecode /Length ${z.length} >>\nstream\n${z.toString("latin1")}\nendstream`;
186
+ return `<< ${head}/Filter /FlateDecode /Length ${z.length} >>\nstream\n${latin1FromBytes(z)}\nendstream`;
210
187
  }
211
188
  }
212
- return `<< ${head}/Length ${data.length} >>\nstream\n${data.toString("latin1")}\nendstream`;
189
+ return `<< ${head}/Length ${data.length} >>\nstream\n${latin1FromBytes(data)}\nendstream`;
213
190
  }
214
191
  // Adds a page content stream (compressed when enabled). The caller passes the raw operator string.
192
+ // Bytes go through the Windows-1252 encoder (NOT a latin1 low-byte cast): a Tj literal may carry a
193
+ // CP1252 char like "…"/"—"/"€" whose codepoint is > 0xFF, and latin1 would mangle it (… -> "&").
194
+ // For every char <= 0xFF the encoder passes the byte through, so existing streams stay byte-identical.
215
195
  addContentStream(content) {
216
- return this.addObject(this.stream("", Buffer.from(content, "latin1")));
196
+ return this.addObject(this.stream("", new Uint8Array(getArrayBuffer(content))));
217
197
  }
218
198
  changePDFConfig(config) {
219
- this.pdfConfig = Object.assign(Object.assign({}, this.pdfConfig), config);
199
+ this.pdfConfig = { ...this.pdfConfig, ...config };
220
200
  }
221
201
  getPDFConfig() {
222
202
  return this.pdfConfig;
223
203
  }
224
204
  fillConfigWithStandardValues() {
225
205
  this.pdfConfig = {
226
- orientation: pdf_config_1.Orientation.portrait,
206
+ orientation: Orientation.portrait,
227
207
  defaultFont: {
228
208
  fontFamily: "Helvetica",
229
209
  fontSize: 12,
230
210
  fontStyle: FontStyle.Normal,
231
211
  },
232
- pageSize: page_sizes_1.PageSize.A4,
212
+ pageSize: PageSize.A4,
233
213
  margin: { left: 72, top: 72, bottom: 72, right: 72 },
234
- colorMode: pdf_config_1.ColorMode.color,
214
+ colorMode: ColorMode.color,
235
215
  };
236
216
  }
237
217
  // Calculates the total length of the document in bytes (for XRef)
@@ -240,10 +220,8 @@ class PDFObjectManager {
240
220
  for (let i = 0; i < this.objects.length; i++) {
241
221
  const obj = this.objects[i];
242
222
  const objectContent = `${i + 1} 0 obj\n${obj}\nendobj\n`;
243
- // Convert the object content into a buffer with the correct encoding
244
- const encodedContent = Buffer.from(objectContent, "binary");
245
- // Add the actual byte length to the total length
246
- length += encodedContent.length;
223
+ // The body is a latin1/binary string (every char <= 0xFF), so its length IS its byte length.
224
+ length += objectContent.length;
247
225
  }
248
226
  return length;
249
227
  }
@@ -256,7 +234,23 @@ class PDFObjectManager {
256
234
  return this.parentObjectNumber;
257
235
  }
258
236
  // Registers an image
259
- registerImage(width, height, imageType, imageData) {
237
+ registerImage(width, height, imageType, imageData, smaskData) {
238
+ // A transparent PNG carries its alpha as a separate DeviceGray /SMask image the viewer composites with.
239
+ let smaskEntry = "";
240
+ if (smaskData) {
241
+ const smaskObject = `<< /Type /XObject
242
+ /Subtype /Image
243
+ /Width ${width}
244
+ /Height ${height}
245
+ /ColorSpace /DeviceGray
246
+ /BitsPerComponent 8
247
+ /Filter /FlateDecode
248
+ /Length ${smaskData.length} >>
249
+ stream
250
+ ${smaskData}
251
+ endstream`;
252
+ smaskEntry = ` /SMask ${this.addObject(smaskObject)} 0 R\n`;
253
+ }
260
254
  const imageObject = `<< /Type /XObject
261
255
  /Subtype /Image
262
256
  /Width ${width}
@@ -264,9 +258,9 @@ class PDFObjectManager {
264
258
  /ColorSpace /DeviceRGB
265
259
  /BitsPerComponent 8
266
260
  /Filter /${imageType}
267
- /Length ${imageData.length} >>
261
+ ${smaskEntry} /Length ${imageData.length} >>
268
262
  stream
269
- ${imageData}
263
+ ${imageData}
270
264
  endstream`;
271
265
  // Add the image and its object number to the image manager - return the object number
272
266
  const imageObjectNumber = this.addObject(imageObject);
@@ -278,13 +272,12 @@ endstream`;
278
272
  // `relationship` is the /AFRelationship (e.g. "Data" for the ZUGFeRD factur-x.xml). Binary bytes
279
273
  // ride as a latin1 string, like images/fonts (the final encoder passes 0x00-0xFF through).
280
274
  attachFile(name, data, opts = {}) {
281
- var _a, _b;
282
- const subtype = ((_a = opts.mimeType) !== null && _a !== void 0 ? _a : "application/octet-stream").replace(/\//g, "#2F");
275
+ const subtype = (opts.mimeType ?? "application/octet-stream").replace(/\//g, "#2F");
283
276
  const embedded = this.addObject(this.stream(`/Type /EmbeddedFile /Subtype /${subtype} /Params << /Size ${data.length} >>`, data));
284
277
  const escaped = (s) => s.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
285
278
  const desc = opts.description ? ` /Desc (${escaped(opts.description)})` : "";
286
279
  const filespec = this.addObject(`<< /Type /Filespec /F (${escaped(name)}) /UF (${escaped(name)}) ` +
287
- `/AFRelationship /${(_b = opts.relationship) !== null && _b !== void 0 ? _b : "Unspecified"}${desc} ` +
280
+ `/AFRelationship /${opts.relationship ?? "Unspecified"}${desc} ` +
288
281
  `/EF << /F ${embedded} 0 R /UF ${embedded} 0 R >> >>`);
289
282
  this.attachments.push({ name, filespec });
290
283
  }
@@ -302,11 +295,10 @@ endstream`;
302
295
  // Embeds an ICC profile and a PDF/A /OutputIntent that points at it (catalog /OutputIntents).
303
296
  // `icc` are the raw profile bytes (an RGB profile, /N 3 - e.g. sRGB).
304
297
  setOutputIntent(icc, opts = {}) {
305
- var _a, _b;
306
298
  const profile = this.addObject(this.stream("/N 3", icc));
307
299
  this.outputIntent = this.addObject(`<< /Type /OutputIntent /S /GTS_PDFA1 ` +
308
- `/OutputConditionIdentifier (${(_a = opts.identifier) !== null && _a !== void 0 ? _a : "sRGB"}) ` +
309
- `/Info (${(_b = opts.info) !== null && _b !== void 0 ? _b : "sRGB IEC61966-2.1"}) /DestOutputProfile ${profile} 0 R >>`);
300
+ `/OutputConditionIdentifier (${opts.identifier ?? "sRGB"}) ` +
301
+ `/Info (${opts.info ?? "sRGB IEC61966-2.1"}) /DestOutputProfile ${profile} 0 R >>`);
310
302
  }
311
303
  getOutputIntent() {
312
304
  return this.outputIntent;
@@ -354,20 +346,19 @@ endstream`;
354
346
  if (this.fonts.hasFont(fontName, fontStyle)) {
355
347
  return this.fonts.getFont(fontName, fontStyle); // Already exists? Return it!
356
348
  }
357
- const afmFilePath = path.resolve(__dirname, "../", `assets/${fullName}.afm`);
358
- if (fs.existsSync(afmFilePath)) {
359
- const data = fs.readFileSync(afmFilePath, "utf-8");
349
+ const data = STANDARD_AFM[fullName];
350
+ if (data !== undefined) {
360
351
  this.afmParsers.push({
361
352
  fontName,
362
353
  fontStyle,
363
354
  fullFontName: fullName,
364
- parser: new afm_parser_1.AFMParser(data),
355
+ parser: new AFMParser(data),
365
356
  });
366
357
  }
367
358
  const resourceNumber = this.objects.length + 1; // New resource number
368
359
  const fontNumber = this.fonts.getLastFontIndex() + 1; // New font index number
369
360
  this.fonts.addFont(fontName, fontNumber, resourceNumber, fontStyle); // Store it
370
- const fontObject = `<</BaseFont/${fullName}/Type/Font\n/Encoding/WinAnsiEncoding\n/Subtype/Type1>>`;
361
+ const fontObject = `<</BaseFont/${pdfName(fullName)}/Type/Font\n/Encoding/WinAnsiEncoding\n/Subtype/Type1>>`;
371
362
  this.addObject(fontObject);
372
363
  return {
373
364
  fontIndex: fontNumber,
@@ -383,7 +374,7 @@ endstream`;
383
374
  const key = this.customKey(name, style);
384
375
  if (this.customFonts.has(key))
385
376
  return;
386
- this.customFonts.set(key, new ttf_parser_1.TTFParser(data));
377
+ this.customFonts.set(key, new TTFParser(data));
387
378
  // Emission (the PDF font objects + page resource) is DEFERRED to first use via ensureEmitted(),
388
379
  // so a registered-but-never-rendered face - e.g. a bundled family the document doesn't touch -
389
380
  // costs nothing in the output. The metrics above are still available for layout immediately.
@@ -429,9 +420,7 @@ endstream`;
429
420
  }
430
421
  // A deterministic 6-uppercase-letter subset tag (PDF/A wants the "TAG+FontName" form).
431
422
  subsetTag(pdfName, used) {
432
- const h = (0, crypto_1.createHash)("md5")
433
- .update(pdfName + [...used].sort((a, b) => a - b).join(","))
434
- .digest();
423
+ const h = md5(new TextEncoder().encode(pdfName + [...used].sort((a, b) => a - b).join(",")));
435
424
  let tag = "";
436
425
  for (let i = 0; i < 6; i++)
437
426
  tag += String.fromCharCode(65 + (h[i] % 26));
@@ -489,13 +478,13 @@ endstream`;
489
478
  // The SUBSET font program (only the used glyphs' outlines). Binary bytes survive as a latin1
490
479
  // string - the final Windows-1252 encoder passes 0x00-0xFF through unchanged (see getArrayBuffer).
491
480
  buildFontFile2(ttf, used) {
492
- const bytes = (0, ttf_subsetter_1.subsetTTF)(ttf.getData(), used);
481
+ const bytes = subsetTTF(ttf.getData(), used);
493
482
  // /Length1 is the UNCOMPRESSED font-program length (required even when FlateDecode'd).
494
483
  return this.stream(`/Length1 ${bytes.length}`, bytes);
495
484
  }
496
485
  buildFontDescriptor(name, ttf, fontFile) {
497
486
  const [x0, y0, x1, y1] = ttf.bbox;
498
- return (`<< /Type /FontDescriptor /FontName /${name} /Flags 4 ` +
487
+ return (`<< /Type /FontDescriptor /FontName /${pdfName(name)} /Flags 4 ` +
499
488
  `/FontBBox [${x0} ${y0} ${x1} ${y1}] /ItalicAngle 0 ` +
500
489
  `/Ascent ${ttf.ascent} /Descent ${ttf.descent} /CapHeight ${ttf.ascent} /StemV 80 ` +
501
490
  `/FontFile2 ${fontFile} 0 R >>`);
@@ -506,9 +495,9 @@ endstream`;
506
495
  const all = ttf.glyphWidths();
507
496
  const w = [...used]
508
497
  .sort((a, b) => a - b)
509
- .map((g) => { var _a; return `${g} [${(_a = all[g]) !== null && _a !== void 0 ? _a : 1000}]`; })
498
+ .map((g) => `${g} [${all[g] ?? 1000}]`)
510
499
  .join(" ");
511
- return (`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /${name} ` +
500
+ return (`<< /Type /Font /Subtype /CIDFontType2 /BaseFont /${pdfName(name)} ` +
512
501
  `/CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> ` +
513
502
  `/FontDescriptor ${descriptor} 0 R /CIDToGIDMap /Identity ` +
514
503
  `/DW 1000 /W [${w}] >>`);
@@ -533,10 +522,10 @@ endstream`;
533
522
  `/CMapName /Adobe-Identity-UCS def\n/CMapType 2 def\n` +
534
523
  `1 begincodespacerange\n<0000> <FFFF>\nendcodespacerange\n${blocks.join("\n")}\n` +
535
524
  `endcmap\nCMapName currentdict /CMap defineresource pop\nend\nend`;
536
- return this.stream("", Buffer.from(body, "latin1"));
525
+ return this.stream("", bytesFromLatin1(body));
537
526
  }
538
527
  buildType0(name, cidFont, toUnicode) {
539
- return (`<< /Type /Font /Subtype /Type0 /BaseFont /${name} /Encoding /Identity-H ` +
528
+ return (`<< /Type /Font /Subtype /Type0 /BaseFont /${pdfName(name)} /Encoding /Identity-H ` +
540
529
  `/DescendantFonts [${cidFont} 0 R] /ToUnicode ${toUnicode} 0 R >>`);
541
530
  }
542
531
  // Returns the current width of a text, included kernings
@@ -561,6 +550,11 @@ endstream`;
561
550
  return char.charCodeAt(0).toString();
562
551
  }
563
552
  getAVMParserByFont(fullFontName, fontName, fontStyle) {
553
+ // A non-string family means font bytes were passed where a name belongs - hint at the fix instead of
554
+ // stringifying the byte blob into an unreadable "parser not found".
555
+ for (const name of [fullFontName, fontName])
556
+ if (name != null && typeof name !== "string")
557
+ throw new Error(`Font family must be a string name, got ${typeof name}. Register font bytes via the document \`fonts\` map (or addFont) and reference them by name.`);
564
558
  if (!fullFontName && (!fontName || !fontStyle)) {
565
559
  throw new Error("No font family is given. Please set a full font name or a font with font style");
566
560
  }
@@ -577,14 +571,16 @@ endstream`;
577
571
  }
578
572
  // Methode zur Berechnung der Zeichenbreite anhand der Schriftgröße
579
573
  getCharWidth(char, fontSize, fullFontName, fontName, fontStyle) {
580
- const ttf = this.getCustomFont(fullFontName !== null && fullFontName !== void 0 ? fullFontName : fontName, fontStyle);
574
+ const ttf = this.getCustomFont(fullFontName ?? fontName, fontStyle);
581
575
  if (ttf)
582
576
  return ttf.getCharWidth(char, fontSize);
583
577
  const currentParser = this.getAVMParserByFont(fullFontName, fontName, fontStyle);
584
- const advanceWidth = currentParser.parser.getAdvanceWidth(char);
585
- // Normally we got still zero. TODO: Return a alternative width like the "space"
578
+ let advanceWidth = currentParser.parser.getAdvanceWidth(char);
579
+ // A character a standard font cannot represent (not in Windows-1252) is drawn as "?" by the
580
+ // encoder; measure it as "?" too so the width matches the glyph - graceful instead of a crash.
586
581
  if (!advanceWidth) {
587
- throw new Error(`Kein Metrik-Eintrag für Zeichen: ${char} ${this.getCharCode(char)}`);
582
+ advanceWidth =
583
+ currentParser.parser.getAdvanceWidth("?") || currentParser.parser.getAdvanceWidth(" ");
588
584
  }
589
585
  // Width of the character multiplied by the font size (scaled proportionally)
590
586
  return (advanceWidth / 1000) * fontSize;
@@ -592,7 +588,7 @@ endstream`;
592
588
  // Method to get the kerning, if available, between two signs
593
589
  getKerning(char, nextChar, fullFontName, fontName, fontStyle) {
594
590
  // TrueType kerning (the kern/GPOS tables) is not wired up yet - no kerning for custom fonts.
595
- if (this.getCustomFont(fullFontName !== null && fullFontName !== void 0 ? fullFontName : fontName, fontStyle))
591
+ if (this.getCustomFont(fullFontName ?? fontName, fontStyle))
596
592
  return 0;
597
593
  const currentParser = this.getAVMParserByFont(fullFontName, fontName, fontStyle);
598
594
  return currentParser.parser.getKerning(char, nextChar) / 1000;
@@ -635,11 +631,10 @@ endstream`;
635
631
  return `trailer\n<< /Size ${objectCount + 1} /Root ${root} 0 R${id} >>\nstartxref\n${startxref}\n%%EOF`;
636
632
  }
637
633
  contentId() {
638
- return `<${(0, crypto_1.createHash)("md5").update(this.objects.join("")).digest("hex").toUpperCase()}>`;
634
+ return `<${md5Hex(new TextEncoder().encode(this.objects.join(""))).toUpperCase()}>`;
639
635
  }
640
636
  // Returns the number of objects
641
637
  getObjectCount() {
642
638
  return this.objects.length;
643
639
  }
644
640
  }
645
- exports.PDFObjectManager = PDFObjectManager;
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RendererRegistry = void 0;
4
- class RendererRegistry {
1
+ export class RendererRegistry {
5
2
  static register(elementClass, renderer) {
6
3
  if (!RendererRegistry.renderers.has(elementClass)) {
7
4
  RendererRegistry.renderers.set(elementClass, renderer);
@@ -15,5 +12,4 @@ class RendererRegistry {
15
12
  return renderer.constructor.name === "AsyncFunction";
16
13
  }
17
14
  }
18
- exports.RendererRegistry = RendererRegistry;
19
15
  RendererRegistry.renderers = new Map();
@@ -10,8 +10,8 @@ export declare class TTFParser {
10
10
  private cmap;
11
11
  private cmapGroups;
12
12
  private tables;
13
- constructor(data: Buffer);
14
- getData(): Buffer;
13
+ constructor(data: Uint8Array);
14
+ getData(): Uint8Array;
15
15
  glyphCount(): number;
16
16
  glyphWidths(): number[];
17
17
  reverseCmap(): Map<number, number>;
@@ -1,10 +1,8 @@
1
- "use strict";
2
1
  // Parses the metric tables of a TrueType (.ttf) font - the binary counterpart to AFMParser.
3
2
  // Slice 1: glyph advance widths (hmtx) + the Unicode→glyph map (cmap), enough to compute
4
3
  // text width the same way AFMParser does for the standard-14. Embedding/subsetting come later.
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TTFParser = void 0;
7
- class TTFParser {
4
+ import { i16, latin1FromBytes, u16, u32 } from "./bytes.js";
5
+ export class TTFParser {
8
6
  constructor(data) {
9
7
  this.data = data;
10
8
  this.unitsPerEm = 1000;
@@ -20,18 +18,18 @@ class TTFParser {
20
18
  this.tables = {};
21
19
  this.readTableDirectory();
22
20
  const head = this.table("head").offset;
23
- this.unitsPerEm = this.data.readUInt16BE(head + 18);
24
- this.numGlyphs = this.data.readUInt16BE(this.table("maxp").offset + 4);
25
- this.numHMetrics = this.data.readUInt16BE(this.table("hhea").offset + 34);
21
+ this.unitsPerEm = u16(this.data, head + 18);
22
+ this.numGlyphs = u16(this.data, this.table("maxp").offset + 4);
23
+ this.numHMetrics = u16(this.data, this.table("hhea").offset + 34);
26
24
  this.bbox = [
27
- this.toGlyphSpace(this.data.readInt16BE(head + 36)), // xMin
28
- this.toGlyphSpace(this.data.readInt16BE(head + 38)), // yMin
29
- this.toGlyphSpace(this.data.readInt16BE(head + 40)), // xMax
30
- this.toGlyphSpace(this.data.readInt16BE(head + 42)), // yMax
25
+ this.toGlyphSpace(i16(this.data, head + 36)), // xMin
26
+ this.toGlyphSpace(i16(this.data, head + 38)), // yMin
27
+ this.toGlyphSpace(i16(this.data, head + 40)), // xMax
28
+ this.toGlyphSpace(i16(this.data, head + 42)), // yMax
31
29
  ];
32
30
  const hhea = this.table("hhea").offset;
33
- this.ascent = this.toGlyphSpace(this.data.readInt16BE(hhea + 4));
34
- this.descent = this.toGlyphSpace(this.data.readInt16BE(hhea + 6));
31
+ this.ascent = this.toGlyphSpace(i16(this.data, hhea + 4));
32
+ this.descent = this.toGlyphSpace(i16(this.data, hhea + 6));
35
33
  this.readHmtx();
36
34
  this.readCmap();
37
35
  }
@@ -76,9 +74,8 @@ class TTFParser {
76
74
  }
77
75
  // Advance width of a glyph in font units. Glyphs past numHMetrics reuse the last advance.
78
76
  getAdvanceWidth(glyphIndex) {
79
- var _a;
80
77
  const i = Math.min(glyphIndex, this.numHMetrics - 1);
81
- return (_a = this.advanceWidths[i]) !== null && _a !== void 0 ? _a : 0;
78
+ return this.advanceWidths[i] ?? 0;
82
79
  }
83
80
  // Char width at fontSize, scaled from font units (em = unitsPerEm) to points.
84
81
  getCharWidth(char, fontSize) {
@@ -99,13 +96,13 @@ class TTFParser {
99
96
  return t;
100
97
  }
101
98
  readTableDirectory() {
102
- const numTables = this.data.readUInt16BE(4);
99
+ const numTables = u16(this.data, 4);
103
100
  let p = 12; // after the offset table (sfntVersion + numTables + 3 fields)
104
101
  for (let i = 0; i < numTables; i++) {
105
- const tag = this.data.toString("latin1", p, p + 4);
102
+ const tag = latin1FromBytes(this.data.subarray(p, p + 4));
106
103
  this.tables[tag] = {
107
- offset: this.data.readUInt32BE(p + 8),
108
- length: this.data.readUInt32BE(p + 12),
104
+ offset: u32(this.data, p + 8),
105
+ length: u32(this.data, p + 12),
109
106
  };
110
107
  p += 16;
111
108
  }
@@ -116,20 +113,20 @@ class TTFParser {
116
113
  let last = 0;
117
114
  for (let i = 0; i < this.numGlyphs; i++) {
118
115
  if (i < this.numHMetrics)
119
- last = this.data.readUInt16BE(o + i * 4);
116
+ last = u16(this.data, o + i * 4);
120
117
  this.advanceWidths.push(last);
121
118
  }
122
119
  }
123
120
  readCmap() {
124
121
  const base = this.table("cmap").offset;
125
- const numTables = this.data.readUInt16BE(base + 2);
122
+ const numTables = u16(this.data, base + 2);
126
123
  // Prefer the Windows Unicode BMP subtable (3,1); accept full-Unicode (3,10) or any (0,x).
127
124
  let subtable = -1;
128
125
  let p = base + 4;
129
126
  for (let i = 0; i < numTables; i++) {
130
- const platform = this.data.readUInt16BE(p);
131
- const encoding = this.data.readUInt16BE(p + 2);
132
- const offset = this.data.readUInt32BE(p + 4);
127
+ const platform = u16(this.data, p);
128
+ const encoding = u16(this.data, p + 2);
129
+ const offset = u32(this.data, p + 4);
133
130
  const unicode = (platform === 3 && (encoding === 1 || encoding === 10)) || platform === 0;
134
131
  if (unicode) {
135
132
  subtable = base + offset;
@@ -140,7 +137,7 @@ class TTFParser {
140
137
  }
141
138
  if (subtable < 0)
142
139
  return;
143
- const format = this.data.readUInt16BE(subtable);
140
+ const format = u16(this.data, subtable);
144
141
  if (format === 4)
145
142
  this.readCmapFormat4(subtable);
146
143
  else if (format === 12)
@@ -149,23 +146,23 @@ class TTFParser {
149
146
  // Format 4: segment mapping. Four parallel arrays keyed by segment; the glyph comes either
150
147
  // from idDelta or, when idRangeOffset != 0, from the glyphIdArray it points into.
151
148
  readCmapFormat4(o) {
152
- const segCountX2 = this.data.readUInt16BE(o + 6);
149
+ const segCountX2 = u16(this.data, o + 6);
153
150
  const endCodes = o + 14;
154
151
  const startCodes = endCodes + segCountX2 + 2; // +2 reservedPad
155
152
  const idDeltas = startCodes + segCountX2;
156
153
  const idRangeOffsets = idDeltas + segCountX2;
157
154
  for (let i = 0; i < segCountX2 / 2; i++) {
158
- const end = this.data.readUInt16BE(endCodes + i * 2);
159
- const start = this.data.readUInt16BE(startCodes + i * 2);
160
- const delta = this.data.readUInt16BE(idDeltas + i * 2);
161
- const rangeOffset = this.data.readUInt16BE(idRangeOffsets + i * 2);
155
+ const end = u16(this.data, endCodes + i * 2);
156
+ const start = u16(this.data, startCodes + i * 2);
157
+ const delta = u16(this.data, idDeltas + i * 2);
158
+ const rangeOffset = u16(this.data, idRangeOffsets + i * 2);
162
159
  for (let c = start; c <= end && c !== 0xffff; c++) {
163
160
  let glyph;
164
161
  if (rangeOffset === 0) {
165
162
  glyph = (c + delta) & 0xffff;
166
163
  }
167
164
  else {
168
- glyph = this.data.readUInt16BE(idRangeOffsets + i * 2 + rangeOffset + (c - start) * 2);
165
+ glyph = u16(this.data, idRangeOffsets + i * 2 + rangeOffset + (c - start) * 2);
169
166
  if (glyph !== 0)
170
167
  glyph = (glyph + delta) & 0xffff;
171
168
  }
@@ -176,16 +173,15 @@ class TTFParser {
176
173
  }
177
174
  // Format 12: sequential groups for full Unicode (incl. astral). Kept un-expanded.
178
175
  readCmapFormat12(o) {
179
- const nGroups = this.data.readUInt32BE(o + 12);
176
+ const nGroups = u32(this.data, o + 12);
180
177
  let p = o + 16;
181
178
  for (let i = 0; i < nGroups; i++) {
182
179
  this.cmapGroups.push({
183
- start: this.data.readUInt32BE(p),
184
- end: this.data.readUInt32BE(p + 4),
185
- startGlyph: this.data.readUInt32BE(p + 8),
180
+ start: u32(this.data, p),
181
+ end: u32(this.data, p + 4),
182
+ startGlyph: u32(this.data, p + 8),
186
183
  });
187
184
  p += 12;
188
185
  }
189
186
  }
190
187
  }
191
- exports.TTFParser = TTFParser;
@@ -1 +1 @@
1
- export declare function subsetTTF(data: Buffer, used: Set<number>): Buffer;
1
+ export declare function subsetTTF(data: Uint8Array, used: Set<number>): Uint8Array;