pdf-parser.js 4.8.10 → 4.8.12

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 (49) hide show
  1. package/dist/annotations.cjs +16 -16
  2. package/dist/annotations.js +16 -16
  3. package/dist/cff-probe.cjs +1 -1
  4. package/dist/cff-probe.js +1 -1
  5. package/dist/crypto/rc4.cjs +4 -5
  6. package/dist/crypto/rc4.js +4 -5
  7. package/dist/crypto/sha2.cjs +10 -10
  8. package/dist/crypto/sha2.js +10 -10
  9. package/dist/encrypt-write.cjs +0 -1
  10. package/dist/encrypt-write.js +0 -1
  11. package/dist/font-style.cjs +9 -11
  12. package/dist/font-style.js +9 -11
  13. package/dist/glyf-contours-OSdG6Edr.d.ts +13 -0
  14. package/dist/glyf-contours-zRQbj-Yp.d.cts +13 -0
  15. package/dist/glyf-contours.d.cts +1 -12
  16. package/dist/glyf-contours.d.ts +1 -12
  17. package/dist/glyf-nXC-IDRW.d.cts +33 -0
  18. package/dist/glyf-vMGtP1pb.d.ts +33 -0
  19. package/dist/glyf.d.cts +1 -32
  20. package/dist/glyf.d.ts +1 -32
  21. package/dist/image/jp2-boxes.cjs +12 -15
  22. package/dist/image/jp2-boxes.js +12 -15
  23. package/dist/image/jpeg2000-codestream.cjs +13 -12
  24. package/dist/image/jpeg2000-codestream.d.cts +11 -1
  25. package/dist/image/jpeg2000-codestream.d.ts +11 -1
  26. package/dist/image/jpeg2000-codestream.js +13 -13
  27. package/dist/image/jpeg2000-dwt.cjs +23 -17
  28. package/dist/image/jpeg2000-dwt.d.cts +13 -1
  29. package/dist/image/jpeg2000-dwt.d.ts +13 -1
  30. package/dist/image/jpeg2000-dwt.js +18 -18
  31. package/dist/math-content-write.cjs +3 -6
  32. package/dist/math-content-write.js +3 -6
  33. package/dist/math-stretch.cjs +0 -1
  34. package/dist/math-stretch.js +0 -1
  35. package/dist/navigation.cjs +0 -8
  36. package/dist/navigation.js +0 -8
  37. package/dist/raster.cjs +34 -41
  38. package/dist/raster.d.cts +21 -1
  39. package/dist/raster.d.ts +21 -1
  40. package/dist/raster.js +32 -42
  41. package/dist/read.cjs +1 -1
  42. package/dist/read.js +1 -1
  43. package/dist/serialize.cjs +1 -5
  44. package/dist/serialize.js +1 -5
  45. package/dist/write.cjs +1 -5
  46. package/dist/write.js +2 -6
  47. package/dist/xmp.cjs +3 -3
  48. package/dist/xmp.js +3 -3
  49. package/package.json +1 -1
package/dist/raster.cjs CHANGED
@@ -17,7 +17,6 @@ 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 FALLBACK_GLYPH_WIDTH_PER_1000 = 500;
21
20
  function regionPixels(extentPt, scale) {
22
21
  return Math.max(1, Math.ceil(extentPt * scale - 1e-9));
23
22
  }
@@ -46,7 +45,7 @@ function renderPdfPage(pdfBytes, pageIndex, options, rasteriser) {
46
45
  cropBox = mediaBox;
47
46
  }
48
47
  const rotation = require_read.normalizeRotation(require_objects.asNumber(require_objects.dictGet(page, "Rotate")));
49
- const rotationResult = require_read.pageRotationTransform(rotation, mediaBox.urx - mediaBox.llx, mediaBox.ury - mediaBox.lly);
48
+ const rotationResult = require_read.pageRotationTransform(rotation, 0, 0);
50
49
  const visibleRect = rotatedRectBounds(cropBox, rotationResult.matrix);
51
50
  const pageWidthPt = visibleRect.maxX - visibleRect.minX;
52
51
  const pageHeightPt = visibleRect.maxY - visibleRect.minY;
@@ -483,7 +482,7 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
483
482
  const stream = resolver.resolve(require_objects.dictGet(descriptor, key));
484
483
  if (stream?.kind !== "stream") continue;
485
484
  const bytes = require_filters.decodeStream(stream.raw, stream.dict, require_diagnostics.NOOP_DIAGNOSTIC_SINK).bytes;
