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

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 (144) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +24 -14
  3. package/dist/api/args.d.ts +1 -1
  4. package/dist/api/args.js +2 -5
  5. package/dist/api/color.d.ts +4 -4
  6. package/dist/api/color.js +11 -17
  7. package/dist/api/content.d.ts +8 -8
  8. package/dist/api/content.js +23 -24
  9. package/dist/api/descriptor.d.ts +2 -2
  10. package/dist/api/descriptor.js +75 -31
  11. package/dist/api/index.d.ts +8 -8
  12. package/dist/api/index.js +8 -24
  13. package/dist/api/insets.js +4 -8
  14. package/dist/api/layout.d.ts +18 -16
  15. package/dist/api/layout.js +41 -52
  16. package/dist/api/structure.d.ts +65 -13
  17. package/dist/api/structure.js +140 -88
  18. package/dist/api/table.d.ts +5 -5
  19. package/dist/api/table.js +28 -24
  20. package/dist/api/text.d.ts +27 -2
  21. package/dist/api/text.js +45 -27
  22. package/dist/assets/font-data.d.ts +2 -0
  23. package/dist/assets/font-data.js +21 -0
  24. package/dist/assets/font-data.ts +37 -0
  25. package/dist/common/color.js +1 -5
  26. package/dist/constants/page-sizes.js +3 -6
  27. package/dist/constants/pdf-parts.js +1 -4
  28. package/dist/crypto/security-handler.d.ts +46 -0
  29. package/dist/crypto/security-handler.js +129 -0
  30. package/dist/crypto/webcrypto.d.ts +11 -0
  31. package/dist/crypto/webcrypto.js +62 -0
  32. package/dist/elements/container-element.d.ts +4 -4
  33. package/dist/elements/container-element.js +9 -13
  34. package/dist/elements/image-element.d.ts +18 -2
  35. package/dist/elements/image-element.js +81 -105
  36. package/dist/elements/index.d.ts +12 -11
  37. package/dist/elements/index.js +12 -29
  38. package/dist/elements/layout/default-text-style-element.d.ts +30 -0
  39. package/dist/elements/layout/default-text-style-element.js +47 -0
  40. package/dist/elements/layout/deferred-element.d.ts +3 -3
  41. package/dist/elements/layout/deferred-element.js +4 -8
  42. package/dist/elements/layout/expanded-element.d.ts +3 -3
  43. package/dist/elements/layout/expanded-element.js +10 -14
  44. package/dist/elements/layout/padding-element.d.ts +3 -3
  45. package/dist/elements/layout/padding-element.js +9 -14
  46. package/dist/elements/layout/positioned-element.d.ts +17 -4
  47. package/dist/elements/layout/positioned-element.js +29 -25
  48. package/dist/elements/layout/repeating-header-element.d.ts +3 -3
  49. package/dist/elements/layout/repeating-header-element.js +8 -12
  50. package/dist/elements/layout/sized-container-element.d.ts +2 -2
  51. package/dist/elements/layout/sized-container-element.js +6 -11
  52. package/dist/elements/line-element.d.ts +3 -3
  53. package/dist/elements/line-element.js +5 -10
  54. package/dist/elements/page-element.d.ts +8 -6
  55. package/dist/elements/page-element.js +20 -23
  56. package/dist/elements/pdf-document-element.d.ts +10 -4
  57. package/dist/elements/pdf-document-element.js +11 -10
  58. package/dist/elements/pdf-element.d.ts +12 -3
  59. package/dist/elements/pdf-element.js +10 -19
  60. package/dist/elements/rectangle-element.d.ts +5 -5
  61. package/dist/elements/rectangle-element.js +19 -25
  62. package/dist/elements/row-element.d.ts +3 -3
  63. package/dist/elements/row-element.js +7 -11
  64. package/dist/elements/text-element.d.ts +37 -11
  65. package/dist/elements/text-element.js +64 -39
  66. package/dist/index.d.ts +3 -3
  67. package/dist/index.js +3 -19
  68. package/dist/ir/display-list.d.ts +4 -2
  69. package/dist/ir/display-list.js +1 -2
  70. package/dist/layout/box-constraints.js +2 -6
  71. package/dist/layout/fragmentation.d.ts +8 -1
  72. package/dist/layout/fragmentation.js +22 -10
  73. package/dist/platform/browser-fs.d.ts +2 -0
  74. package/dist/platform/browser-fs.js +9 -0
  75. package/dist/platform/browser-image.d.ts +5 -0
  76. package/dist/platform/browser-image.js +13 -0
  77. package/dist/platform/node-fs.d.ts +2 -0
  78. package/dist/platform/node-fs.js +10 -0
  79. package/dist/platform/node-image.d.ts +5 -0
  80. package/dist/platform/node-image.js +9 -0
  81. package/dist/renderer/container-renderer.d.ts +3 -3
  82. package/dist/renderer/container-renderer.js +12 -27
  83. package/dist/renderer/default-text-style-renderer.d.ts +6 -0
  84. package/dist/renderer/default-text-style-renderer.js +10 -0
  85. package/dist/renderer/deferred-renderer.d.ts +3 -3
  86. package/dist/renderer/deferred-renderer.js +8 -23
  87. package/dist/renderer/expanded-renderer.d.ts +3 -3
  88. package/dist/renderer/expanded-renderer.js +6 -21
  89. package/dist/renderer/image-renderer.d.ts +3 -3
  90. package/dist/renderer/image-renderer.js +77 -75
  91. package/dist/renderer/index.d.ts +10 -10
  92. package/dist/renderer/index.js +10 -26
  93. package/dist/renderer/line-renderer.d.ts +3 -3
  94. package/dist/renderer/line-renderer.js +13 -28
  95. package/dist/renderer/padding-renderer.d.ts +3 -3
  96. package/dist/renderer/padding-renderer.js +6 -21
  97. package/dist/renderer/page-renderer.d.ts +2 -2
  98. package/dist/renderer/page-renderer.js +61 -77
  99. package/dist/renderer/pdf-backend.d.ts +2 -2
  100. package/dist/renderer/pdf-backend.js +21 -19
  101. package/dist/renderer/pdf-config.js +4 -7
  102. package/dist/renderer/pdf-document-class.d.ts +5 -5
  103. package/dist/renderer/pdf-document-class.js +24 -41
  104. package/dist/renderer/pdf-document-renderer.d.ts +3 -3
  105. package/dist/renderer/pdf-document-renderer.js +71 -85
  106. package/dist/renderer/pdf-renderer.d.ts +2 -2
  107. package/dist/renderer/pdf-renderer.js +85 -93
  108. package/dist/renderer/positioned-renderer.d.ts +3 -3
  109. package/dist/renderer/positioned-renderer.js +8 -23
  110. package/dist/renderer/rectangle-renderer.d.ts +3 -3
  111. package/dist/renderer/rectangle-renderer.js +45 -52
  112. package/dist/renderer/repeating-header-renderer.d.ts +3 -3
  113. package/dist/renderer/repeating-header-renderer.js +11 -26
  114. package/dist/renderer/row-renderer.d.ts +3 -3
  115. package/dist/renderer/row-renderer.js +12 -27
  116. package/dist/renderer/text-renderer.d.ts +6 -5
  117. package/dist/renderer/text-renderer.js +33 -42
  118. package/dist/text/line-breaker.d.ts +8 -5
  119. package/dist/text/line-breaker.js +67 -16
  120. package/dist/text/text-style.d.ts +25 -0
  121. package/dist/text/text-style.js +29 -0
  122. package/dist/utils/afm-parser.js +3 -13
  123. package/dist/utils/bytes.d.ts +24 -0
  124. package/dist/utils/bytes.js +76 -0
  125. package/dist/utils/flex-layout.d.ts +2 -2
  126. package/dist/utils/flex-layout.js +15 -20
  127. package/dist/utils/font-metrics.d.ts +1 -1
  128. package/dist/utils/font-metrics.js +1 -2
  129. package/dist/utils/font-path.js +3 -6
  130. package/dist/utils/image-helper.d.ts +6 -5
  131. package/dist/utils/image-helper.js +101 -111
  132. package/dist/utils/md5.d.ts +4 -0
  133. package/dist/utils/md5.js +79 -0
  134. package/dist/utils/pdf-object-manager.d.ts +18 -6
  135. package/dist/utils/pdf-object-manager.js +0 -0
  136. package/dist/utils/renderer-registry.js +1 -5
  137. package/dist/utils/ttf-parser.d.ts +2 -2
  138. package/dist/utils/ttf-parser.js +32 -36
  139. package/dist/utils/ttf-subsetter.d.ts +1 -1
  140. package/dist/utils/ttf-subsetter.js +40 -42
  141. package/dist/utils/utf8-to-windows1252-encoder.js +1 -4
  142. package/dist/validators/element-validator.d.ts +2 -2
  143. package/dist/validators/element-validator.js +9 -13
  144. package/package.json +14 -2
