pdf-parser.js 5.2.27 → 5.2.29

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 (145) hide show
  1. package/dist/{afm-widths-BYiX2L9D.cjs → afm-widths-BHD2HZIL.cjs} +553 -642
  2. package/dist/{afm-widths-blUDDjlI.js → afm-widths-B_IGbGky.js} +553 -642
  3. package/dist/afm-widths.cjs +1 -1
  4. package/dist/afm-widths.js +1 -1
  5. package/dist/annotations.cjs +5 -3
  6. package/dist/annotations.js +5 -3
  7. package/dist/builtin-encoding.cjs +17 -6
  8. package/dist/builtin-encoding.js +17 -6
  9. package/dist/bytes/crc32.cjs +5 -3
  10. package/dist/bytes/crc32.js +5 -3
  11. package/dist/bytes/flate.cjs +0 -1
  12. package/dist/bytes/flate.js +0 -1
  13. package/dist/cff-bounds.cjs +42 -24
  14. package/dist/cff-bounds.js +42 -24
  15. package/dist/cff.cjs +13 -6
  16. package/dist/cff.js +13 -6
  17. package/dist/cmap-table.cjs +54 -26
  18. package/dist/cmap-table.js +54 -26
  19. package/dist/cmap.cjs +5 -3
  20. package/dist/cmap.js +5 -3
  21. package/dist/content-write.cjs +3 -2
  22. package/dist/content-write.js +3 -2
  23. package/dist/crypto/aes.cjs +76 -55
  24. package/dist/crypto/aes.js +76 -55
  25. package/dist/crypto/md5.cjs +345 -149
  26. package/dist/crypto/md5.js +345 -149
  27. package/dist/crypto/rc4.cjs +5 -4
  28. package/dist/crypto/rc4.js +5 -4
  29. package/dist/crypto/sha2.cjs +92 -43
  30. package/dist/crypto/sha2.js +92 -43
  31. package/dist/embedded-font.cjs +4 -2
  32. package/dist/embedded-font.js +4 -2
  33. package/dist/encoding.cjs +1 -1
  34. package/dist/encoding.js +1 -1
  35. package/dist/encrypt-write.cjs +25 -21
  36. package/dist/encrypt-write.js +25 -21
  37. package/dist/encrypt.cjs +43 -64
  38. package/dist/encrypt.js +43 -64
  39. package/dist/filters.cjs +40 -20
  40. package/dist/filters.js +40 -20
  41. package/dist/font-face.cjs +2 -1
  42. package/dist/font-face.js +2 -1
  43. package/dist/font-read.cjs +12 -6
  44. package/dist/font-read.js +12 -6
  45. package/dist/font-tables.cjs +55 -28
  46. package/dist/font-tables.js +55 -28
  47. package/dist/gdef-table.cjs +6 -3
  48. package/dist/gdef-table.js +6 -3
  49. package/dist/glyf-contours.cjs +3 -1
  50. package/dist/glyf-contours.js +3 -1
  51. package/dist/glyf.cjs +22 -11
  52. package/dist/glyf.js +22 -11
  53. package/dist/gpos-table.cjs +37 -19
  54. package/dist/gpos-table.js +37 -19
  55. package/dist/gsub-table.cjs +28 -17
  56. package/dist/gsub-table.js +28 -17
  57. package/dist/hmtx-table.cjs +5 -3
  58. package/dist/hmtx-table.js +5 -3
  59. package/dist/image/ccitt-encode.cjs +8 -5
  60. package/dist/image/ccitt-encode.js +8 -5
  61. package/dist/image/ccitt.cjs +801 -209
  62. package/dist/image/ccitt.js +801 -209
  63. package/dist/image/jbig2-arith.cjs +340 -306
  64. package/dist/image/jbig2-arith.js +340 -306
  65. package/dist/image/jbig2-bitmap.cjs +8 -5
  66. package/dist/image/jbig2-bitmap.js +8 -5
  67. package/dist/image/jbig2-generic.cjs +240 -69
  68. package/dist/image/jbig2-generic.js +240 -69
  69. package/dist/image/jbig2-text.cjs +4 -2
  70. package/dist/image/jbig2-text.js +4 -2
  71. package/dist/image/jbig2.cjs +69 -31
  72. package/dist/image/jbig2.js +69 -31
  73. package/dist/image/jp2-boxes.cjs +52 -27
  74. package/dist/image/jp2-boxes.js +52 -27
  75. package/dist/image/jpeg-info.cjs +29 -24
  76. package/dist/image/jpeg-info.js +29 -24
  77. package/dist/image/jpeg2000-codestream.cjs +44 -24
  78. package/dist/image/jpeg2000-codestream.js +44 -24
  79. package/dist/image/jpeg2000-dwt.cjs +2 -1
  80. package/dist/image/jpeg2000-dwt.js +2 -1
  81. package/dist/image/jpeg2000-t1.cjs +21 -11
  82. package/dist/image/jpeg2000-t1.js +21 -11
  83. package/dist/image/jpeg2000-t2.cjs +12 -5
  84. package/dist/image/jpeg2000-t2.js +12 -5
  85. package/dist/image/jpeg2000-tagtree.cjs +8 -4
  86. package/dist/image/jpeg2000-tagtree.js +8 -4
  87. package/dist/image/jpeg2000.cjs +11 -6
  88. package/dist/image/jpeg2000.js +11 -6
  89. package/dist/image/png-decode.cjs +62 -39
  90. package/dist/image/png-decode.d.cts +3 -2
  91. package/dist/image/png-decode.d.ts +3 -2
  92. package/dist/image/png-decode.js +62 -39
  93. package/dist/image/png-filter.cjs +23 -15
  94. package/dist/image/png-filter.js +23 -15
  95. package/dist/images-read.cjs +41 -36
  96. package/dist/images-read.js +41 -36
  97. package/dist/index.cjs +1 -1
  98. package/dist/index.js +1 -1
  99. package/dist/interpret.cjs +39 -24
  100. package/dist/interpret.js +39 -24
  101. package/dist/lexer.cjs +86 -51
  102. package/dist/lexer.js +86 -51
  103. package/dist/math-content-write.cjs +9 -5
  104. package/dist/math-content-write.js +9 -5
  105. package/dist/math-font-write.cjs +2 -1
  106. package/dist/math-font-write.js +2 -1
  107. package/dist/math-font.cjs +16 -7
  108. package/dist/math-font.js +16 -7
  109. package/dist/math-table.cjs +25 -13
  110. package/dist/math-table.js +25 -13
  111. package/dist/matrix.cjs +3 -2
  112. package/dist/matrix.js +3 -2
  113. package/dist/measure.cjs +1 -1
  114. package/dist/measure.js +1 -1
  115. package/dist/navigation.cjs +10 -5
  116. package/dist/navigation.js +10 -5
  117. package/dist/ot-layout-common.cjs +4 -2
  118. package/dist/ot-layout-common.js +4 -2
  119. package/dist/parse.cjs +7 -5
  120. package/dist/parse.js +7 -5
  121. package/dist/pdf-text.cjs +5 -2
  122. package/dist/pdf-text.js +5 -2
  123. package/dist/predictors.cjs +14 -9
  124. package/dist/predictors.js +14 -9
  125. package/dist/raster.cjs +30 -19
  126. package/dist/raster.js +30 -19
  127. package/dist/read.cjs +17 -8
  128. package/dist/read.js +17 -8
  129. package/dist/serialize.cjs +6 -2
  130. package/dist/serialize.js +6 -2
  131. package/dist/sfnt-subset.cjs +25 -13
  132. package/dist/sfnt-subset.js +25 -13
  133. package/dist/sfnt.cjs +20 -10
  134. package/dist/sfnt.js +20 -10
  135. package/dist/text-group.cjs +0 -1
  136. package/dist/text-group.js +0 -1
  137. package/dist/tounicode.cjs +4 -2
  138. package/dist/tounicode.js +4 -2
  139. package/dist/winansi.cjs +1 -1
  140. package/dist/winansi.js +1 -1
  141. package/dist/write.cjs +20 -12
  142. package/dist/write.js +20 -12
  143. package/dist/xref.cjs +5 -2
  144. package/dist/xref.js +5 -2
  145. package/package.json +2 -2