486
- if (bytes.length >= 3 && bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
485
+ if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
487
486
  const sfnt = require_sfnt.parseSfnt(bytes);
488
487
  if (sfnt === void 0) continue;
489
488
  if (sfnt.tables.has("CFF ")) return { kind: "cff" };
@@ -499,10 +498,8 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
499
498
  kind: "glyf",
500
499
  sfnt,
501
500
  face: {
502
- composite: false,
503
501
  glyf,
504
- unitsPerEm: head.unitsPerEm,
505
- glyphIdOf: () => void 0
502
+ unitsPerEm: head.unitsPerEm
506
503
  }
507
504
  };
508
505
  }
@@ -574,17 +571,15 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
574
571
  const entries = [];
575
572
  for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << 8 | decodedBytes[i + 1]);
576
573
  return {
577
- composite: true,
578
574
  glyf: program.face.glyf,
579
575
  unitsPerEm: program.face.unitsPerEm,
580
576
  glyphIdOf: (codes, offset) => {
581
577
  const cid = codes[offset] << 8 | codes[offset + 1];
582
- return cid < entries.length ? entries[cid] : void 0;
578
+ return entries[cid];
583
579
  }
584
580
  };
585
581
  }
586
582
  return {
587
- composite: true,
588
583
  glyf: program.face.glyf,
589
584
  unitsPerEm: program.face.unitsPerEm,
590
585
  glyphIdOf: (codes, offset) => codes[offset] << 8 | codes[offset + 1]
@@ -606,7 +601,6 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
606
601
  return;
607
602
  }
