@ironsoftware/ironpdf 2026.4.1 → 2026.6.1

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 (141) hide show
  1. package/package.json +3 -3
  2. package/src/index.d.ts +3 -0
  3. package/src/index.d.ts.map +1 -1
  4. package/src/index.js +3 -0
  5. package/src/index.js.map +1 -1
  6. package/src/index.ts +3 -0
  7. package/src/internal/IronPdfEngine.ProtoFiles/chrome_render.proto +6 -0
  8. package/src/internal/IronPdfEngine.ProtoFiles/iron_pdf_service.proto +7 -1
  9. package/src/internal/IronPdfEngine.ProtoFiles/pdfium_compress.proto +1 -0
  10. package/src/internal/IronPdfEngine.ProtoFiles/pdfium_form.proto +32 -0
  11. package/src/internal/IronPdfEngine.ProtoFiles/qpdf.proto +51 -0
  12. package/src/internal/access.d.ts.map +1 -1
  13. package/src/internal/access.js +3 -0
  14. package/src/internal/access.js.map +1 -1
  15. package/src/internal/access.ts +4 -0
  16. package/src/internal/generated_proto/iron_pdf_service.d.ts +628 -305
  17. package/src/internal/generated_proto/iron_pdf_service.d.ts.map +1 -1
  18. package/src/internal/generated_proto/iron_pdf_service.ts +628 -305
  19. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.d.ts +15 -0
  20. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.d.ts.map +1 -1
  21. package/src/internal/generated_proto/ironpdfengineproto/ChromePdfRenderOptionsP.ts +15 -0
  22. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.d.ts +52 -0
  23. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.d.ts.map +1 -1
  24. package/src/internal/generated_proto/ironpdfengineproto/IronPdfService.ts +64 -0
  25. package/src/internal/generated_proto/ironpdfengineproto/PdfiumCompressImagesRequestP.d.ts +2 -0
  26. package/src/internal/generated_proto/ironpdfengineproto/PdfiumCompressImagesRequestP.d.ts.map +1 -1
  27. package/src/internal/generated_proto/ironpdfengineproto/PdfiumCompressImagesRequestP.ts +2 -0
  28. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackRequestP.d.ts +8 -0
  29. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackRequestP.d.ts.map +1 -0
  30. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackRequestP.js +4 -0
  31. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackRequestP.js.map +1 -0
  32. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackRequestP.ts +11 -0
  33. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackResultP.d.ts +12 -0
  34. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackResultP.d.ts.map +1 -0
  35. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackResultP.js +4 -0
  36. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackResultP.js.map +1 -0
  37. package/src/internal/generated_proto/ironpdfengineproto/PdfiumDisableFormFontFallbackResultP.ts +15 -0
  38. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontRequestStreamP.d.ts +25 -0
  39. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontRequestStreamP.d.ts.map +1 -0
  40. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontRequestStreamP.js +4 -0
  41. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontRequestStreamP.js.map +1 -0
  42. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontRequestStreamP.ts +28 -0
  43. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontResultP.d.ts +12 -0
  44. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontResultP.d.ts.map +1 -0
  45. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontResultP.js +4 -0
  46. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontResultP.js.map +1 -0
  47. package/src/internal/generated_proto/ironpdfengineproto/PdfiumSetFormFontResultP.ts +15 -0
  48. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedFromBytesRequestStreamP.d.ts +23 -0
  49. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedFromBytesRequestStreamP.d.ts.map +1 -0
  50. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedFromBytesRequestStreamP.js +4 -0
  51. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedFromBytesRequestStreamP.js.map +1 -0
  52. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedFromBytesRequestStreamP.ts +26 -0
  53. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedRequestP.d.ts +15 -0
  54. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedRequestP.d.ts.map +1 -0
  55. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedRequestP.js +4 -0
  56. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedRequestP.js.map +1 -0
  57. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressAndSaveAsAdvancedRequestP.ts +18 -0
  58. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressionFlagsP.d.ts +30 -0
  59. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressionFlagsP.d.ts.map +1 -0
  60. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressionFlagsP.js +4 -0
  61. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressionFlagsP.js.map +1 -0
  62. package/src/internal/generated_proto/ironpdfengineproto/QPdfCompressionFlagsP.ts +33 -0
  63. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.d.ts +10 -0
  64. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.d.ts.map +1 -0
  65. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.js +4 -0
  66. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.js.map +1 -0
  67. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestIdP.ts +13 -0
  68. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.d.ts +18 -0
  69. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.d.ts.map +1 -0
  70. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.js +4 -0
  71. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.js.map +1 -0
  72. package/src/internal/generated_proto/ironpdfengineproto/QPdfLinearizeInMemoryRequestStreamP.ts +21 -0
  73. package/src/internal/grpc_layer/chrome/converter.d.ts +10 -0
  74. package/src/internal/grpc_layer/chrome/converter.d.ts.map +1 -1
  75. package/src/internal/grpc_layer/chrome/converter.js +61 -2
  76. package/src/internal/grpc_layer/chrome/converter.js.map +1 -1
  77. package/src/internal/grpc_layer/chrome/converter.ts +67 -0
  78. package/src/internal/grpc_layer/pdfium/annotations.d.ts +30 -0
  79. package/src/internal/grpc_layer/pdfium/annotations.d.ts.map +1 -0
  80. package/src/internal/grpc_layer/pdfium/annotations.js +161 -0
  81. package/src/internal/grpc_layer/pdfium/annotations.js.map +1 -0
  82. package/src/internal/grpc_layer/pdfium/annotations.ts +190 -0
  83. package/src/internal/grpc_layer/pdfium/bookmarks.d.ts +7 -0
  84. package/src/internal/grpc_layer/pdfium/bookmarks.d.ts.map +1 -0
  85. package/src/internal/grpc_layer/pdfium/bookmarks.js +53 -0
  86. package/src/internal/grpc_layer/pdfium/bookmarks.js.map +1 -0
  87. package/src/internal/grpc_layer/pdfium/bookmarks.ts +50 -0
  88. package/src/internal/grpc_layer/pdfium/compress.d.ts +28 -0
  89. package/src/internal/grpc_layer/pdfium/compress.d.ts.map +1 -1
  90. package/src/internal/grpc_layer/pdfium/compress.js +154 -3
  91. package/src/internal/grpc_layer/pdfium/compress.js.map +1 -1
  92. package/src/internal/grpc_layer/pdfium/compress.ts +191 -1
  93. package/src/internal/grpc_layer/pdfium/form.d.ts +15 -0
  94. package/src/internal/grpc_layer/pdfium/form.d.ts.map +1 -0
  95. package/src/internal/grpc_layer/pdfium/form.js +99 -0
  96. package/src/internal/grpc_layer/pdfium/form.js.map +1 -0
  97. package/src/internal/grpc_layer/pdfium/form.ts +119 -0
  98. package/src/internal/grpc_layer/pdfium/formFontValidator.d.ts +26 -0
  99. package/src/internal/grpc_layer/pdfium/formFontValidator.d.ts.map +1 -0
  100. package/src/internal/grpc_layer/pdfium/formFontValidator.js +81 -0
  101. package/src/internal/grpc_layer/pdfium/formFontValidator.js.map +1 -0
  102. package/src/internal/grpc_layer/pdfium/formFontValidator.ts +86 -0
  103. package/src/internal/grpc_layer/pdfium/linearize.d.ts +48 -0
  104. package/src/internal/grpc_layer/pdfium/linearize.d.ts.map +1 -0
  105. package/src/internal/grpc_layer/pdfium/linearize.js +309 -0
  106. package/src/internal/grpc_layer/pdfium/linearize.js.map +1 -0
  107. package/src/internal/grpc_layer/pdfium/linearize.ts +338 -0
  108. package/src/internal/zod/renderSchema.d.ts.map +1 -1
  109. package/src/internal/zod/renderSchema.js +6 -1
  110. package/src/internal/zod/renderSchema.js.map +1 -1
  111. package/src/internal/zod/renderSchema.ts +6 -1
  112. package/src/public/annotation.d.ts +166 -0
  113. package/src/public/annotation.d.ts.map +1 -0
  114. package/src/public/annotation.js +61 -0
  115. package/src/public/annotation.js.map +1 -0
  116. package/src/public/annotation.ts +166 -0
  117. package/src/public/bookmark.d.ts +25 -0
  118. package/src/public/bookmark.d.ts.map +1 -0
  119. package/src/public/bookmark.js +3 -0
  120. package/src/public/bookmark.js.map +1 -0
  121. package/src/public/bookmark.ts +28 -0
  122. package/src/public/compression.d.ts +92 -0
  123. package/src/public/compression.d.ts.map +1 -0
  124. package/src/public/compression.js +26 -0
  125. package/src/public/compression.js.map +1 -0
  126. package/src/public/compression.ts +107 -0
  127. package/src/public/ironpdfglobalconfig.d.ts +12 -0
  128. package/src/public/ironpdfglobalconfig.d.ts.map +1 -1
  129. package/src/public/ironpdfglobalconfig.js +7 -0
  130. package/src/public/ironpdfglobalconfig.js.map +1 -1
  131. package/src/public/ironpdfglobalconfig.ts +19 -0
  132. package/src/public/pdfDocument.d.ts +234 -1
  133. package/src/public/pdfDocument.d.ts.map +1 -1
  134. package/src/public/pdfDocument.js +489 -17
  135. package/src/public/pdfDocument.js.map +1 -1
  136. package/src/public/pdfDocument.ts +518 -19
  137. package/src/public/render.d.ts +104 -0
  138. package/src/public/render.d.ts.map +1 -1
  139. package/src/public/render.js +35 -1
  140. package/src/public/render.js.map +1 -1
  141. package/src/public/render.ts +101 -0