package/dist/raster.cjs CHANGED
@@ -17,13 +17,16 @@ const require_read = require("./read.cjs");
17
17
  const require_glyf = require("./glyf.cjs");
18
18
  const require_glyf_contours = require("./glyf-contours.cjs");
19
19
  //#region src/raster.ts
20
+ const PIXEL_ROUNDING_EPSILON = 1e-9;
21
+ const POINTS_PER_INCH = 72;
22
+ const EXTENT_ZERO_EPSILON = 1e-9;
20
23
  function regionPixels(extentPt, scale) {
21
- return Math.max(1, Math.ceil(extentPt * scale - 1e-9));
24
+ return Math.max(1, Math.ceil(extentPt * scale - PIXEL_ROUNDING_EPSILON));
22
25
  }
23
26
  function renderPdfPage(pdfBytes, pageIndex, options, rasteriser) {
24
27
  const sink = options.sink ?? require_diagnostics.NOOP_DIAGNOSTIC_SINK;
25
28
  if (options.scale !== void 0 && options.dpi !== void 0) throw new Error("renderPdfPage accepts at most one of scale and dpi; they name the same factor in different units (dpi = 72 x scale)");
26
- const scale = options.dpi !== void 0 ? options.dpi / 72 : options.scale;
29
+ const scale = options.dpi !== void 0 ? options.dpi / POINTS_PER_INCH : options.scale;
27
30
  if (scale !== void 0 && !(scale > 0)) throw new Error(`renderPdfPage requires a positive scale factor (received scale ${options.scale}, dpi ${options.dpi})`);
28
31
  const pixelsPerPt = scale ?? 1;
29
32
  if (options.clipPt !== void 0 && (!(options.clipPt.widthPt > 0) || !(options.clipPt.heightPt > 0))) throw new Error("renderPdfPage clipPt must carry positive widthPt and heightPt; a zero-extent region has no pixels to render");
@@ -195,6 +198,7 @@ function drawRect(item, matrix, pixelsPerPt, rasteriser) {
195
198
  stroke: strokeSpec(item.stroke, void 0, pixelsPerPt)
196
199
  });
197
200
  }
201
+ const ELLIPSE_QUADRANT_COUNT = 4;
198
202
  function drawEllipse(item, matrix, pixelsPerPt, rasteriser) {
199
203
  const cx = item.xPt + item.widthPt / 2;
200
204
  const cy = item.yPt + item.heightPt / 2;
@@ -224,8 +228,8 @@ function drawEllipse(item, matrix, pixelsPerPt, rasteriser) {
224
228
  });
225
229
  const start = transformed(cardinalPoints[0]);
226
230
  const segments = [];