608
603
  return {
609
- composite: false,
610
604
  glyf: program.face.glyf,
611
605
  unitsPerEm: program.face.unitsPerEm,
612
606
  glyphIdOf: (codes, offset) => {
@@ -624,14 +618,13 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
624
618
  function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDeviceMatrix, rasteriser, sink) {
625
619
  const face = resolveTextOutlineFace(item.fontResourceName, item.resources, resolver, fontResolver, outlineFaces, sink);
626
620
  if (face === void 0) return;
627
- const composite = face.composite;
628
621
  const placements = [];
629
622
  let offset = 0;
630
623
  let cumulative = 0;
631
624
  while (offset < item.codes.length) {
632
625
  const advance = fontResolver.metrics.glyphAdvance(item.fontResourceName, item.resources, item.codes, offset);
633
- const widthPer1000 = advance?.widthPer1000 ?? FALLBACK_GLYPH_WIDTH_PER_1000;
634
- const byteLength = advance?.byteLengthConsumed ?? (composite ? 2 : 1);
626
+ const widthPer1000 = advance.widthPer1000;
627
+ const byteLength = advance.byteLengthConsumed;
635
628
  placements.push({
636
629
  glyphId: face.glyphIdOf(item.codes, offset),
637
630
  advance: cumulative
@@ -660,20 +653,23 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
660
653
  for (const placement of placements) {
661
654
  if (placement.glyphId === void 0) continue;
662
655
  const outline = require_glyf_contours.decodeGlyphOutline(face.glyf, placement.glyphId);
663
- if (outline === void 0 || outline.contours.length === 0) continue;
656
+ if (outline === void 0) continue;
664
657
  const trm = require_matrix.multiplyMatrices(require_matrix.translationMatrix(placement.advance * correction, 0), item.startMatrix);
665
- const subpaths = glyphOutlineSubpaths(outline, require_matrix.multiplyMatrices(glyphScale, require_matrix.multiplyMatrices(trm, interpretToDeviceMatrix)));
666
- if (subpaths.length === 0) continue;
667
- rasteriser.draw({
668
- kind: "path",
669
- subpaths,
670
- fill: {
671
- color: item.color,
672
- fillRule: "nonzero"
673
- }
674
- });
658
+ drawGlyphOutline(outline, require_matrix.multiplyMatrices(glyphScale, require_matrix.multiplyMatrices(trm, interpretToDeviceMatrix)), item.color, rasteriser);
675
659
  }
676
660
  }
661
+ function drawGlyphOutline(outline, glyphMatrix, color, rasteriser) {
662
+ const subpaths = glyphOutlineSubpaths(outline, glyphMatrix);
663
+ if (subpaths.length === 0) return;
664
+ rasteriser.draw({
665
+ kind: "path",
666
+ subpaths,
667
+ fill: {
668
+ color,
669
+ fillRule: "nonzero"
670
+ }
671
+ });
672
+ }
677
673
  function glyphOutlineSubpaths(outline, matrix) {
678
674
  const subpaths = [];
679
675
  for (const contour of outline.contours) {
@@ -684,8 +680,9 @@ function glyphOutlineSubpaths(outline, matrix) {
684
680
  y: point.y,
685
681
  onCurve: point.onCurve
686
682
  }));
687
- const ordered = firstOn >= 0 ? [...contourPoints.slice(firstOn), ...contourPoints.slice(0, firstOn)] : contourPoints;
688
- let current = firstOn >= 0 ? {
683
+ const hasLeadingOnCurvePoint = firstOn >= 0;
684
+ const ordered = hasLeadingOnCurvePoint ? [...contourPoints.slice(firstOn), ...contourPoints.slice(0, firstOn)] : contourPoints;
685
+ let current = hasLeadingOnCurvePoint ? {
689
686
  x: contourPoints[firstOn].x,
690
687
  y: contourPoints[firstOn].y
691
688
  } : {
@@ -734,27 +731,20 @@ function glyphOutlineSubpaths(outline, matrix) {
734
731
  pendingOffCurve = point;
735
732
  }
736
733
  if (pendingOffCurve !== void 0) emitQuad(current, pendingOffCurve, start);
737
- if (segments.length >= 2) {
738
- const startPx = require_matrix.applyMatrix(matrix, start);
739
- subpaths.push({
740
- startXPx: startPx.x,
741
- startYPx: startPx.y,
742
- segments,
743
- closed: true
744
- });
745
- }
734
+ const startPx = require_matrix.applyMatrix(matrix, start);
735
+ subpaths.push({
736
+ startXPx: startPx.x,
737
+ startYPx: startPx.y,
738
+ segments,
739
+ closed: true
740
+ });
746
741
  }
747
742
  return subpaths;
748
743
  }
749
- const PDF_HEADER_BYTES = new TextEncoder().encode("%PDF-");
750
744
  const HEADER_SEARCH_WINDOW = 1024;
751
745
  function hasPdfHeader(bytes) {
752
746
  const window = bytes.subarray(0, Math.min(HEADER_SEARCH_WINDOW, bytes.length));
753
- outer: for (let i = 0; i <= window.length - PDF_HEADER_BYTES.length; i++) {
754
- for (let j = 0; j < PDF_HEADER_BYTES.length; j++) if (window[i + j] !== PDF_HEADER_BYTES[j]) continue outer;
755
- return true;
756
- }
757
- return false;
747
+ return new TextDecoder("latin1").decode(window).includes("%PDF-");
758
748
  }
759
749
  function readDeclaredPageBox(page, key) {
760
750
  const arr = require_objects.asArray(require_objects.dictGet(page, key));
@@ -813,4 +803,7 @@ function readPageContentBytes(page, resolver, sink) {
813
803
  return /* @__PURE__ */ new Uint8Array(0);
814
804
  }
815
805
  //#endregion
806
+ exports.drawGlyphOutline = drawGlyphOutline;
807
+ exports.flattenCubic = flattenCubic;
808
+ exports.glyphOutlineSubpaths = glyphOutlineSubpaths;
816
809
  exports.renderPdfPage = renderPdfPage;
package/dist/raster.d.cts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { PdfDiagnosticSink } from "./diagnostics.cjs";
2
+ import { r as Matrix } from "./matrix-B7_SBKQ5.cjs";
3
+ import { n as GlyphOutline } from "./glyf-contours-zRQbj-Yp.cjs";
2
4
  import { Color } from "document-schema.js";
3
5
  //#region src/raster.d.ts
4
6
  type RasterMatrix = readonly [number, number, number, number, number, number];
@@ -79,5 +81,23 @@ interface RenderPdfPageOptions {
79
81
  readonly signal?: AbortSignal;
80
82
  }
81
83
  declare function renderPdfPage(pdfBytes: Uint8Array<ArrayBuffer>, pageIndex: number, options: RenderPdfPageOptions, rasteriser: PageRasteriser): Uint8Array<ArrayBuffer> | Promise<Uint8Array<ArrayBuffer>>;
84
+ declare function flattenCubic(p0: {
85
+ x: number;
86
+ y: number;
87
+ }, c1: {
88
+ x: number;
89
+ y: number;
90
+ }, c2: {
91
+ x: number;
92
+ y: number;
93
+ }, p1: {
94
+ x: number;
95
+ y: number;
96
+ }): readonly {
97
+ x: number;
98
+ y: number;
99
+ }[];
100
+ declare function drawGlyphOutline(outline: GlyphOutline, glyphMatrix: Matrix, color: Color, rasteriser: PageRasteriser): void;
101
+ declare function glyphOutlineSubpaths(outline: GlyphOutline, matrix: Matrix): readonly RasterSubpath[];
82
102
  //#endregion
83
- export { PageRasteriser, RasterDrawOp, RasterFillRectOp, RasterFillSpec, RasterImageOp, RasterMatrix, RasterPageGeometry, RasterPathOp, RasterPathSegment, RasterRegionPt, RasterStrokeSpec, RasterSubpath, RenderPdfPageOptions, renderPdfPage };
103
+ export { PageRasteriser, RasterDrawOp, RasterFillRectOp, RasterFillSpec, RasterImageOp, RasterMatrix, RasterPageGeometry, RasterPathOp, RasterPathSegment, RasterRegionPt, RasterStrokeSpec, RasterSubpath, RenderPdfPageOptions, drawGlyphOutline, flattenCubic, glyphOutlineSubpaths, renderPdfPage };
package/dist/raster.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { PdfDiagnosticSink } from "./diagnostics.js";
2
+ import { r as Matrix } from "./matrix-B7_SBKQ5.js";
3
+ import { n as GlyphOutline } from "./glyf-contours-OSdG6Edr.js";
2
4
  import { Color } from "document-schema.js";
3
5
  //#region src/raster.d.ts
4
6
  type RasterMatrix = readonly [number, number, number, number, number, number];
@@ -79,5 +81,23 @@ interface RenderPdfPageOptions {
79
81
  readonly signal?: AbortSignal;
80
82
  }
81
83
  declare function renderPdfPage(pdfBytes: Uint8Array<ArrayBuffer>, pageIndex: number, options: RenderPdfPageOptions, rasteriser: PageRasteriser): Uint8Array<ArrayBuffer> | Promise<Uint8Array<ArrayBuffer>>;
84
+ declare function flattenCubic(p0: {
85
+ x: number;
86
+ y: number;
87
+ }, c1: {
88
+ x: number;
89
+ y: number;
90
+ }, c2: {
91
+ x: number;
92
+ y: number;
93
+ }, p1: {
94
+ x: number;
95
+ y: number;
96
+ }): readonly {
97
+ x: number;
98
+ y: number;
99
+ }[];
100
+ declare function drawGlyphOutline(outline: GlyphOutline, glyphMatrix: Matrix, color: Color, rasteriser: PageRasteriser): void;
101
+ declare function glyphOutlineSubpaths(outline: GlyphOutline, matrix: Matrix): readonly RasterSubpath[];
82
102
  //#endregion
83
- export { PageRasteriser, RasterDrawOp, RasterFillRectOp, RasterFillSpec, RasterImageOp, RasterMatrix, RasterPageGeometry, RasterPathOp, RasterPathSegment, RasterRegionPt, RasterStrokeSpec, RasterSubpath, RenderPdfPageOptions, renderPdfPage };
103
+ export { PageRasteriser, RasterDrawOp, RasterFillRectOp, RasterFillSpec, RasterImageOp, RasterMatrix, RasterPageGeometry, RasterPathOp, RasterPathSegment, RasterRegionPt, RasterStrokeSpec, RasterSubpath, RenderPdfPageOptions, drawGlyphOutline, flattenCubic, glyphOutlineSubpaths, renderPdfPage };
package/dist/raster.js CHANGED
@@ -16,7 +16,6 @@ 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 FALLBACK_GLYPH_WIDTH_PER_1000 = 500;
20
19
  function regionPixels(extentPt, scale) {
21
20
  return Math.max(1, Math.ceil(extentPt * scale - 1e-9));
22
21
  }
@@ -45,7 +44,7 @@ function renderPdfPage(pdfBytes, pageIndex, options, rasteriser) {
45
44
  cropBox = mediaBox;
46
45
  }
47
46
  const rotation = normalizeRotation(asNumber(dictGet(page, "Rotate")));
48
- const rotationResult = pageRotationTransform(rotation, mediaBox.urx - mediaBox.llx, mediaBox.ury - mediaBox.lly);
47
+ const rotationResult = pageRotationTransform(rotation, 0, 0);
49
48
  const visibleRect = rotatedRectBounds(cropBox, rotationResult.matrix);
50
49
  const pageWidthPt = visibleRect.maxX - visibleRect.minX;
51
50
  const pageHeightPt = visibleRect.maxY - visibleRect.minY;
@@ -482,7 +481,7 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
482
481
  const stream = resolver.resolve(dictGet(descriptor, key));
483
482
  if (stream?.kind !== "stream") continue;
484
483
  const bytes = decodeStream(stream.raw, stream.dict, NOOP_DIAGNOSTIC_SINK).bytes;
485
- if (bytes.length >= 3 && bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
484
+ if (bytes[0] === 1 && bytes[1] === 0 && bytes[2] === 4) return { kind: "cff" };
486
485
  const sfnt = parseSfnt(bytes);
487
486
  if (sfnt === void 0) continue;
488
487
  if (sfnt.tables.has("CFF ")) return { kind: "cff" };
@@ -498,10 +497,8 @@ function openEmbeddedProgram(descriptorOwner, resolver) {
498
497
  kind: "glyf",
499
498
  sfnt,
500
499
  face: {
501
- composite: false,
502
500
  glyf,
503
- unitsPerEm: head.unitsPerEm,
504
- glyphIdOf: () => void 0
501
+ unitsPerEm: head.unitsPerEm
505
502
  }
506
503
  };
507
504
  }
@@ -573,17 +570,15 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
573
570
  const entries = [];
574
571
  for (let i = 0; i + 1 < decodedBytes.length; i += 2) entries.push(decodedBytes[i] << 8 | decodedBytes[i + 1]);
575
572
  return {
576
- composite: true,
577
573
  glyf: program.face.glyf,
578
574
  unitsPerEm: program.face.unitsPerEm,
579
575
  glyphIdOf: (codes, offset) => {
580
576
  const cid = codes[offset] << 8 | codes[offset + 1];
581
- return cid < entries.length ? entries[cid] : void 0;
577
+ return entries[cid];
582
578
  }
583
579
  };
584
580
  }
585
581
  return {
586
- composite: true,
587
582
  glyf: program.face.glyf,
588
583
  unitsPerEm: program.face.unitsPerEm,
589
584
  glyphIdOf: (codes, offset) => codes[offset] << 8 | codes[offset + 1]
@@ -605,7 +600,6 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
605
600
  return;
606
601
  }
607
602
  return {
608
- composite: false,
609
603
  glyf: program.face.glyf,
610
604
  unitsPerEm: program.face.unitsPerEm,
611
605
  glyphIdOf: (codes, offset) => {
@@ -623,14 +617,13 @@ function buildTextOutlineFace(fontDict, resolver, fontResolver, fontResourceName
623
617
  function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDeviceMatrix, rasteriser, sink) {
624
618
  const face = resolveTextOutlineFace(item.fontResourceName, item.resources, resolver, fontResolver, outlineFaces, sink);
625
619
  if (face === void 0) return;
626
- const composite = face.composite;
627
620
  const placements = [];
628
621
  let offset = 0;
629
622
  let cumulative = 0;
630
623
  while (offset < item.codes.length) {
631
624
  const advance = fontResolver.metrics.glyphAdvance(item.fontResourceName, item.resources, item.codes, offset);
632
- const widthPer1000 = advance?.widthPer1000 ?? FALLBACK_GLYPH_WIDTH_PER_1000;
633
- const byteLength = advance?.byteLengthConsumed ?? (composite ? 2 : 1);
625
+ const widthPer1000 = advance.widthPer1000;
626
+ const byteLength = advance.byteLengthConsumed;
634
627
  placements.push({
635
628
  glyphId: face.glyphIdOf(item.codes, offset),
636
629
  advance: cumulative
@@ -659,20 +652,23 @@ function drawTextRun(item, fontResolver, resolver, outlineFaces, interpretToDevi
659
652
  for (const placement of placements) {
660
653
  if (placement.glyphId === void 0) continue;
661
654
  const outline = decodeGlyphOutline(face.glyf, placement.glyphId);
662
- if (outline === void 0 || outline.contours.length === 0) continue;
655
+ if (outline === void 0) continue;
663
656
  const trm = multiplyMatrices(translationMatrix(placement.advance * correction, 0), item.startMatrix);
664
- const subpaths = glyphOutlineSubpaths(outline, multiplyMatrices(glyphScale, multiplyMatrices(trm, interpretToDeviceMatrix)));
665
- if (subpaths.length === 0) continue;
666
- rasteriser.draw({
667
- kind: "path",
668
- subpaths,
669
- fill: {
670
- color: item.color,
671
- fillRule: "nonzero"
672
- }
673
- });
657
+ drawGlyphOutline(outline, multiplyMatrices(glyphScale, multiplyMatrices(trm, interpretToDeviceMatrix)), item.color, rasteriser);
674
658
  }
675
659
  }
660
+ function drawGlyphOutline(outline, glyphMatrix, color, rasteriser) {
661
+ const subpaths = glyphOutlineSubpaths(outline, glyphMatrix);
662
+ if (subpaths.length === 0) return;
663
+ rasteriser.draw({
664
+ kind: "path",
665
+ subpaths,
666
+ fill: {
667
+ color,
668
+ fillRule: "nonzero"
669
+ }
670
+ });
671
+ }
676
672
  function glyphOutlineSubpaths(outline, matrix) {
677
673
  const subpaths = [];
678
674
  for (const contour of outline.contours) {
@@ -683,8 +679,9 @@ function glyphOutlineSubpaths(outline, matrix) {
683
679
  y: point.y,
684
680
  onCurve: point.onCurve
685
681
  }));
686
- const ordered = firstOn >= 0 ? [...contourPoints.slice(firstOn), ...contourPoints.slice(0, firstOn)] : contourPoints;
687
- let current = firstOn >= 0 ? {
682
+ const hasLeadingOnCurvePoint = firstOn >= 0;
683
+ const ordered = hasLeadingOnCurvePoint ? [...contourPoints.slice(firstOn), ...contourPoints.slice(0, firstOn)] : contourPoints;
684
+ let current = hasLeadingOnCurvePoint ? {
688
685
  x: contourPoints[firstOn].x,
689
686
  y: contourPoints[firstOn].y
690
687
  } : {
@@ -733,27 +730,20 @@ function glyphOutlineSubpaths(outline, matrix) {
733
730
  pendingOffCurve = point;
734
731
  }
735
732
  if (pendingOffCurve !== void 0) emitQuad(current, pendingOffCurve, start);
736
- if (segments.length >= 2) {
737
- const startPx = applyMatrix(matrix, start);
738
- subpaths.push({
739
- startXPx: startPx.x,
740
- startYPx: startPx.y,
741
- segments,
742
- closed: true
743
- });
744
- }
733
+ const startPx = applyMatrix(matrix, start);
734
+ subpaths.push({
735
+ startXPx: startPx.x,
736
+ startYPx: startPx.y,
737
+ segments,
738
+ closed: true
739
+ });
745
740
  }
746
741
  return subpaths;
747
742
  }
748
- const PDF_HEADER_BYTES = new TextEncoder().encode("%PDF-");
749
743
  const HEADER_SEARCH_WINDOW = 1024;
750
744
  function hasPdfHeader(bytes) {
751
745
  const window = bytes.subarray(0, Math.min(HEADER_SEARCH_WINDOW, bytes.length));
752
- outer: for (let i = 0; i <= window.length - PDF_HEADER_BYTES.length; i++) {
753
- for (let j = 0; j < PDF_HEADER_BYTES.length; j++) if (window[i + j] !== PDF_HEADER_BYTES[j]) continue outer;
754
- return true;
755
- }
756
- return false;
746
+ return new TextDecoder("latin1").decode(window).includes("%PDF-");
757
747
  }
758
748
  function readDeclaredPageBox(page, key) {
759
749
  const arr = asArray(dictGet(page, key));
@@ -812,4 +802,4 @@ function readPageContentBytes(page, resolver, sink) {
812
802
  return /* @__PURE__ */ new Uint8Array(0);
813
803
  }
814
804
  //#endregion
815
- export { renderPdfPage };
805
+ export { drawGlyphOutline, flattenCubic, glyphOutlineSubpaths, renderPdfPage };
package/dist/read.cjs CHANGED
@@ -288,7 +288,7 @@ function readPage(pageIndex, page, resolver, fontResolver, images, imageIdCache,
288
288
  });
289
289
  cropBox = mediaBox;
290
290
  }
291
- const rotationResult = pageRotationTransform(normalizeRotation(require_objects.asNumber(require_objects.dictGet(page, "Rotate"))), mediaBox.urx - mediaBox.llx, mediaBox.ury - mediaBox.lly);
291
+ const rotationResult = pageRotationTransform(normalizeRotation(require_objects.asNumber(require_objects.dictGet(page, "Rotate"))), 0, 0);
292
292
  const visibleRect = rotatedRectBounds(cropBox, rotationResult.matrix);
293
293
  const widthPt = visibleRect.maxX - visibleRect.minX;
294
294
  const heightPt = visibleRect.maxY - visibleRect.minY;
package/dist/read.js CHANGED
@@ -287,7 +287,7 @@ function readPage(pageIndex, page, resolver, fontResolver, images, imageIdCache,
287
287
  });
288
288
  cropBox = mediaBox;
289
289
  }
290
- const rotationResult = pageRotationTransform(normalizeRotation(asNumber(dictGet(page, "Rotate"))), mediaBox.urx - mediaBox.llx, mediaBox.ury - mediaBox.lly);
290
+ const rotationResult = pageRotationTransform(normalizeRotation(asNumber(dictGet(page, "Rotate"))), 0, 0);
291
291
  const visibleRect = rotatedRectBounds(cropBox, rotationResult.matrix);
292
292
  const widthPt = visibleRect.maxX - visibleRect.minX;
293
293
  const heightPt = visibleRect.maxY - visibleRect.minY;
@@ -6,13 +6,9 @@ const NUMBER_DECIMAL_PLACES = 4;
6
6
  const NUMBER_EPSILON = 10 ** -4;
7
7
  function formatNumber(n) {
8
8
  if (Math.abs(n) < NUMBER_EPSILON) return "0";
9
- let formatted = n.toFixed(NUMBER_DECIMAL_PLACES);
10
- if (formatted.includes(".")) formatted = formatted.replace(/0+$/, "").replace(/\.$/, "");
11
- return formatted === "-0" ? "0" : formatted;
9
+ return n.toFixed(NUMBER_DECIMAL_PLACES).replace(/0+$/, "").replace(/\.$/, "");
12
10
  }
13
- const NAME_ESCAPE_PATTERN = /[^!-~]|[#()<>[\]{}/%]/;
14
11
  function escapeName(name) {
15
- if (!NAME_ESCAPE_PATTERN.test(name)) return name;
16
12
  let out = "";
17
13
  for (const ch of name) {
18
14
  const code = ch.codePointAt(0);
package/dist/serialize.js CHANGED
@@ -5,13 +5,9 @@ const NUMBER_DECIMAL_PLACES = 4;
5
5
  const NUMBER_EPSILON = 10 ** -4;
6
6
  function formatNumber(n) {
7
7
  if (Math.abs(n) < NUMBER_EPSILON) return "0";
8
- let formatted = n.toFixed(NUMBER_DECIMAL_PLACES);
9
- if (formatted.includes(".")) formatted = formatted.replace(/0+$/, "").replace(/\.$/, "");
10
- return formatted === "-0" ? "0" : formatted;
8
+ return n.toFixed(NUMBER_DECIMAL_PLACES).replace(/0+$/, "").replace(/\.$/, "");
11
9
  }
12
- const NAME_ESCAPE_PATTERN = /[^!-~]|[#()<>[\]{}/%]/;
13
10
  function escapeName(name) {
14
- if (!NAME_ESCAPE_PATTERN.test(name)) return name;
15
11
  let out = "";
16
12
  for (const ch of name) {
17
13
  const code = ch.codePointAt(0);
package/dist/write.cjs CHANGED
@@ -74,14 +74,10 @@ function computeFontFlags(standardName, metrics) {
74
74
  if (standardName.includes("Bold")) flags |= FLAG_FORCE_BOLD;
75
75
  return flags;
76
76
  }
77
- function widthForWidthsArray(standardName, code) {
78
- if (require_afm_widths.STANDARD_METRICS[standardName].fixedWidth === void 0 && require_afm_widths.winAnsiGlyphName(code) === void 0) return 0;
79
- return require_afm_widths.widthOfCode(standardName, code);
80
- }
81
77
  function buildFontObjects(standardName, descriptorRef) {
82
78
  const metrics = require_afm_widths.STANDARD_METRICS[standardName];
83
79
  const widths = [];
84
- for (let code = FIRST_CHAR; code <= LAST_CHAR; code++) widths.push(require_objects.pdfNum(widthForWidthsArray(standardName, code)));
80
+ for (let code = FIRST_CHAR; code <= LAST_CHAR; code++) widths.push(require_objects.pdfNum(require_afm_widths.widthOfCode(standardName, code)));
85
81
  return {
86
82
  font: require_objects.pdfDict({
87
83
  Type: require_objects.pdfName("Font"),
package/dist/write.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as widthOfCode, p as winAnsiGlyphName, t as STANDARD_METRICS } from "./afm-widths-De_QMWgC.js";
1
+ import { n as widthOfCode, t as STANDARD_METRICS } from "./afm-widths-De_QMWgC.js";
2
2
  import { NOTES_ANNOTATION_AUTHOR } from "./notes-annotation-author.js";
3
3
  import { pdfArray, pdfBool, pdfDict, pdfHexString, pdfLiteralString, pdfName, pdfNull, pdfNum, pdfRef, pdfStream } from "./objects.js";
4
4
  import { ByteWriter, concatBytes } from "./bytes/writer.js";
@@ -73,14 +73,10 @@ function computeFontFlags(standardName, metrics) {
73
73
  if (standardName.includes("Bold")) flags |= FLAG_FORCE_BOLD;
74
74
  return flags;
75
75
  }
76
- function widthForWidthsArray(standardName, code) {
77
- if (STANDARD_METRICS[standardName].fixedWidth === void 0 && winAnsiGlyphName(code) === void 0) return 0;
78
- return widthOfCode(standardName, code);
79
- }
80
76
  function buildFontObjects(standardName, descriptorRef) {
81
77
  const metrics = STANDARD_METRICS[standardName];
82
78
  const widths = [];
83
- for (let code = FIRST_CHAR; code <= LAST_CHAR; code++) widths.push(pdfNum(widthForWidthsArray(standardName, code)));
79
+ for (let code = FIRST_CHAR; code <= LAST_CHAR; code++) widths.push(pdfNum(widthOfCode(standardName, code)));
84
80
  return {
85
81
  font: pdfDict({
86
82
  Type: pdfName("Font"),
package/dist/xmp.cjs CHANGED
@@ -15,7 +15,7 @@ function readXmpMetadata(packet) {
15
15
  function xmpValue(packet, element) {
16
16
  const match = new RegExp(`<${element}(?:\\s[^>]*)?>([\\s\\S]*?)</${element}>`).exec(packet);
17
17
  if (match === null) return;
18
- const inner = match[1] ?? "";
18
+ const inner = match[1];
19
19
  const items = listItems(inner);
20
20
  if (items.length > 0) return items;
21
21
  const text = inner.trim();
@@ -26,7 +26,7 @@ function listItems(inner) {
26
26
  const pattern = /<rdf:li(?:\s[^>]*)?>([\s\S]*?)<\/rdf:li>/g;
27
27
  let match;
28
28
  while ((match = pattern.exec(inner)) !== null) {
29
- const text = (match[1] ?? "").trim();
29
+ const text = match[1].trim();
30
30
  if (text.length > 0) items.push(text);
31
31
  }
32
32
  return items;
@@ -39,7 +39,7 @@ function field(value, key) {
39
39
  function keywordsOf(packet) {
40
40
  const match = (/* @__PURE__ */ new RegExp("<dc:subject(?:\\s[^>]*)?>([\\s\\S]*?)</dc:subject>")).exec(packet);
41
41
  if (match === null) return {};
42
- const items = listItems(match[1] ?? "");
42
+ const items = listItems(match[1]);
43
43
  return items.length > 0 ? { keywords: items } : {};
44
44
  }
45
45
  //#endregion
package/dist/xmp.js CHANGED
@@ -14,7 +14,7 @@ function readXmpMetadata(packet) {
14
14
  function xmpValue(packet, element) {
15
15
  const match = new RegExp(`<${element}(?:\\s[^>]*)?>([\\s\\S]*?)</${element}>`).exec(packet);
16
16
  if (match === null) return;
17
- const inner = match[1] ?? "";
17
+ const inner = match[1];
18
18
  const items = listItems(inner);
19
19
  if (items.length > 0) return items;
20
20
  const text = inner.trim();
@@ -25,7 +25,7 @@ function listItems(inner) {
25
25
  const pattern = /<rdf:li(?:\s[^>]*)?>([\s\S]*?)<\/rdf:li>/g;
26
26
  let match;
27
27
  while ((match = pattern.exec(inner)) !== null) {
28
- const text = (match[1] ?? "").trim();
28
+ const text = match[1].trim();
29
29
  if (text.length > 0) items.push(text);
30
30
  }
31
31
  return items;
@@ -38,7 +38,7 @@ function field(value, key) {
38
38
  function keywordsOf(packet) {
39
39
  const match = (/* @__PURE__ */ new RegExp("<dc:subject(?:\\s[^>]*)?>([\\s\\S]*?)</dc:subject>")).exec(packet);
40
40
  if (match === null) return {};
41
- const items = listItems(match[1] ?? "");
41
+ const items = listItems(match[1]);
42
42
  return items.length > 0 ? { keywords: items } : {};
43
43
  }
44
44
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pdf-parser.js",
3
- "version": "4.8.10",
3
+ "version": "4.8.12",
4
4
  "description": "Hand-written, dependency-minimal PDF codec: parses arbitrary real-world PDFs and generates new ones, built on its own codec-owned LayoutDocument item model and Zod 4 codecs.",
5
5
  "type": "module",
6
6
  "repository": {