@@ -15,12 +15,14 @@ import {
15
15
  ImageStampOptions,
16
16
  ImageToPdfOptions,
17
17
  ImageType,
18
+ LinearizationMode,
18
19
  PageInfo,
19
20
  PageRotation,
20
21
  PdfInput,
21
22
  PdfPageSelection,
22
23
  PdfPaperSize,
23
24
  PdfPassword, PdfPermission,
25
+ RenderedElementLocation,
24
26
  SaveOptions,
25
27
  TextAffix,
26
28
  TextStampOptions,
@@ -65,7 +67,20 @@ import {mergePdfs, renderHtmlToPdf, renderHtmlZipToPdf, renderUrlToPdf, renderHt
65
67
  import {disposePdf, getBinaryData, openPdfFileBuffer} from "../internal/grpc_layer/pdfium/io";
66
68
  import {Access} from "../internal/access";
67
69
  import {renderImagesBufferToPdf, renderImagesFilesToPdf} from "../internal/grpc_layer/chrome/image";
68
- import {compressAndSaveAs, compressImage, compressInMemory, compressInMemoryStream, compressStructTree} from "../internal/grpc_layer/pdfium/compress";
70
+ import {compressAndSaveAs, compressImage, compressInMemory, compressInMemoryStream, compressStructTree, compressAndSaveAsAdvanced, compressAndSaveAsAdvancedFromBytes} from "../internal/grpc_layer/pdfium/compress";
71
+ import {disableFormFontFallback, setFormFont} from "../internal/grpc_layer/pdfium/form";
72
+ import {AdvancedCompressionOptions} from "./compression";
73
+ import * as path from "path";
74
+ import {
75
+ isLinearizedFromBytes,
76
+ linearizeCoreFromBytes,
77
+ linearizeCoreFromId,
78
+ linearizeInMemoryFromIdStream
79
+ } from "../internal/grpc_layer/pdfium/linearize";
80
+ import {addLinkAnnotation, getAnnotationCount, getAnnotations} from "../internal/grpc_layer/pdfium/annotations";
81
+ import {LinkAnnotation} from "./annotation";
82
+ import {getBookmarks} from "../internal/grpc_layer/pdfium/bookmarks";
83
+ import {Bookmark} from "./bookmark";
69
84
  import {Readable} from "stream";
70
85
  import {
71
86
  duplicate,
@@ -78,7 +93,7 @@ import {
78
93
  import {extractRawImages, rasterizeToImageBuffers} from "../internal/grpc_layer/pdfium/image";
79
94
  import Jimp from "jimp";
80
95
  import {extractAllText, replaceText} from "../internal/grpc_layer/pdfium/text";
81
- import {PdfAVersions, PdfUAVersions, toPdfA, toPdfUA} from "../internal/grpc_layer/pdfium/pdfa";
96
+ import {PdfAVersions, PdfUAVersions, toPdfA, toPdfUA, toPdfUAForScreenReader} from "../internal/grpc_layer/pdfium/pdfa";
82
97
  import {getMetadataDict, removeMetadata, setMetadata, setMetadataDict} from "../internal/grpc_layer/pdfium/metadata";
83
98
  import {getSignatureCount, getVerifiedSignatures, signPdf} from "../internal/grpc_layer/pdfium/signing";
84
99
  import {addHtmlAffix, addTextAffix} from "../internal/grpc_layer/pdfium/headerFooter";
@@ -459,6 +474,324 @@ export class PdfDocument{
459
474
  (filePath, imageQuality);
460
475
  }
461
476
 
477
+ /**
478
+ * Apply the advanced compression pipeline and save the result to a file.
479
+ *
480
+ * Combines pdfium-side image DPI downsampling with qpdf-side structural
481
+ * optimization in a single call.
482
+ *
483
+ * @param filePath the file path to save the compressed PDF
484
+ * @param options advanced compression options; pass an empty object `{}` to
485
+ * reproduce the legacy compressAndSaveAs behaviour with no
486
+ * image downsampling
487
+ * @param password the PDF password (empty string if none)
488
+ */
489
+ public async compressAndSaveAsAdvanced(
490
+ filePath: string,
491
+ options: AdvancedCompressionOptions,
492
+ password?: string
493
+ ): Promise<void> {
494
+ return this.internal_compressAndSaveAsAdvanced(filePath, options, password);
495
+ }
496
+
497
+ /**
498
+ * Apply the advanced compression pipeline to byte[] input and save the
499
+ * compressed result to a file. Returns the compressed bytes as well.
500
+ */
501
+ public static async compressAndSaveAsAdvancedFromBytes(
502
+ pdfBytes: Buffer,
503
+ filePath: string,
504
+ options: AdvancedCompressionOptions,
505
+ password?: string
506
+ ): Promise<Buffer> {
507
+ if (!pdfBytes || pdfBytes.length === 0) {
508
+ throw new Error("pdfBytes must not be null or empty");
509
+ }
510
+ if (!options) {
511
+ throw new Error("options must not be null");
512
+ }
513
+ return compressAndSaveAsAdvancedFromBytes(pdfBytes, filePath, options, password ?? "");
514
+ }
515
+
516
+ //#endregion
517
+
518
+ //#region form (PDF-2184)
519
+
520
+ /**
521
+ * Set the document-wide form font for subsequent form-field fills. When
522
+ * set, the engine skips its automatic Tahoma/Arial fallback embed for
523
+ * non-ASCII form values and registers the supplied font in the AcroForm
524
+ * /DR /Font dictionary so default-appearance strings resolve correctly
525
+ * at render time.
526
+ *
527
+ * File-size impact:
528
+ * - Name-only mode (`fontData` omitted or empty): zero bytes added; the
529
+ * font must already be in the document.
530
+ * - Bytes mode and the font is already embedded with usable glyph data:
531
+ * zero bytes added.
532
+ * - Bytes mode and the font is missing or has no glyph data: the full
533
+ * font is embedded.
534
+ * - Bytes mode with `forceEmbed = true`: a fresh font copy is added
535
+ * alongside any existing copy; the document grows on every call.
536
+ *
537
+ * @param fontName PDF font name to register (e.g. "Poppins-Regular").
538
+ * Allowed characters: letters, digits, `_`, `-`, `.`, `+`.
539
+ * @param fontData Raw TrueType/OpenType bytes; pass `undefined` or an
540
+ * empty Buffer for name-only mode.
541
+ * @param forceEmbed When true, embed `fontData` even if a font with the
542
+ * same name and usable glyph data is already present.
543
+ */
544
+ public async setFormFont(
545
+ fontName: string,
546
+ fontData?: Buffer,
547
+ forceEmbed = false
548
+ ): Promise<void> {
549
+ return setFormFont(await this.internal_getId(), fontName, fontData, forceEmbed);
550
+ }
551
+
552
+ /**
553
+ * Load a TrueType/OpenType font from disk and apply it as the
554
+ * document-wide form font. The PDF font name is derived from the file
555
+ * name (without extension) when `fontName` is omitted.
556
+ *
557
+ * @param fontFilePath Path to a TTF/OTF/TTC font file
558
+ * @param fontName Optional PDF font name. When omitted the file name
559
+ * (without extension) is used.
560
+ * @param forceEmbed When true, embed even if the font is already present.
561
+ */
562
+ public async setFormFontFromFile(
563
+ fontFilePath: string,
564
+ fontName?: string,
565
+ forceEmbed = false
566
+ ): Promise<void> {
567
+ if (!fontFilePath) {
568
+ throw new Error("fontFilePath must not be empty");
569
+ }
570
+ const fontData = fs.readFileSync(fontFilePath);
571
+ const resolvedName = fontName ?? deriveFontNameFromPath(fontFilePath);
572
+ return setFormFont(await this.internal_getId(), resolvedName, fontData, forceEmbed);
573
+ }
574
+
575
+ /**
576
+ * Suppress the automatic Tahoma/Arial fallback embed for non-ASCII form
577
+ * values without registering any replacement font. Use when zero
578
+ * file-size growth is required and the template's existing font
579
+ * references are sufficient for the values being filled.
580
+ *
581
+ * Rendering of non-ASCII characters then depends entirely on the
582
+ * viewer's font substitution.
583
+ */
584
+ public async disableFormFontFallback(): Promise<void> {
585
+ return disableFormFontFallback(await this.internal_getId());
586
+ }
587
+
588
+ //#endregion
589
+
590
+ //#region linearize
591
+ /**
592
+ * Linearize the current PDF document and return the result as a {@link Buffer} (byte array).
593
+ * Produces a web-optimized PDF that can be viewed incrementally in a browser.
594
+ *
595
+ * @param mode Linearization strategy. Defaults to {@link LinearizationMode.Automatic}.
596
+ * @returns A Promise resolving to a Buffer containing the linearized PDF bytes.
597
+ */
598
+ public async linearizePdfToBytes(
599
+ mode: LinearizationMode = LinearizationMode.Automatic
600
+ ): Promise<Buffer> {
601
+ return this.internal_linearizePdfToBytes(mode);
602
+ }
603
+
604
+ /**
605
+ * Linearize the current PDF document and return the result as a {@link Readable} stream.
606
+ * Useful for piping directly to file streams or HTTP responses without buffering the
607
+ * entire PDF in memory.
608
+ *
609
+ * <b>Note:</b> Stream output is only supported with {@link LinearizationMode.InMemory}
610
+ * (or {@link LinearizationMode.Automatic} when memory mode is selected). For
611
+ * {@link LinearizationMode.FileBased} use {@link linearizePdfToBytes} or
612
+ * {@link saveAsLinearized}.
613
+ *
614
+ * @returns A Promise resolving to a Readable stream of the linearized PDF bytes.
615
+ */
616
+ public async linearizePdfToStream(): Promise<Readable> {
617
+ return this.internal_linearizePdfToStream();
618
+ }
619
+
620
+ /**
621
+ * Linearize the current PDF document and save the result to the given output file path.
622
+ *
623
+ * @param outputFilePath The file path to save the linearized PDF.
624
+ * @param mode Linearization strategy. Defaults to {@link LinearizationMode.Automatic}.
625
+ */
626
+ public async saveAsLinearized(
627
+ outputFilePath: string,
628
+ mode: LinearizationMode = LinearizationMode.Automatic
629
+ ): Promise<void> {
630
+ return await z.function()
631
+ .args(filePathSchema, z.nativeEnum(LinearizationMode).optional())
632
+ .returns(z.promise(z.void()))
633
+ .implement(async (filePath: string, m?: LinearizationMode): Promise<void> => {
634
+ return this.internal_saveAsLinearized(filePath, m ?? LinearizationMode.Automatic);
635
+ })
636
+ (outputFilePath, mode);
637
+ }
638
+
639
+ /**
640
+ * Check whether the PDF file at the given path is linearized ("Fast Web View").
641
+ *
642
+ * @param pdfFilePath Path to a PDF file on disk.
643
+ * @param password Optional password for encrypted PDFs.
644
+ * @returns A Promise resolving to true if the file is linearized, false otherwise.
645
+ */
646
+ public static async isLinearized(
647
+ pdfFilePath: string,
648
+ password = ""
649
+ ): Promise<boolean> {
650
+ return await z.function()
651
+ .args(pdfFilePathSchema, stringSchema.optional())
652
+ .returns(z.promise(booleanSchema))
653
+ .implement(async (filePath: string, pwd?: string): Promise<boolean> => {
654
+ const bytes = fs.readFileSync(filePath);
655
+ return await isLinearizedFromBytes(bytes, pwd ?? "");
656
+ })
657
+ (pdfFilePath, password);
658
+ }
659
+
660
+ /**
661
+ * Linearize the given PDF bytes and return the linearized bytes.
662
+ * Static helper for linearizing PDFs without creating a PdfDocument instance.
663
+ *
664
+ * @param pdfBytes Buffer containing the PDF data.
665
+ * @param password Optional password to decrypt the PDF if encrypted.
666
+ * @param mode Linearization strategy. Defaults to {@link LinearizationMode.Automatic}.
667
+ */
668
+ public static async linearizePdfBytesToBytes(
669
+ pdfBytes: Buffer,
670
+ password = "",
671
+ mode: LinearizationMode = LinearizationMode.Automatic
672
+ ): Promise<Buffer> {
673
+ return await z.function()
674
+ .args(bufferSchema, stringSchema.optional(), z.nativeEnum(LinearizationMode).optional())
675
+ .returns(z.promise(z.instanceof(Buffer)))
676
+ .implement(async (bytes: Buffer, pwd?: string, m?: LinearizationMode): Promise<Buffer> => {
677
+ return await linearizeCoreFromBytes(bytes, pwd ?? "", m ?? LinearizationMode.Automatic);
678
+ })
679
+ (pdfBytes, password, mode);
680
+ }
681
+
682
+ /**
683
+ * Linearize the given PDF bytes and save the result to the given output file path.
684
+ * Static helper for linearizing PDFs without creating a PdfDocument instance.
685
+ *
686
+ * @param pdfBytes Buffer containing the PDF data.
687
+ * @param outputFilePath The file path to save the linearized PDF.
688
+ * @param password Optional password to decrypt the PDF if encrypted.
689
+ * @param mode Linearization strategy. Defaults to {@link LinearizationMode.Automatic}.
690
+ */
691
+ public static async saveAsLinearizedFromBytes(
692
+ pdfBytes: Buffer,
693
+ outputFilePath: string,
694
+ password = "",
695
+ mode: LinearizationMode = LinearizationMode.Automatic
696
+ ): Promise<void> {
697
+ return await z.function()
698
+ .args(bufferSchema, filePathSchema, stringSchema.optional(), z.nativeEnum(LinearizationMode).optional())
699
+ .returns(z.promise(z.void()))
700
+ .implement(async (bytes: Buffer, filePath: string, pwd?: string, m?: LinearizationMode): Promise<void> => {
701
+ const linearized = await linearizeCoreFromBytes(bytes, pwd ?? "", m ?? LinearizationMode.Automatic);
702
+ fs.writeFileSync(filePath, linearized);
703
+ })
704
+ (pdfBytes, outputFilePath, password, mode);
705
+ }
706
+ //#endregion
707
+
708
+ //#region elementLocations
709
+ /**
710
+ * Retrieves the rendered page locations of HTML elements that were tracked during rendering.
711
+ *
712
+ * To use this feature, set {@link ChromePdfRenderOptions.elementQuerySelectors} with CSS
713
+ * selectors before rendering. After rendering, call this method to retrieve the page index
714
+ * and coordinates of each matched element.
715
+ *
716
+ * Results are cached on first call and reused on subsequent calls. If you modify the
717
+ * document's annotations after rendering, call {@link resetElementLocationCache} to force
718
+ * the cache to be rebuilt on next access.
719
+ *
720
+ * Mirrors {@code IronPdf.PdfDocument.GetElementLocations()} on the C# side.
721
+ *
722
+ * @returns A list of {@link RenderedElementLocation} objects, one per matched element,
723
+ * sorted in document order. Returns an empty list if no element query selectors were
724
+ * configured or no elements matched.
725
+ */
726
+ public async getElementLocations(): Promise<RenderedElementLocation[]> {
727
+ return this.internal_getElementLocations();
728
+ }
729
+
730
+ /**
731
+ * Clears the cached result of {@link getElementLocations}, forcing a fresh scan of the
732
+ * document's annotations on the next call. Call this if you've modified the document's
733
+ * annotations or structure after rendering.
734
+ */
735
+ public resetElementLocationCache(): void {
736
+ this.cachedElementLocations = null;
737
+ }
738
+ //#endregion
739
+
740
+ //#region bookmarks
741
+ /**
742
+ * Retrieves all outline bookmarks (table-of-contents entries) in this PDF document.
743
+ *
744
+ * <p>Bookmarks are returned as a flat list with parent linkage via
745
+ * {@link Bookmark.parentItemId}. Roots have an empty {@code parentItemId}.
746
+ * Use {@link Bookmark.hierarchy} for depth information.</p>
747
+ *
748
+ * <p>Auto-bookmarks generated from HTML headings (via
749
+ * {@link ChromePdfRenderOptions.autoBookmarksFromHeadings}) are included.</p>
750
+ *
751
+ * <p>Mirrors {@code IronPdf.PdfDocument.Bookmarks} on the C# side.</p>
752
+ *
753
+ * @returns A list of {@link Bookmark} objects, sorted in document order.
754
+ * Returns an empty list if the document has no bookmarks.
755
+ */
756
+ public async getBookmarks(): Promise<Bookmark[]> {
757
+ return this.internal_getBookmarks();
758
+ }
759
+ //#endregion
760
+
761
+ //#region annotation
762
+ /**
763
+ * Adds a clickable internal hyperlink annotation that navigates to another page within
764
+ * the same PDF document. Useful for building custom tables of contents, cross-references,
765
+ * and in-document navigation.
766
+ *
767
+ * The target page and display options are configured via the {@link LinkAnnotation}
768
+ * fields ({@code destinationPageIndex}, {@code destinationType}, etc.).
769
+ *
770
+ * Mirrors {@code IronPdf.Annotations.LinkAnnotation} on the C# side.
771
+ *
772
+ * @example
773
+ * ```ts
774
+ * await pdf.addLinkAnnotation({
775
+ * pageIndex: 0,
776
+ * destinationPageIndex: 3,
777
+ * x: 72, y: 700,
778
+ * width: 300, height: 18,
779
+ * contents: "Chapter 1",
780
+ * });
781
+ * ```
782
+ */
783
+ public async addLinkAnnotation(link: LinkAnnotation): Promise<void> {
784
+ return this.internal_addLinkAnnotation(link);
785
+ }
786
+
787
+ /**
788
+ * Retrieves the number of annotations contained on the specified page.
789
+ *
790
+ * @param pageIndex Zero-based page index. The first page has a page index of 0.
791
+ */
792
+ public async getAnnotationCount(pageIndex: number): Promise<number> {
793
+ return this.internal_getAnnotationCount(pageIndex);
794
+ }
462
795
  //#endregion
463
796
 
464
797
  //#region page
@@ -735,23 +1068,24 @@ export class PdfDocument{
735
1068
  (pdfaVersion, customICC);
736
1069
  }
737
1070
 
738
- // TODO: Re-enable once IronPdfEngine handler for Pdfium_ConvertToPdfUAForScreenReader
739
- // is fixed to call HtmlHelper.HtmlStructTreeDOM() and ConvertToPdfUAForScreenReader().
740
- // Currently the engine handler ignores the HTML and falls back to basic ConvertToPdfUA,
741
- // producing a flat tag tree instead of proper semantic structure.
742
- // See: IronPdfServiceHandler.cs:97-108
743
- //
744
- // public static async fromHtmlAsPdfUA(
745
- // html: string,
746
- // naturalLanguages: NaturalLanguages = NaturalLanguages.English,
747
- // options?: {
748
- // renderOptions?: ChromePdfRenderOptions | undefined;
749
- // } | undefined
750
- // ): Promise<PdfDocument> {
751
- // const pdf = await PdfDocument.fromHtml(html, options);
752
- // await toPdfUAForScreenReader(await pdf.internal_getId(), html, naturalLanguages);
753
- // return pdf;
754
- // }
1071
+ /**
1072
+ * Render HTML to PDF and convert to PDF/UA format with screen reader support.
1073
+ * Produces a proper semantic structure tree (Sect H1, P, etc.) for accessibility.
1074
+ * @param html The HTML string to render
1075
+ * @param naturalLanguages Document language for screen readers (default: English)
1076
+ * @param options Optional render options
1077
+ */
1078
+ public static async fromHtmlAsPdfUA(
1079
+ html: string,
1080
+ naturalLanguages: NaturalLanguages = NaturalLanguages.English,
1081
+ options?: {
1082
+ renderOptions?: ChromePdfRenderOptions | undefined;
1083
+ } | undefined
1084
+ ): Promise<PdfDocument> {
1085
+ const pdf = await PdfDocument.fromHtml(html, options);
1086
+ await toPdfUAForScreenReader(await pdf.internal_getId(), html, naturalLanguages);
1087
+ return pdf;
1088
+ }
755
1089
 
756
1090
  /**
757
1091
  * Convert the current document into the specified PDF/UA standard format
@@ -1619,6 +1953,160 @@ export class PdfDocument{
1619
1953
  );
1620
1954
  }
1621
1955
 
1956
+ private async internal_compressAndSaveAsAdvanced(
1957
+ filePath: string,
1958
+ options: AdvancedCompressionOptions,
1959
+ password?: string
1960
+ ): Promise<void> {
1961
+ if (!filePath || filePath.trim().length === 0) {
1962
+ throw new Error("filePath must not be empty");
1963
+ }
1964
+ if (!options) {
1965
+ throw new Error("options must not be null");
1966
+ }
1967
+ if (
1968
+ options.jpegQuality !== undefined &&
1969
+ options.jpegQuality !== null &&
1970
+ (options.jpegQuality < 1 || options.jpegQuality > 100)
1971
+ ) {
1972
+ throw new Error(
1973
+ `Invalid jpegQuality (${options.jpegQuality}). Must be between 1 and 100.`
1974
+ );
1975
+ }
1976
+ return await compressAndSaveAsAdvanced(
1977
+ await this.internal_getId(),
1978
+ filePath,
1979
+ options,
1980
+ password ?? ""
1981
+ );
1982
+ }
1983
+
1984
+ //#endregion
1985
+
1986
+ //#region linearize
1987
+ /**
1988
+ * Linearize the current PDF document and return the result as a Buffer.
1989
+ */
1990
+ private async internal_linearizePdfToBytes(mode: LinearizationMode): Promise<Buffer> {
1991
+ const id = await this.internal_getId();
1992
+ return await linearizeCoreFromId(id, () => this.internal_saveAsBuffer(), "", mode);
1993
+ }
1994
+
1995
+ /**
1996
+ * Linearize the current PDF document and return the result as a Readable stream.
1997
+ * Always uses the in-memory streaming RPC.
1998
+ */
1999
+ private async internal_linearizePdfToStream(): Promise<Readable> {
2000
+ return await linearizeInMemoryFromIdStream(await this.internal_getId());
2001
+ }
2002
+
2003
+ /**
2004
+ * Linearize the current PDF document and save the result to the given output file path.
2005
+ */
2006
+ private async internal_saveAsLinearized(outputFilePath: string, mode: LinearizationMode): Promise<void> {
2007
+ const id = await this.internal_getId();
2008
+ const linearized = await linearizeCoreFromId(id, () => this.internal_saveAsBuffer(), "", mode);
2009
+ fs.writeFileSync(outputFilePath, linearized);
2010
+ }
2011
+ //#endregion
2012
+
2013
+ //#region elementLocations
2014
+ /**
2015
+ * Prefix used by the engine-side element query JavaScript extension when injecting anchor
2016
+ * markers. Must match {@code IronPdf.TableOfContents.ElementQueryJavascriptExtension.ELEMENT_QUERY_PREFIX}
2017
+ * on the C# side.
2018
+ */
2019
+ private static readonly ELEMENT_QUERY_PREFIX = "ironpdf-elq-";
2020
+
2021
+ /**
2022
+ * Cache for {@link getElementLocations}. Built lazily on first call.
2023
+ *
2024
+ * The underlying element-query anchor annotations are written during rendering and are
2025
+ * not expected to be mutated afterwards, so a simple populate-once cache is appropriate.
2026
+ * Callers who modify the document's annotations after rendering should call
2027
+ * {@link resetElementLocationCache} to force a rebuild.
2028
+ */
2029
+ private cachedElementLocations: RenderedElementLocation[] | null = null;
2030
+
2031
+ private async internal_getElementLocations(): Promise<RenderedElementLocation[]> {
2032
+ if (this.cachedElementLocations !== null) {
2033
+ return this.cachedElementLocations;
2034
+ }
2035
+
2036
+ const id = await this.internal_getId();
2037
+ const pageInfos = await getPageInfo(id);
2038
+ const locations: RenderedElementLocation[] = [];
2039
+
2040
+ for (let pageIdx = 0; pageIdx < pageInfos.length; pageIdx++) {
2041
+ const annotations = await getAnnotations(id, pageIdx);
2042
+
2043
+ for (const wrapped of annotations) {
2044
+ if (!wrapped.link) continue;
2045
+ const dest = wrapped.link.dest;
2046
+ if (!dest || !dest.startsWith(PdfDocument.ELEMENT_QUERY_PREFIX)) continue;
2047
+
2048
+ const remainder = dest.substring(PdfDocument.ELEMENT_QUERY_PREFIX.length);
2049
+ const dashIdx = remainder.indexOf("-");
2050
+ if (dashIdx <= 0) continue;
2051
+
2052
+ const indexStr = remainder.substring(0, dashIdx);
2053
+ const elementIndex = parseInt(indexStr, 10);
2054
+ if (isNaN(elementIndex)) continue;
2055
+
2056
+ const encodedText = remainder.substring(dashIdx + 1);
2057
+ let text: string;
2058
+ try {
2059
+ text = decodeURIComponent(encodedText);
2060
+ } catch {
2061
+ text = encodedText;
2062
+ }
2063
+
2064
+ const innerRect = wrapped.link.annotation?.rectangle;
2065
+ const rectangle = innerRect
2066
+ ? {
2067
+ x: innerRect.x ?? 0,
2068
+ y: innerRect.y ?? 0,
2069
+ width: innerRect.width ?? 0,
2070
+ height: innerRect.height ?? 0,
2071
+ }
2072
+ : {x: 0, y: 0, width: 0, height: 0};
2073
+
2074
+ locations.push({text, pageIndex: pageIdx, rectangle, elementIndex});
2075
+ }
2076
+ }
2077
+
2078
+ locations.sort((a, b) => a.elementIndex - b.elementIndex);
2079
+ this.cachedElementLocations = locations;
2080
+ return this.cachedElementLocations;
2081
+ }
2082
+ //#endregion
2083
+
2084
+ //#region annotation
2085
+ private async internal_addLinkAnnotation(link: LinkAnnotation): Promise<void> {
2086
+ if (!link) {
2087
+ throw new Error("link annotation cannot be null or undefined");
2088
+ }
2089
+ if (link.pageIndex < 0) {
2090
+ throw new Error("Invalid page index when adding link annotation");
2091
+ }
2092
+ if (link.destinationPageIndex < 0) {
2093
+ throw new Error("Invalid destination page index when adding link annotation");
2094
+ }
2095
+ await addLinkAnnotation(await this.internal_getId(), link);
2096
+ }
2097
+
2098
+ private async internal_getAnnotationCount(pageIndex: number): Promise<number> {
2099
+ if (pageIndex < 0) {
2100
+ throw new Error("Invalid page index when getting annotation count");
2101
+ }
2102
+ return await getAnnotationCount(await this.internal_getId(), pageIndex);
2103
+ }
2104
+ //#endregion
2105
+
2106
+ //#region bookmarks
2107
+ private async internal_getBookmarks(): Promise<Bookmark[]> {
2108
+ return await getBookmarks(await this.internal_getId());
2109
+ }
1622
2110
  //#endregion
1623
2111
 
1624
2112
  //#region page
@@ -2224,3 +2712,14 @@ export class PdfDocument{
2224
2712
 
2225
2713
  //#endregion
2226
2714
  }
2715
+
2716
+ /**
2717
+ * Derive a PDF font name from a font file path: strip the directory and the
2718
+ * extension. Used by {@link PdfDocument.setFormFontFromFile} when no
2719
+ * explicit name is supplied.
2720
+ */
2721
+ function deriveFontNameFromPath(fontFilePath: string): string {
2722
+ const base = path.basename(fontFilePath);
2723
+ const dot = base.lastIndexOf(".");
2724
+ return dot > 0 ? base.substring(0, dot) : base;
2725
+ }