227
- for (let i = 0; i < 4; i++) {
228
- const end = transformed(cardinalPoints[(i + 1) % 4]);
231
+ for (let i = 0; i < ELLIPSE_QUADRANT_COUNT; i++) {
232
+ const end = transformed(cardinalPoints[(i + 1) % ELLIPSE_QUADRANT_COUNT]);
229
233
  const c1 = transformed(controls[i * 2]);
230
234
  const c2 = transformed(controls[i * 2 + 1]);
231
235
  segments.push({
@@ -402,12 +406,13 @@ function drawImage(image, ctm, interpretToDeviceMatrix, rasteriser) {
402
406
  matrix
403
407
  });
404
408
  }
409
+ const DASHED_STROKE_WIDTH_MULTIPLE = 3;
405
410
  function strokeSpec(stroke, style, pixelsPerPt) {
406
411
  const widthPx = stroke.widthPt * pixelsPerPt;
407
412
  if (style === "dashed") return {
408
413
  color: stroke.color,
409
414
  widthPx,
410
- dashPx: [widthPx * 3, widthPx * 3]
415
+ dashPx: [widthPx * DASHED_STROKE_WIDTH_MULTIPLE, widthPx * DASHED_STROKE_WIDTH_MULTIPLE]
411
416
  };
412
417
  return {
413
418
  color: stroke.color,
@@ -475,6 +480,7 @@ function flattenCubic(p0, c1, c2, p1) {
475
480
  flatten(p0, c1, c2, p1, 0);
476
481
  return points;
477
482
  }
483
+ const CFF_HEADER_SIZE = 4;
478
484
  function openEmbeddedProgram(descriptorOwner, resolver) {
479
485
  const descriptor = resolver.resolveDict(require_objects.dictGet(descriptorOwner, "FontDescriptor"));
480
486
  if (descriptor === void 0) return { kind: "absent" };
@@ -482,7 +488,7 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
482
488
  const stream = resolver.resolve(require_objects.dictGet(descriptor, key));
483
489
  if (stream?.kind !== "stream") continue;
484
490
  const bytes = require_filters.decodeStream(stream.raw, stream.dict, require_diagnostics.NOOP_DIAGNOSTIC_SINK).bytes;
485
- if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
491
+ if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === CFF_HEADER_SIZE) return { kind: "cff" };
486
492
  const sfnt = require_sfnt.parseSfnt(bytes);
487
493
  if (sfnt === void 0) continue;
488
494
  if (sfnt.tables.has("CFF ")) return { kind: "cff" };
@@ -514,6 +520,7 @@ function resolveTextOutlineFace(fontResourceName, resources, resolver, fontResol
514
520
  outlineFaces.set(fontDict, face);
515
521
  return face;
516
522
  }
523
+ const BITS_PER_BYTE = 8;
517
524
  function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName, resources, sink) {
518
525
  const faceName = require_objects.asName(require_objects.dictGet(fontDict, "BaseFont")) ?? require_objects.asName(require_objects.dictGet(fontDict, "Subtype")) ?? "font";
519
526
  const unavailable = (reason) => {
@@ -548,12 +555,12 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
548
555
  if (cidToGidMap?.kind === "stream") {
549
556
  const decodedBytes = require_filters.decodeStream(cidToGidMap.raw, cidToGidMap.dict, require_diagnostics.NOOP_DIAGNOSTIC_SINK).bytes;
550
557
  const entries = [];
551
- for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << 8 | decodedBytes[i + 1]);
558
+ for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << BITS_PER_BYTE | decodedBytes[i + 1]);
552
559
  return {
553
560
  glyf: program.face.glyf,
554
561
  unitsPerEm: program.face.unitsPerEm,
555
562
  glyphIdOf: (codes, offset) => {
556
- const cid = codes[offset] << 8 | codes[offset + 1];
563
+ const cid = codes[offset] << BITS_PER_BYTE | codes[offset + 1];
557
564
  return entries[cid];
558
565
  }
559
566
  };
@@ -561,7 +568,7 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
561
568
  return {
562
569
  glyf: program.face.glyf,
563
570
  unitsPerEm: program.face.unitsPerEm,
564
- glyphIdOf: (codes, offset) => codes[offset] << 8 | codes[offset + 1]
571
+ glyphIdOf: (codes, offset) => codes[offset] << BITS_PER_BYTE | codes[offset + 1]
565
572
  };
566
573
  }
567
574
  if (subtype === "TrueType") {
@@ -585,6 +592,7 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
585
592
  }
586
593
  return unavailable(`a font of subtype ${subtype ?? "(none)"} (a Type3 glyph-procedure font has no static outline at all)`);
587
594
  }
595
+ const METRICS_PER_1000_SCALE = 1e3;
588
596
  function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDeviceMatrix, rasteriser, sink) {
589
597
  const face = resolveTextOutlineFace(item.fontResourceName, item.resources, resolver, fontResolver, outlineFaces, sink);
590
598
  if (face === void 0) return;
@@ -597,10 +605,10 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
597
605
  placements.push({
598
606
  glyphId: face.glyphIdOf(item.codes, offset),
599
607
  advance: cumulative,
600
- positionX: (advance.vertical?.positionXPer1000 ?? 0) / 1e3,
601
- positionY: (advance.vertical?.positionYPer1000 ?? 0) / 1e3
608
+ positionX: (advance.vertical?.positionXPer1000 ?? 0) / METRICS_PER_1000_SCALE,
609
+ positionY: (advance.vertical?.positionYPer1000 ?? 0) / METRICS_PER_1000_SCALE
602
610
  });
603
- cumulative += (advance.vertical?.displacementPer1000 ?? advance.widthPer1000) / 1e3 * item.sizePt;
611
+ cumulative += (advance.vertical?.displacementPer1000 ?? advance.widthPer1000) / METRICS_PER_1000_SCALE * item.sizePt;
604
612
  offset += byteLength;
605
613
  }
606
614
  const startDeviceMatrix = require_matrix.multiplyMatrices(item.startMatrix, interpretToDeviceMatrix);
@@ -623,7 +631,7 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
623
631
  });
624
632
  const rawExtent = Math.hypot(rawEndPoint.x - startPoint.x, rawEndPoint.y - startPoint.y);
625
633
  const actualExtent = Math.hypot(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
626
- const correction = rawExtent > 1e-9 ? actualExtent / rawExtent : 1;
634
+ const correction = rawExtent > EXTENT_ZERO_EPSILON ? actualExtent / rawExtent : 1;
627
635
  const firstPlacement = placements[0];
628
636
  const glyphScale = require_matrix.scaleMatrix(1 / face.unitsPerEm, 1 / face.unitsPerEm);
629
637
  for (const placement of placements) {
@@ -646,10 +654,12 @@ function drawGlyphOutline(outline, glyphMatrix, color, rasteriser) {
646
654
  }
647
655
  });
648
656
  }