@@ -1,5 +1,7 @@
1
- import type { PDFConfig } from "../renderer/pdf-document-class";
2
- import type { FontMetrics } from "./font-metrics";
1
+ import type { OverflowPolicy } from "../layout/fragmentation.js";
2
+ import type { SecurityHandler } from "../crypto/security-handler.js";
3
+ import type { PDFConfig } from "../renderer/pdf-document-class.js";
4
+ import type { FontMetrics } from "./font-metrics.js";
3
5
  interface FontIndexes {
4
6
  fontIndex: number;
5
7
  resourceIndex: number;
@@ -30,10 +32,18 @@ export declare class PDFObjectManager implements FontMetrics {
30
32
  private pdfVersion;
31
33
  private documentId;
32
34
  private compress;
35
+ private overflowPolicy;
36
+ private security?;
37
+ private encJobs;
38
+ private encryptObjNum?;
33
39
  constructor();
34
40
  addObject(content: string): number;
35
41
  replaceObject(objectNumber: number, content: string): void;
36
42
  setCompress(on: boolean): void;
43
+ setOverflowPolicy(policy: OverflowPolicy): void;
44
+ getOverflowPolicy(): OverflowPolicy;
45
+ private encToken;
46
+ private streamPayload;
37
47
  private stream;
38
48
  addContentStream(content: string): number;
39
49
  changePDFConfig(config: PDFConfig): void;
@@ -42,8 +52,8 @@ export declare class PDFObjectManager implements FontMetrics {
42
52
  private getCurrentByteLength;
43
53
  setParentObjectNumber(number: number): void;
44
54
  getParentObjectNumber(): number;
45
- registerImage(width: number, height: number, imageType: string, imageData: string): number;
46
- attachFile(name: string, data: Buffer, opts?: {
55
+ registerImage(width: number, height: number, imageType: string, imageData: string, smaskData?: string): number;
56
+ attachFile(name: string, data: Uint8Array, opts?: {
47
57
  relationship?: string;
48
58
  mimeType?: string;
49
59
  description?: string;
@@ -54,7 +64,7 @@ export declare class PDFObjectManager implements FontMetrics {
54
64
  }[];
55
65
  setXmpMetadata(xml: string): void;
56
66
  getXmpMetadata(): string | undefined;
57
- setOutputIntent(icc: Buffer, opts?: {
67
+ setOutputIntent(icc: Uint8Array, opts?: {
58
68
  identifier?: string;
59
69
  info?: string;
60
70
  }): void;
@@ -63,10 +73,12 @@ export declare class PDFObjectManager implements FontMetrics {
63
73
  getPdfVersion(): string;
64
74
  getHeader(): string;
65
75
  enableDocumentId(): void;
76
+ setSecurityHandler(handler: SecurityHandler): void;
77
+ finalizeEncryption(): Promise<void>;
66
78
  registerExtGState(fillAlpha: number, strokeAlpha: number): string;
67
79
  getAllExtGStatesRaw(): Map<string, number>;
68
80
  registerFont(fontName: string, fontStyle?: FontStyle, fullName?: string): FontIndexes;
69
- registerCustomFont(name: string, data: Buffer, style?: FontStyle): void;
81
+ registerCustomFont(name: string, data: Uint8Array, style?: FontStyle): void;
70
82
  private ensureEmitted;
71
83
  finalizeCustomFonts(): void;
72
84
  private subsetTag;
Binary file
@@ -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;
@@ -1,32 +1,30 @@
1
- "use strict";
2
1
  // Builds a subset TrueType font that KEEPS the original glyph ids: the PDF content stream emits
3
2
  // original gids and /W + CIDToGIDMap=Identity stay valid, so only the font program shrinks. We drop
4
3
  // the `glyf` outlines of unused glyphs (the bulk of the file) and rebuild `loca`; every other table
5
4
  // is copied verbatim. The used-glyph set is closed over composite-glyph components first, so a glyph
6
5
  // built from others (e.g. "ä") keeps its parts. Fonts without `glyf`/`loca` (CFF/OTF) pass through.
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.subsetTTF = subsetTTF;
9
- const u32 = (n) => n >>> 0;
6
+ import { concatBytes, i16, latin1FromBytes, u16, u32, wi16, wu16, wu32, writeLatin1, } from "./bytes.js";
7
+ const wrap32 = (n) => n >>> 0;
10
8
  /** TrueType table checksum: sum of big-endian uint32 over the 4-byte-padded table data. */
11
9
  function checksum(buf) {
12
10
  let sum = 0;
13
11
  for (let i = 0; i < buf.length; i += 4)
14
- sum = u32(sum + buf.readUInt32BE(i));
12
+ sum = wrap32(sum + u32(buf, i));
15
13
  return sum;
16
14
  }
17
15
  /** Right-pad to a 4-byte boundary (table data is aligned in the sfnt). */
18
16
  function pad4(buf) {
19
17
  const rem = buf.length % 4;
20
- return rem === 0 ? buf : Buffer.concat([buf, Buffer.alloc(4 - rem)]);
18
+ return rem === 0 ? buf : concatBytes([buf, new Uint8Array(4 - rem)]);
21
19
  }
22
- function subsetTTF(data, used) {
23
- const numTables = data.readUInt16BE(4);
20
+ export function subsetTTF(data, used) {
21
+ const numTables = u16(data, 4);
24
22
  const dir = new Map();
25
23
  let p = 12;
26
24
  for (let i = 0; i < numTables; i++) {
27
- dir.set(data.toString("latin1", p, p + 4), {
28
- offset: data.readUInt32BE(p + 8),
29
- length: data.readUInt32BE(p + 12),
25
+ dir.set(latin1FromBytes(data.subarray(p, p + 4)), {
26
+ offset: u32(data, p + 8),
27
+ length: u32(data, p + 12),
30
28
  });
31
29
  p += 16;
32
30
  }
@@ -34,14 +32,14 @@ function subsetTTF(data, used) {
34
32
  if (!dir.has("glyf") || !dir.has("loca") || !dir.has("head") || !dir.has("maxp"))
35
33
  return data;
36
34
  const headOff = dir.get("head").offset;
37
- const longLoca = data.readInt16BE(headOff + 50) === 1;
38
- const numGlyphs = data.readUInt16BE(dir.get("maxp").offset + 4);
35
+ const longLoca = i16(data, headOff + 50) === 1;
36
+ const numGlyphs = u16(data, dir.get("maxp").offset + 4);
39
37
  const locaOff = dir.get("loca").offset;
40
38
  const glyfOff = dir.get("glyf").offset;
41
39
  // Original glyph offsets (numGlyphs + 1 entries; short loca stores half-offsets).
42
40
  const loca = [];
43
41
  for (let g = 0; g <= numGlyphs; g++) {
44
- loca.push(longLoca ? data.readUInt32BE(locaOff + g * 4) : data.readUInt16BE(locaOff + g * 2) * 2);
42
+ loca.push(longLoca ? u32(data, locaOff + g * 4) : u16(data, locaOff + g * 2) * 2);
45
43
  }
46
44
  const glyphBytes = (g) => data.subarray(glyfOff + loca[g], glyfOff + loca[g + 1]);
47
45
  // Close the used set over composite components (and always keep .notdef = gid 0).
@@ -53,12 +51,12 @@ function subsetTTF(data, used) {
53
51
  continue;
54
52
  keep.add(g);
55
53
  const gd = glyphBytes(g);
56
- if (gd.length >= 10 && gd.readInt16BE(0) < 0) {
54
+ if (gd.length >= 10 && i16(gd, 0) < 0) {
57
55
  // Composite glyph: walk the component records to collect the referenced gids.
58
56
  let q = 10; // numberOfContours(2) + xMin/yMin/xMax/yMax(8)
59
57
  for (;;) {
60
- const flags = gd.readUInt16BE(q);
61
- stack.push(gd.readUInt16BE(q + 2));
58
+ const flags = u16(gd, q);
59
+ stack.push(u16(gd, q + 2));
62
60
  q += 4 + (flags & 0x0001 ? 4 : 2); // ARG_1_AND_2_ARE_WORDS
63
61
  if (flags & 0x0008)
64
62
  q += 2; // WE_HAVE_A_SCALE
@@ -73,24 +71,24 @@ function subsetTTF(data, used) {
73
71
  }
74
72
  // Rebuild glyf (kept glyphs only, original numbering) + a long-format loca.
75
73
  const parts = [];
76
- const newLoca = Buffer.alloc((numGlyphs + 1) * 4);
74
+ const newLoca = new Uint8Array((numGlyphs + 1) * 4);
77
75
  let off = 0;
78
76
  for (let g = 0; g < numGlyphs; g++) {
79
- newLoca.writeUInt32BE(off, g * 4);
77
+ wu32(newLoca, off, g * 4);
80
78
  if (keep.has(g)) {
81
- let gd = Buffer.from(glyphBytes(g));
79
+ let gd = glyphBytes(g).slice(); // copy: padded + concatenated, must not view `data`
82
80
  if (gd.length % 2 === 1)
83
- gd = Buffer.concat([gd, Buffer.alloc(1)]); // keep offsets even
81
+ gd = concatBytes([gd, new Uint8Array(1)]); // keep offsets even
84
82
  parts.push(gd);
85
83
  off += gd.length;
86
84
  }
87
85
  }
88
- newLoca.writeUInt32BE(off, numGlyphs * 4);
89
- const newGlyf = Buffer.concat(parts);
86
+ wu32(newLoca, off, numGlyphs * 4);
87
+ const newGlyf = concatBytes(parts);
90
88
  // head copy with indexToLocFormat = 1 (long); checkSumAdjustment zeroed, fixed up at the end.
91
- const newHead = Buffer.from(data.subarray(headOff, headOff + dir.get("head").length));
92
- newHead.writeInt16BE(1, 50);
93
- newHead.writeUInt32BE(0, 8);
89
+ const newHead = data.slice(headOff, headOff + dir.get("head").length);
90
+ wi16(newHead, 1, 50);
91
+ wu32(newHead, 0, 8);
94
92
  // Tables a PDF-embedded CIDFontType2 doesn't need - layout (GSUB/GPOS…), hinting hints and the
95
93
  // signature are dead weight; dropping them is most of the size win. `post` is reduced to format 3
96
94
  // (header only, no glyph names). cmap/name/OS-2 are kept for a still-valid standalone font.
@@ -119,8 +117,8 @@ function subsetTTF(data, used) {
119
117
  body = newHead;
120
118
  else if (tag === "post") {
121
119
  // Keep the 32-byte header, force version 3.0 (drops the per-glyph name list).
122
- body = Buffer.from(data.subarray(dir.get("post").offset, dir.get("post").offset + 32));
123
- body.writeUInt32BE(0x00030000, 0);
120
+ body = data.slice(dir.get("post").offset, dir.get("post").offset + 32);
121
+ wu32(body, 0x00030000, 0);
124
122
  }
125
123
  else {
126
124
  const d = dir.get(tag);
@@ -132,30 +130,30 @@ function subsetTTF(data, used) {
132
130
  const n = tables.length;
133
131
  const maxPow2 = 1 << Math.floor(Math.log2(n));
134
132
  const out = [];
135
- const offsetTable = Buffer.alloc(12);
136
- offsetTable.writeUInt32BE(data.readUInt32BE(0), 0); // sfntVersion
137
- offsetTable.writeUInt16BE(n, 4);
138
- offsetTable.writeUInt16BE(maxPow2 * 16, 6); // searchRange
139
- offsetTable.writeUInt16BE(Math.floor(Math.log2(n)), 8); // entrySelector
140
- offsetTable.writeUInt16BE(n * 16 - maxPow2 * 16, 10); // rangeShift
133
+ const offsetTable = new Uint8Array(12);
134
+ wu32(offsetTable, u32(data, 0), 0); // sfntVersion
135
+ wu16(offsetTable, n, 4);
136
+ wu16(offsetTable, maxPow2 * 16, 6); // searchRange
137
+ wu16(offsetTable, Math.floor(Math.log2(n)), 8); // entrySelector
138
+ wu16(offsetTable, n * 16 - maxPow2 * 16, 10); // rangeShift
141
139
  out.push(offsetTable);
142
- const dirBuf = Buffer.alloc(n * 16);
140
+ const dirBuf = new Uint8Array(n * 16);
143
141
  let tableOffset = 12 + n * 16;
144
142
  const dataBufs = [];
145
143
  tables.forEach((t, i) => {
146
144
  const padded = pad4(t.body);
147
- dirBuf.write(t.tag, i * 16, 4, "latin1");
148
- dirBuf.writeUInt32BE(checksum(padded), i * 16 + 4);
149
- dirBuf.writeUInt32BE(tableOffset, i * 16 + 8);
150
- dirBuf.writeUInt32BE(t.length, i * 16 + 12); // real (unpadded) length
145
+ writeLatin1(dirBuf, t.tag, i * 16);
146
+ wu32(dirBuf, checksum(padded), i * 16 + 4);
147
+ wu32(dirBuf, tableOffset, i * 16 + 8);
148
+ wu32(dirBuf, t.length, i * 16 + 12); // real (unpadded) length
151
149
  tableOffset += padded.length;
152
150
  dataBufs.push(padded);
153
151
  });
154
152
  out.push(dirBuf, ...dataBufs);
155
- const font = Buffer.concat(out);
153
+ const font = concatBytes(out);
156
154
  // head.checkSumAdjustment = 0xB1B0AFBA - checksum(whole font). Locate head in the assembled font.
157
155
  const headIdx = tables.findIndex((t) => t.tag === "head");
158
- const headPos = dirBuf.readUInt32BE(headIdx * 16 + 8);
159
- font.writeUInt32BE(u32(0xb1b0afba - checksum(font)), headPos + 8);
156
+ const headPos = u32(dirBuf, headIdx * 16 + 8);
157
+ wu32(font, wrap32(0xb1b0afba - checksum(font)), headPos + 8);
160
158
  return font;
161
159
  }
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getArrayBuffer = getArrayBuffer;
4
1
  // Windows-1252 equals Latin-1 (codepoint == byte) EXCEPT in 0x80-0x9F, where it carries
5
2
  // printable punctuation - the Euro sign, smart quotes, dashes, ellipsis, ... - instead of
6
3
  // C1 controls. Those glyphs sit at Unicode codepoints far outside 0x00-0xFF, so a naive
@@ -37,7 +34,7 @@ const CP1252_FROM_UNICODE = {
37
34
  0x0178: 0x9f, // Ÿ Y diaeresis
38
35
  };
39
36
  /** Encodes a JavaScript string to a Windows-1252 byte buffer (the PDF text encoding). */
40
- function getArrayBuffer(data) {
37
+ export function getArrayBuffer(data) {
41
38
  const u8 = new Uint8Array(data.length);
42
39
  for (let i = 0; i < data.length; i++) {
43
40
  const code = data.charCodeAt(i);
@@ -1,5 +1,5 @@
1
- import { PDFDocumentElement } from "../elements/pdf-document-element";
2
- import { PDFElement, FlexiblePDFElement, SizedPDFElement } from "../elements/pdf-element";
1
+ import { PDFDocumentElement } from "../elements/pdf-document-element.js";
2
+ import { PDFElement, FlexiblePDFElement, SizedPDFElement } from "../elements/pdf-element.js";
3
3
  export declare class Validator {
4
4
  static validateDocument(document: PDFDocumentElement): void;
5
5
  static validateElement(element: PDFElement): void;
@@ -1,14 +1,11 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Validator = void 0;
4
- const pdf_document_element_1 = require("../elements/pdf-document-element");
5
- const pdf_element_1 = require("../elements/pdf-element");
6
- class Validator {
1
+ import { PDFDocumentElement } from "../elements/pdf-document-element.js";
2
+ import { FlexiblePDFElement, hasChildProp, SizedPDFElement, } from "../elements/pdf-element.js";
3
+ export class Validator {
7
4
  static validateDocument(document) {
8
5
  // More validation will be added later...
9
6
  document.getProps().children.forEach((page) => {
10
7
  page.getProps().children.forEach((element) => {
11
- if (element instanceof pdf_document_element_1.PDFDocumentElement) {
8
+ if (element instanceof PDFDocumentElement) {
12
9
  throw new Error("PDFDocument cannot be nested inside another element.");
13
10
  }
14
11
  });
@@ -16,11 +13,11 @@ class Validator {
16
13
  }
17
14
  static validateElement(element) {
18
15
  // Structural validation
19
- if (element instanceof pdf_document_element_1.PDFDocumentElement) {
16
+ if (element instanceof PDFDocumentElement) {
20
17
  throw new Error("PDFDocument cannot be nested inside another element.");
21
18
  }
22
19
  // Layout validation: geometry comes from the typed getSize(), not the props bag.
23
- if (element instanceof pdf_element_1.SizedPDFElement) {
20
+ if (element instanceof SizedPDFElement) {
24
21
  const { width, height } = element.getSize();
25
22
  // Negative coordinates are allowed: a `Positioned` child overflows its frame on purpose,
26
23
  // and the page clips anything past its edge. 0 size is legitimate (a hairline divider, an
@@ -30,7 +27,7 @@ class Validator {
30
27
  }
31
28
  }
32
29
  // Logical validation: Flexible and fixed elements
33
- if (element instanceof pdf_element_1.FlexiblePDFElement) {
30
+ if (element instanceof FlexiblePDFElement) {
34
31
  this.validateFlexElement(element);
35
32
  }
36
33
  }
@@ -49,11 +46,10 @@ class Validator {
49
46
  throw new Error(`Flexible element ${element.constructor.name} has invalid flex value`);
50
47
  }
51
48
  // Ensure a flexible element does not contain another flexible element
52
- if ((0, pdf_element_1.hasChildProp)(element)) {
53
- if (element.child instanceof pdf_element_1.FlexiblePDFElement) {
49
+ if (hasChildProp(element)) {
50
+ if (element.child instanceof FlexiblePDFElement) {
54
51
  throw new Error(`Flexible element ${element.constructor.name} cannot hold another flexible element`);
55
52
  }
56
53
  }
57
54
  }
58
55
  }
59
- exports.Validator = Validator;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jasy/pdf",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.4",
4
4
  "description": "Declarative, component-based PDF generation in pure TypeScript - Flutter-style components, real AFM font metrics, a hand-rolled PDF writer. No headless browser, no Java.",
5
5
  "keywords": [
6
6
  "declarative",
@@ -19,9 +19,21 @@
19
19
  "files": [
20
20
  "dist"
21
21
  ],
22
+ "type": "module",
22
23
  "main": "dist/index.js",
24
+ "browser": {
25
+ "./dist/platform/node-fs.js": "./dist/platform/browser-fs.js",
26
+ "./dist/platform/node-image.js": "./dist/platform/browser-image.js"
27
+ },
23
28
  "types": "dist/index.d.ts",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/index.d.ts",
32
+ "default": "./dist/index.js"
33
+ }
34
+ },
24
35
  "dependencies": {
36
+ "fflate": "^0.8.3",
25
37
  "jimp": "^1.6.0"
26
38
  },
27
39
  "devDependencies": {
@@ -41,7 +53,7 @@
41
53
  "play": "pnpm --filter @jasy/playground play",
42
54
  "test": "vitest",
43
55
  "test:coverage": "vitest --coverage",
44
- "build": "tsc && pnpm run copy-assets",
56
+ "build": "tsc && node scripts/fix-dts-ext.mjs && pnpm run copy-assets",
45
57
  "lint": "oxlint",
46
58
  "lint:fix": "oxlint --fix",
47
59
  "fmt": "oxfmt",