657
+ const MIN_CONTOUR_POINTS = 3;
658
+ const QUADRATIC_TO_CUBIC_CONTROL_FRACTION = 2 / 3;
649
659
  function glyphOutlineSubpaths(outline, matrix) {
650
660
  const subpaths = [];
651
661
  for (const contour of outline.contours) {
652
- if (contour.length < 3) continue;
662
+ if (contour.length < MIN_CONTOUR_POINTS) continue;
653
663
  const firstOn = contour.findIndex((point) => point.onCurve);
654
664
  const contourPoints = contour.map((point) => ({
655
665
  x: point.x,
@@ -674,10 +684,10 @@ function glyphOutlineSubpaths(outline, matrix) {
674
684
  const p1 = require_matrix.applyMatrix(matrix, to);
675
685
  segments.push({
676
686
  kind: "cubic",
677
- c1xPx: p0.x + 2 / 3 * (q.x - p0.x),
678
- c1yPx: p0.y + 2 / 3 * (q.y - p0.y),
679
- c2xPx: p1.x + 2 / 3 * (q.x - p1.x),
680
- c2yPx: p1.y + 2 / 3 * (q.y - p1.y),
687
+ c1xPx: p0.x + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.x - p0.x),
688
+ c1yPx: p0.y + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.y - p0.y),
689
+ c2xPx: p1.x + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.x - p1.x),
690
+ c2yPx: p1.y + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.y - p1.y),
681
691
  xPx: p1.x,
682
692
  yPx: p1.y
683
693
  });
@@ -765,6 +775,7 @@ function rotatedRectBounds(rect, matrix) {
765
775
  maxY: Math.max(...ys)
766
776
  };
767
777
  }
778
+ const NEWLINE_BYTE = 10;
768
779
  function readPageContentBytes(page, resolver, sink) {
769
780
  const contentsObj = resolver.resolve(require_objects.dictGet(page, "Contents"));
770
781
  if (contentsObj?.kind === "stream") return require_filters.decodeStream(contentsObj.raw, contentsObj.dict, sink).bytes;
@@ -772,7 +783,7 @@ function readPageContentBytes(page, resolver, sink) {
772
783
  const chunks = [];
773
784
  for (const entry of contentsObj.items) {
774
785
  const streamObj = resolver.resolve(entry);
775
- if (streamObj?.kind === "stream") chunks.push(require_filters.decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([10]));
786
+ if (streamObj?.kind === "stream") chunks.push(require_filters.decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([NEWLINE_BYTE]));
776
787
  }
777
788
  return require_bytes_writer.concatBytes(chunks);
778
789
  }
package/dist/raster.js CHANGED
@@ -16,13 +16,16 @@ import { normalizeRotation, pageRotationTransform } from "./read.js";
16
16
  import { parseGlyf } from "./glyf.js";
17
17
  import { decodeGlyphOutline } from "./glyf-contours.js";
18
18
  //#region src/raster.ts
19
+ const PIXEL_ROUNDING_EPSILON = 1e-9;
20
+ const POINTS_PER_INCH = 72;
21
+ const EXTENT_ZERO_EPSILON = 1e-9;
19
22
  function regionPixels(extentPt, scale) {
20
- return Math.max(1, Math.ceil(extentPt * scale - 1e-9));
23
+ return Math.max(1, Math.ceil(extentPt * scale - PIXEL_ROUNDING_EPSILON));
21
24
  }
22
25
  function renderPdfPage(pdfBytes, pageIndex, options, rasteriser) {
23
26
  const sink = options.sink ?? NOOP_DIAGNOSTIC_SINK;
24
27
  if (options.scale !== void 0 && options.dpi !== void 0) throw new Error("renderPdfPage accepts at most one of scale and dpi; they name the same factor in different units (dpi = 72 x scale)");
25
- const scale = options.dpi !== void 0 ? options.dpi / 72 : options.scale;
28
+ const scale = options.dpi !== void 0 ? options.dpi / POINTS_PER_INCH : options.scale;
26
29
  if (scale !== void 0 && !(scale > 0)) throw new Error(`renderPdfPage requires a positive scale factor (received scale ${options.scale}, dpi ${options.dpi})`);
27
30
  const pixelsPerPt = scale ?? 1;
28
31
  if (options.clipPt !== void 0 && (!(options.clipPt.widthPt > 0) || !(options.clipPt.heightPt > 0))) throw new Error("renderPdfPage clipPt must carry positive widthPt and heightPt; a zero-extent region has no pixels to render");
@@ -194,6 +197,7 @@ function drawRect(item, matrix, pixelsPerPt, rasteriser) {
194
197
  stroke: strokeSpec(item.stroke, void 0, pixelsPerPt)
195
198
  });
196
199
  }
200
+ const ELLIPSE_QUADRANT_COUNT = 4;
197
201
  function drawEllipse(item, matrix, pixelsPerPt, rasteriser) {
198
202
  const cx = item.xPt + item.widthPt / 2;
199
203
  const cy = item.yPt + item.heightPt / 2;
@@ -223,8 +227,8 @@ function drawEllipse(item, matrix, pixelsPerPt, rasteriser) {
223
227
  });
224
228
  const start = transformed(cardinalPoints[0]);
225
229
  const segments = [];
226
- for (let i = 0; i < 4; i++) {
227
- const end = transformed(cardinalPoints[(i + 1) % 4]);
230
+ for (let i = 0; i < ELLIPSE_QUADRANT_COUNT; i++) {
231
+ const end = transformed(cardinalPoints[(i + 1) % ELLIPSE_QUADRANT_COUNT]);
228
232
  const c1 = transformed(controls[i * 2]);
229
233
  const c2 = transformed(controls[i * 2 + 1]);
230
234
  segments.push({
@@ -401,12 +405,13 @@ function drawImage(image, ctm, interpretToDeviceMatrix, rasteriser) {
401
405
  matrix
402
406
  });
403
407
  }
408
+ const DASHED_STROKE_WIDTH_MULTIPLE = 3;
404
409
  function strokeSpec(stroke, style, pixelsPerPt) {
405
410
  const widthPx = stroke.widthPt * pixelsPerPt;
406
411
  if (style === "dashed") return {
407
412
  color: stroke.color,
408
413
  widthPx,
409
- dashPx: [widthPx * 3, widthPx * 3]
414
+ dashPx: [widthPx * DASHED_STROKE_WIDTH_MULTIPLE, widthPx * DASHED_STROKE_WIDTH_MULTIPLE]
410
415
  };
411
416
  return {
412
417
  color: stroke.color,
@@ -474,6 +479,7 @@ function flattenCubic(p0, c1, c2, p1) {
474
479
  flatten(p0, c1, c2, p1, 0);
475
480
  return points;
476
481
  }
482
+ const CFF_HEADER_SIZE = 4;
477
483
  function openEmbeddedProgram(descriptorOwner, resolver) {
478
484
  const descriptor = resolver.resolveDict(dictGet(descriptorOwner, "FontDescriptor"));
479
485
  if (descriptor === void 0) return { kind: "absent" };
@@ -481,7 +487,7 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
481
487
  const stream = resolver.resolve(dictGet(descriptor, key));
482
488
  if (stream?.kind !== "stream") continue;
483
489
  const bytes = decodeStream(stream.raw, stream.dict, NOOP_DIAGNOSTIC_SINK).bytes;
484
- if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
490
+ if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === CFF_HEADER_SIZE) return { kind: "cff" };
485
491
  const sfnt = parseSfnt(bytes);
486
492
  if (sfnt === void 0) continue;
487
493
  if (sfnt.tables.has("CFF ")) return { kind: "cff" };
@@ -513,6 +519,7 @@ function resolveTextOutlineFace(fontResourceName, resources, resolver, fontResol
513
519
  outlineFaces.set(fontDict, face);
514
520
  return face;
515
521
  }
522
+ const BITS_PER_BYTE = 8;
516
523
  function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName, resources, sink) {
517
524
  const faceName = asName(dictGet(fontDict, "BaseFont")) ?? asName(dictGet(fontDict, "Subtype")) ?? "font";
518
525
  const unavailable = (reason) => {
@@ -547,12 +554,12 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
547
554
  if (cidToGidMap?.kind === "stream") {
548
555
  const decodedBytes = decodeStream(cidToGidMap.raw, cidToGidMap.dict, NOOP_DIAGNOSTIC_SINK).bytes;
549
556
  const entries = [];
550
- for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << 8 | decodedBytes[i + 1]);
557
+ for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << BITS_PER_BYTE | decodedBytes[i + 1]);
551
558
  return {
552
559
  glyf: program.face.glyf,
553
560
  unitsPerEm: program.face.unitsPerEm,
554
561
  glyphIdOf: (codes, offset) => {
555
- const cid = codes[offset] << 8 | codes[offset + 1];
562
+ const cid = codes[offset] << BITS_PER_BYTE | codes[offset + 1];
556
563
  return entries[cid];
557
564
  }
558
565
  };
@@ -560,7 +567,7 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
560
567
  return {
561
568
  glyf: program.face.glyf,
562
569
  unitsPerEm: program.face.unitsPerEm,
563
- glyphIdOf: (codes, offset) => codes[offset] << 8 | codes[offset + 1]
570
+ glyphIdOf: (codes, offset) => codes[offset] << BITS_PER_BYTE | codes[offset + 1]
564
571
  };
565
572
  }
566
573
  if (subtype === "TrueType") {
@@ -584,6 +591,7 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
584
591
  }
585
592
  return unavailable(`a font of subtype ${subtype ?? "(none)"} (a Type3 glyph-procedure font has no static outline at all)`);
586
593
  }
594
+ const METRICS_PER_1000_SCALE = 1e3;
587
595
  function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDeviceMatrix, rasteriser, sink) {
588
596
  const face = resolveTextOutlineFace(item.fontResourceName, item.resources, resolver, fontResolver, outlineFaces, sink);
589
597
  if (face === void 0) return;
@@ -596,10 +604,10 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
596
604
  placements.push({
597
605
  glyphId: face.glyphIdOf(item.codes, offset),
598
606
  advance: cumulative,
599
- positionX: (advance.vertical?.positionXPer1000 ?? 0) / 1e3,
600
- positionY: (advance.vertical?.positionYPer1000 ?? 0) / 1e3
607
+ positionX: (advance.vertical?.positionXPer1000 ?? 0) / METRICS_PER_1000_SCALE,
608
+ positionY: (advance.vertical?.positionYPer1000 ?? 0) / METRICS_PER_1000_SCALE
601
609
  });
602
- cumulative += (advance.vertical?.displacementPer1000 ?? advance.widthPer1000) / 1e3 * item.sizePt;
610
+ cumulative += (advance.vertical?.displacementPer1000 ?? advance.widthPer1000) / METRICS_PER_1000_SCALE * item.sizePt;
603
611
  offset += byteLength;
604
612
  }
605
613
  const startDeviceMatrix = multiplyMatrices(item.startMatrix, interpretToDeviceMatrix);
@@ -622,7 +630,7 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
622
630
  });
623
631
  const rawExtent = Math.hypot(rawEndPoint.x - startPoint.x, rawEndPoint.y - startPoint.y);
624
632
  const actualExtent = Math.hypot(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
625
- const correction = rawExtent > 1e-9 ? actualExtent / rawExtent : 1;
633
+ const correction = rawExtent > EXTENT_ZERO_EPSILON ? actualExtent / rawExtent : 1;
626
634
  const firstPlacement = placements[0];
627
635
  const glyphScale = scaleMatrix(1 / face.unitsPerEm, 1 / face.unitsPerEm);
628
636
  for (const placement of placements) {
@@ -645,10 +653,12 @@ function drawGlyphOutline(outline, glyphMatrix, color, rasteriser) {
645
653
  }
646
654
  });
647
655
  }
656
+ const MIN_CONTOUR_POINTS = 3;
657
+ const QUADRATIC_TO_CUBIC_CONTROL_FRACTION = 2 / 3;
648
658
  function glyphOutlineSubpaths(outline, matrix) {
649
659
  const subpaths = [];
650
660
  for (const contour of outline.contours) {
651
- if (contour.length < 3) continue;
661
+ if (contour.length < MIN_CONTOUR_POINTS) continue;
652
662
  const firstOn = contour.findIndex((point) => point.onCurve);
653
663
  const contourPoints = contour.map((point) => ({
654
664
  x: point.x,
@@ -673,10 +683,10 @@ function glyphOutlineSubpaths(outline, matrix) {
673
683
  const p1 = applyMatrix(matrix, to);
674
684
  segments.push({
675
685
  kind: "cubic",
676
- c1xPx: p0.x + 2 / 3 * (q.x - p0.x),
677
- c1yPx: p0.y + 2 / 3 * (q.y - p0.y),
678
- c2xPx: p1.x + 2 / 3 * (q.x - p1.x),
679
- c2yPx: p1.y + 2 / 3 * (q.y - p1.y),
686
+ c1xPx: p0.x + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.x - p0.x),
687
+ c1yPx: p0.y + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.y - p0.y),
688
+ c2xPx: p1.x + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.x - p1.x),
689
+ c2yPx: p1.y + QUADRATIC_TO_CUBIC_CONTROL_FRACTION * (q.y - p1.y),
680
690
  xPx: p1.x,
681
691
  yPx: p1.y
682
692
  });
@@ -764,6 +774,7 @@ function rotatedRectBounds(rect, matrix) {
764
774
  maxY: Math.max(...ys)
765
775
  };
766
776
  }
777
+ const NEWLINE_BYTE = 10;
767
778
  function readPageContentBytes(page, resolver, sink) {
768
779
  const contentsObj = resolver.resolve(dictGet(page, "Contents"));
769
780
  if (contentsObj?.kind === "stream") return decodeStream(contentsObj.raw, contentsObj.dict, sink).bytes;
@@ -771,7 +782,7 @@ function readPageContentBytes(page, resolver, sink) {
771
782
  const chunks = [];
772
783
  for (const entry of contentsObj.items) {
773
784
  const streamObj = resolver.resolve(entry);
774
- if (streamObj?.kind === "stream") chunks.push(decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([10]));
785
+ if (streamObj?.kind === "stream") chunks.push(decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([NEWLINE_BYTE]));
775
786
  }
776
787
  return concatBytes(chunks);
777
788
  }
package/dist/read.cjs CHANGED
@@ -121,13 +121,20 @@ function rotatedRectBounds(rect, matrix) {
121
121
  maxY: Math.max(...ys)
122
122
  };
123
123
  }
124
+ const QUARTER_TURN_DEG = 90;
125
+ const HALF_TURN_DEG = 180;
126
+ const THREE_QUARTER_TURN_DEG = 270;
127
+ const DEGREES_PER_TURN = 360;
128
+ function isNonZeroPageRotation(n) {
129
+ return n === QUARTER_TURN_DEG || n === HALF_TURN_DEG || n === THREE_QUARTER_TURN_DEG;
130
+ }
124
131
  function normalizeRotation(rotate) {
125
132
  if (rotate === void 0) return 0;
126
- const normalized = (Math.round(rotate / 90) * 90 % 360 + 360) % 360;
127
- return normalized === 90 || normalized === 180 || normalized === 270 ? normalized : 0;
133
+ const normalized = (Math.round(rotate / QUARTER_TURN_DEG) * QUARTER_TURN_DEG % DEGREES_PER_TURN + DEGREES_PER_TURN) % DEGREES_PER_TURN;
134
+ return isNonZeroPageRotation(normalized) ? normalized : 0;
128
135
  }
129
136
  function pageRotationTransform(rotation, w, h) {
130
- if (rotation === 90) return {
137
+ if (rotation === QUARTER_TURN_DEG) return {
131
138
  matrix: [
132
139
  0,
133
140
  -1,
@@ -139,7 +146,7 @@ function pageRotationTransform(rotation, w, h) {
139
146
  widthPt: h,
140
147
  heightPt: w
141
148
  };
142
- if (rotation === 180) return {
149
+ if (rotation === HALF_TURN_DEG) return {
143
150
  matrix: [
144
151
  -1,
145
152
  0,
@@ -151,7 +158,7 @@ function pageRotationTransform(rotation, w, h) {
151
158
  widthPt: w,
152
159
  heightPt: h
153
160
  };
154
- if (rotation === 270) return {
161
+ if (rotation === THREE_QUARTER_TURN_DEG) return {
155
162
  matrix: [
156
163
  0,
157
164
  1,
@@ -176,6 +183,7 @@ function pageRotationTransform(rotation, w, h) {
176
183
  heightPt: h
177
184
  };
178
185
  }
186
+ const CONTENT_STREAM_JOIN_BYTE = 10;
179
187
  function readPageContentBytes(page, resolver, sink) {
180
188
  const contentsObj = resolver.resolve(require_objects.dictGet(page, "Contents"));
181
189
  if (contentsObj?.kind === "stream") return require_filters.decodeStream(contentsObj.raw, contentsObj.dict, sink).bytes;
@@ -183,7 +191,7 @@ function readPageContentBytes(page, resolver, sink) {
183
191
  const chunks = [];
184
192
  for (const item of contentsObj.items) {
185
193
  const streamObj = resolver.resolve(item);
186
- if (streamObj?.kind === "stream") chunks.push(require_filters.decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([10]));
194
+ if (streamObj?.kind === "stream") chunks.push(require_filters.decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([CONTENT_STREAM_JOIN_BYTE]));
187
195
  }
188
196
  return require_bytes_writer.concatBytes(chunks);
189
197
  }
@@ -198,7 +206,7 @@ function contentItemBounds(item) {
198
206
  maxY: yPt + heightPt
199
207
  });
200
208
  if (item.kind === "text" || item.kind === "image" || item.kind === "rect" || item.kind === "ellipse") {
201
- if (item.kind !== "text" || item.rotationDeg === void 0 || item.rotationDeg % 180 === 0) return frameBounds(item.xPt, item.yPt, item.widthPt ?? 0, item.kind === "text" ? item.sizePt : item.heightPt);
209
+ if (item.kind !== "text" || item.rotationDeg === void 0 || item.rotationDeg % HALF_TURN_DEG === 0) return frameBounds(item.xPt, item.yPt, item.widthPt ?? 0, item.kind === "text" ? item.sizePt : item.heightPt);
202
210
  const rotationDeg = item.rotationDeg;
203
211
  const anchorX = item.xPt;
204
212
  const anchorY = item.yPt;
@@ -502,8 +510,9 @@ function imagePlacementFrom(matrix) {
502
510
  rotationDeg: rotationDeg !== 0 ? rotationDeg : void 0
503
511
  };
504
512
  }
513
+ const HEX_RADIX = 16;
505
514
  function registerExtractedImage(format, bytes, widthPx, heightPx, images, original) {
506
- const imageId = `img${require_bytes_crc32.crc32(bytes).toString(16)}`;
515
+ const imageId = `img${require_bytes_crc32.crc32(bytes).toString(HEX_RADIX)}`;
507
516
  if (!(imageId in images)) images[imageId] = {
508
517
  format,
509
518
  base64: (0, byte_codec.bytesToBase64)(bytes),
package/dist/read.js CHANGED
@@ -120,13 +120,20 @@ function rotatedRectBounds(rect, matrix) {
120
120
  maxY: Math.max(...ys)
121
121
  };
122
122
  }
123
+ const QUARTER_TURN_DEG = 90;
124
+ const HALF_TURN_DEG = 180;
125
+ const THREE_QUARTER_TURN_DEG = 270;
126
+ const DEGREES_PER_TURN = 360;
127
+ function isNonZeroPageRotation(n) {
128
+ return n === QUARTER_TURN_DEG || n === HALF_TURN_DEG || n === THREE_QUARTER_TURN_DEG;
129
+ }
123
130
  function normalizeRotation(rotate) {
124
131
  if (rotate === void 0) return 0;
125
- const normalized = (Math.round(rotate / 90) * 90 % 360 + 360) % 360;
126
- return normalized === 90 || normalized === 180 || normalized === 270 ? normalized : 0;
132
+ const normalized = (Math.round(rotate / QUARTER_TURN_DEG) * QUARTER_TURN_DEG % DEGREES_PER_TURN + DEGREES_PER_TURN) % DEGREES_PER_TURN;
133
+ return isNonZeroPageRotation(normalized) ? normalized : 0;
127
134
  }
128
135
  function pageRotationTransform(rotation, w, h) {
129
- if (rotation === 90) return {
136
+ if (rotation === QUARTER_TURN_DEG) return {
130
137
  matrix: [
131
138
  0,
132
139
  -1,
@@ -138,7 +145,7 @@ function pageRotationTransform(rotation, w, h) {
138
145
  widthPt: h,
139
146
  heightPt: w
140
147
  };
141
- if (rotation === 180) return {
148
+ if (rotation === HALF_TURN_DEG) return {
142
149
  matrix: [
143
150
  -1,
144
151
  0,
@@ -150,7 +157,7 @@ function pageRotationTransform(rotation, w, h) {
150
157
  widthPt: w,
151
158
  heightPt: h
152
159
  };
153
- if (rotation === 270) return {
160
+ if (rotation === THREE_QUARTER_TURN_DEG) return {
154
161
  matrix: [
155
162
  0,
156
163
  1,
@@ -175,6 +182,7 @@ function pageRotationTransform(rotation, w, h) {
175
182
  heightPt: h
176
183
  };
177
184
  }
185
+ const CONTENT_STREAM_JOIN_BYTE = 10;
178
186
  function readPageContentBytes(page, resolver, sink) {
179
187
  const contentsObj = resolver.resolve(dictGet(page, "Contents"));
180
188
  if (contentsObj?.kind === "stream") return decodeStream(contentsObj.raw, contentsObj.dict, sink).bytes;
@@ -182,7 +190,7 @@ function readPageContentBytes(page, resolver, sink) {
182
190
  const chunks = [];
183
191
  for (const item of contentsObj.items) {
184
192
  const streamObj = resolver.resolve(item);
185
- if (streamObj?.kind === "stream") chunks.push(decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([10]));
193
+ if (streamObj?.kind === "stream") chunks.push(decodeStream(streamObj.raw, streamObj.dict, sink).bytes, new Uint8Array([CONTENT_STREAM_JOIN_BYTE]));
186
194
  }
187
195
  return concatBytes(chunks);
188
196
  }
@@ -197,7 +205,7 @@ function contentItemBounds(item) {
197
205
  maxY: yPt + heightPt
198
206
  });
199
207
  if (item.kind === "text" || item.kind === "image" || item.kind === "rect" || item.kind === "ellipse") {
200
- if (item.kind !== "text" || item.rotationDeg === void 0 || item.rotationDeg % 180 === 0) return frameBounds(item.xPt, item.yPt, item.widthPt ?? 0, item.kind === "text" ? item.sizePt : item.heightPt);
208
+ if (item.kind !== "text" || item.rotationDeg === void 0 || item.rotationDeg % HALF_TURN_DEG === 0) return frameBounds(item.xPt, item.yPt, item.widthPt ?? 0, item.kind === "text" ? item.sizePt : item.heightPt);
201
209
  const rotationDeg = item.rotationDeg;
202
210
  const anchorX = item.xPt;
203
211
  const anchorY = item.yPt;
@@ -501,8 +509,9 @@ function imagePlacementFrom(matrix) {
501
509
  rotationDeg: rotationDeg !== 0 ? rotationDeg : void 0
502
510
  };
503
511
  }
512
+ const HEX_RADIX = 16;
504
513
  function registerExtractedImage(format, bytes, widthPx, heightPx, images, original) {
505
- const imageId = `img${crc32(bytes).toString(16)}`;
514
+ const imageId = `img${crc32(bytes).toString(HEX_RADIX)}`;
506
515
  if (!(imageId in images)) images[imageId] = {
507
516
  format,
508
517
  base64: bytesToBase64(bytes),
@@ -8,18 +8,22 @@ function formatNumber(n) {
8
8
  if (Math.abs(n) < NUMBER_EPSILON) return "0";
9
9
  return n.toFixed(NUMBER_DECIMAL_PLACES).replace(/0+$/, "").replace(/\.$/, "");
10
10
  }
11
+ const NAME_SAFE_RANGE_START = 33;
12
+ const NAME_SAFE_RANGE_END = 126;
13
+ const HEX_RADIX = 16;
14
+ const HEX_DIGIT_WIDTH = 2;
11
15
  function escapeName(name) {
12
16
  let out = "";
13
17
  for (const ch of name) {
14
18
  const code = ch.codePointAt(0);
15
- if (code < 33 || code > 126 || "#()<>[]{}/%".includes(ch)) out += `#${code.toString(16).padStart(2, "0")}`;
19
+ if (code < NAME_SAFE_RANGE_START || code > NAME_SAFE_RANGE_END || "#()<>[]{}/%".includes(ch)) out += `#${code.toString(HEX_RADIX).padStart(HEX_DIGIT_WIDTH, "0")}`;
16
20
  else out += ch;
17
21
  }
18
22
  return out;
19
23
  }
20
24
  function bytesToHex(bytes) {
21
25
  let out = "";
22
- for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
26
+ for (const byte of bytes) out += byte.toString(HEX_RADIX).padStart(HEX_DIGIT_WIDTH, "0");
23
27
  return out;
24
28
  }
25
29
  function writeDictBody(writer, entries) {
package/dist/serialize.js CHANGED
@@ -7,18 +7,22 @@ function formatNumber(n) {
7
7
  if (Math.abs(n) < NUMBER_EPSILON) return "0";
8
8
  return n.toFixed(NUMBER_DECIMAL_PLACES).replace(/0+$/, "").replace(/\.$/, "");
9
9
  }
10
+ const NAME_SAFE_RANGE_START = 33;
11
+ const NAME_SAFE_RANGE_END = 126;
12
+ const HEX_RADIX = 16;
13
+ const HEX_DIGIT_WIDTH = 2;
10
14
  function escapeName(name) {
11
15
  let out = "";
12
16
  for (const ch of name) {
13
17
  const code = ch.codePointAt(0);
14
- if (code < 33 || code > 126 || "#()<>[]{}/%".includes(ch)) out += `#${code.toString(16).padStart(2, "0")}`;
18
+ if (code < NAME_SAFE_RANGE_START || code > NAME_SAFE_RANGE_END || "#()<>[]{}/%".includes(ch)) out += `#${code.toString(HEX_RADIX).padStart(HEX_DIGIT_WIDTH, "0")}`;
15
19
  else out += ch;
16
20
  }
17
21
  return out;
18
22
  }
19
23
  function bytesToHex(bytes) {
20
24
  let out = "";
21
- for (const byte of bytes) out += byte.toString(16).padStart(2, "0");
25
+ for (const byte of bytes) out += byte.toString(HEX_RADIX).padStart(HEX_DIGIT_WIDTH, "0");
22
26
  return out;
23
27
  }
24
28
  function writeDictBody(writer, entries) {
@@ -21,6 +21,13 @@ const LEFT_SIDE_BEARING_SIZE = 2;
21
21
  const LOCA_LONG_ENTRY_SIZE = 4;
22
22
  const TABLE_DIRECTORY_HEADER_SIZE = 12;
23
23
  const TABLE_RECORD_SIZE = 16;
24
+ const SFNT_HEADER_NUM_TABLES_OFFSET = 4;
25
+ const SFNT_HEADER_SEARCH_RANGE_OFFSET = 6;
26
+ const SFNT_HEADER_ENTRY_SELECTOR_OFFSET = 8;
27
+ const SFNT_HEADER_RANGE_SHIFT_OFFSET = 10;
28
+ const TABLE_RECORD_CHECKSUM_OFFSET = 4;
29
+ const TABLE_RECORD_TABLE_OFFSET_OFFSET = 8;
30
+ const TABLE_RECORD_LENGTH_OFFSET = 12;
24
31
  const SFNT_VERSION_TRUETYPE = 65536;
25
32
  const CHECKSUM_ADJUSTMENT_MAGIC = 2981146554;
26
33
  const GLYPH_ALIGNMENT = 4;
@@ -32,15 +39,20 @@ const COPIED_TAGS = [
32
39
  function alignUp(value) {
33
40
  return Math.ceil(value / GLYPH_ALIGNMENT) * GLYPH_ALIGNMENT;
34
41
  }
42
+ const BITS_PER_BYTE = 8;
43
+ const BYTE_MASK = 255;
44
+ const U32_BYTE_2_SHIFT = 16;
45
+ const U32_BYTE_1_SHIFT = 24;
46
+ const U32_LAST_BYTE_OFFSET = 3;
35
47
  function writeU16(bytes, offset, value) {
36
- bytes[offset] = value >>> 8 & 255;
37
- bytes[offset + 1] = value & 255;
48
+ bytes[offset] = value >>> BITS_PER_BYTE & BYTE_MASK;
49
+ bytes[offset + 1] = value & BYTE_MASK;
38
50
  }
39
51
  function writeU32(bytes, offset, value) {
40
- bytes[offset] = value >>> 24 & 255;
41
- bytes[offset + 1] = value >>> 16 & 255;
42
- bytes[offset + 2] = value >>> 8 & 255;
43
- bytes[offset + 3] = value & 255;
52
+ bytes[offset] = value >>> U32_BYTE_1_SHIFT & BYTE_MASK;
53
+ bytes[offset + 1] = value >>> U32_BYTE_2_SHIFT & BYTE_MASK;
54
+ bytes[offset + 2] = value >>> BITS_PER_BYTE & BYTE_MASK;
55
+ bytes[offset + U32_LAST_BYTE_OFFSET] = value & BYTE_MASK;
44
56
  }
45
57
  function checksum(bytes, offset, length) {
46
58
  let sum = 0;
@@ -230,19 +242,19 @@ function subsetSfnt(font, codePoints, extraGlyphIds = []) {
230
242
  }
231
243
  const file = new Uint8Array(fileLength);
232
244
  writeU32(file, 0, SFNT_VERSION_TRUETYPE);
233
- writeU16(file, 4, numTables);
234
- writeU16(file, 6, searchRange);
235
- writeU16(file, 8, entrySelector);
236
- writeU16(file, 10, rangeShift);
245
+ writeU16(file, SFNT_HEADER_NUM_TABLES_OFFSET, numTables);
246
+ writeU16(file, SFNT_HEADER_SEARCH_RANGE_OFFSET, searchRange);
247
+ writeU16(file, SFNT_HEADER_ENTRY_SELECTOR_OFFSET, entrySelector);
248
+ writeU16(file, SFNT_HEADER_RANGE_SHIFT_OFFSET, rangeShift);
237
249
  for (let i = 0; i < numTables; i++) {
238
250
  const table = tables[i];
239
251
  const tableOffset = offsets[i];
240
252
  file.set(table.data, tableOffset);
241
253
  const recordOffset = TABLE_DIRECTORY_HEADER_SIZE + i * TABLE_RECORD_SIZE;
242
254
  for (let c = 0; c < table.tag.length; c++) file[recordOffset + c] = table.tag.charCodeAt(c);
243
- writeU32(file, recordOffset + 4, checksum(file, tableOffset, alignUp(table.data.length)));
244
- writeU32(file, recordOffset + 8, tableOffset);
245
- writeU32(file, recordOffset + 12, table.data.length);
255
+ writeU32(file, recordOffset + TABLE_RECORD_CHECKSUM_OFFSET, checksum(file, tableOffset, alignUp(table.data.length)));
256
+ writeU32(file, recordOffset + TABLE_RECORD_TABLE_OFFSET_OFFSET, tableOffset);
257
+ writeU32(file, recordOffset + TABLE_RECORD_LENGTH_OFFSET, table.data.length);
246
258
  }
247
259
  const headOffsetInFile = offsets[tables.findIndex((table) => table.tag === "head")];
248
260
  writeU32(file, headOffsetInFile + HEAD_CHECKSUM_ADJUSTMENT_OFFSET, CHECKSUM_ADJUSTMENT_MAGIC - checksum(file, 0, fileLength) >>> 0);