import {Buffer} from "buffer"; import { BarcodeStampOptions, BarcodeType, ChangeTrackingModes, ChromePdfRenderOptions, DigitalSignature, VerifiedSignature, HtmlAffix, HtmlFilePath, HtmlStampOptions, HtmlString, HttpLoginCredentials, ImageBuffer, ImageFilePath, ImageStampOptions, ImageToPdfOptions, ImageType, PageInfo, PageRotation, PdfInput, PdfPageSelection, PdfPaperSize, PdfPassword, PdfPermission, SaveOptions, TextAffix, TextStampOptions, } from "./types"; import { barcodeTypeSchema, booleanSchema, bufferArraySchema, bufferSchema, changeTrackingModesSchema, filePathSchema, htmlFilePathSchema, htmlStringSchema, imageBufferSchema, imageFilePathSchema, mapStringSchema, numberSchema, pdfFilePathSchema, pdfInputSchema, pdfPageSelectionSchema, pdfPasswordSchema, saveOptionsSchema, stringArraySchema, stringSchema, urlSchema } from "../internal/zod/typeSchema"; import {z} from "zod"; import {pdfPermissionSchema} from "../internal/zod/securitySchema"; import {pdfDocumentSchema} from "../internal/zod/pdfDocumentSchema"; import { barcodeStampOptionsSchema, htmlStampOptionsSchema, imageStampOptionsSchema, textStampOptionsSchema } from "../internal/zod/stampSchema"; import {htmlAffixSchema, textAffixSchema} from "../internal/zod/affixSchema"; import {digitalSignatureSchema} from "../internal/zod/signatureSchema"; import {imageToPdfOptionsSchema, imageTypeSchema} from "../internal/zod/imageSchema"; import {pdfPaperSizeSchema} from "../internal/zod/paperSchema"; import {pageRotationSchema} from "../internal/zod/pageSchema"; import {chromePdfRenderOptionsSchema, httpLoginCredentialsSchema} from "../internal/zod/renderSchema"; import { getFileName, getImageExtType, separateImageBufferOrImagePathInput, separatePdfInput } from "../internal/grpc_layer/util"; import fs from "fs"; import {mergePdfs, renderHtmlToPdf, renderHtmlZipToPdf, renderUrlToPdf, renderHtmlFileToPdf} from "../internal/grpc_layer/chrome/render"; import {disposePdf, getBinaryData, openPdfFileBuffer} from "../internal/grpc_layer/pdfium/io"; import {Access} from "../internal/access"; import {renderImagesBufferToPdf, renderImagesFilesToPdf} from "../internal/grpc_layer/chrome/image"; import {compressAndSaveAs, compressImage, compressInMemory, compressInMemoryStream, compressStructTree} from "../internal/grpc_layer/pdfium/compress"; import {Readable} from "stream"; import { duplicate, getPageInfo, insertPdf, removePage, resizePage, setPageRotation } from "../internal/grpc_layer/pdfium/page"; import {extractRawImages, rasterizeToImageBuffers} from "../internal/grpc_layer/pdfium/image"; import Jimp from "jimp"; import {extractAllText, replaceText} from "../internal/grpc_layer/pdfium/text"; import {PdfAVersions, PdfUAVersions, toPdfA, toPdfUA} from "../internal/grpc_layer/pdfium/pdfa"; import {getMetadataDict, removeMetadata, setMetadata, setMetadataDict} from "../internal/grpc_layer/pdfium/metadata"; import {getSignatureCount, getVerifiedSignatures, signPdf} from "../internal/grpc_layer/pdfium/signing"; import {addHtmlAffix, addTextAffix} from "../internal/grpc_layer/pdfium/headerFooter"; import {stampBarcode, stampHtml, stampImage, stampText} from "../internal/grpc_layer/chrome/stamp"; import {addBackgroundForeground} from "../internal/grpc_layer/pdfium/BackgroundForeground"; import { getPermission, removePasswordsAndEncryption, setOwnerPasswords, setSecurity, setUserPasswords } from "../internal/grpc_layer/pdfium/security"; import { NaturalLanguages } from "./naturalLanguages"; /** * Represents a PDF document. Allows: loading, editing, manipulating, merging, signing printing and saving PDFs. * * @remark Make sure that you call {@link PdfDocument.close} or {@link cleanUp} to free the memory, when you stop using the PdfDocument object. */ export class PdfDocument{ //#region io /** * Open or Create a PdfDocument from a {@link PdfInput} * @param pdfInput {@link PdfInput} * @param options including {@link PdfPassword} {@link ChromePdfRenderOptions} {@link HttpLoginCredentials} mainHtmlFile */ public static async open( pdfInput: PdfInput, options?: { /** * required for open a protected PDF file * @default undefined */ password?: PdfPassword | undefined; /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; /** * Apply httpLoginCredentials if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ httpLoginCredentials?: HttpLoginCredentials | undefined; /** * Apply mainHtmlFile if PdfInput is {@link ZipFilePath} * @default index.html */ mainHtmlFile?: string | undefined; /** * Optionally track changes to the document (for use with incremental saves) * @default {@link ChangeTrackingModes.AutoChangeTracking} */ trackChanges?: ChangeTrackingModes | undefined; // /** // * Apply baseUrl if // * The HTML base URL for which references to external CSS, Javascript and Image files will be relative. // * @default undefined // */ // baseUrl ?: string | undefined; //not supported } | undefined ): Promise { return z.function() .args( pdfInputSchema, z.object({ password: pdfPasswordSchema.optional(), renderOptions: chromePdfRenderOptionsSchema.optional(), httpLoginCredentials: httpLoginCredentialsSchema.optional(), mainHtmlFile: stringSchema.optional(), trackChanges: changeTrackingModesSchema.optional(), }).optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_open.bind(this)) (pdfInput, options); } /** * Open a PdfDocument from .pdf file * @param pdfFilePath A path to .pdf file * @param Optionally track changes to the document (for use with incremental saves) */ public static async fromFile( pdfFilePath: string, trackChanges?: ChangeTrackingModes | undefined ): Promise { return z.function() .args( pdfFilePathSchema, changeTrackingModesSchema.optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_fromFile.bind(this)) (pdfFilePath, trackChanges); } /** * Create a PdfDocument from an Url * @param url A website Url * @param options including {@link ChromePdfRenderOptions} */ public static async fromUrl( url: URL | string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; } | undefined ): Promise { return z.function() .args( z.union([urlSchema, stringSchema]), z.object({ renderOptions: chromePdfRenderOptionsSchema.optional(), }).optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_fromUrl.bind(this)) (url, options); } /** * Creates a PDF file from a local Zip file, and returns it as a {@link PdfDocument}. * IronPDF is a W3C standards compliant HTML rendering based on Google's Chromium browser. * If your output PDF does not look as expected: * * - Validate your HTML file using https://validator.w3.org/ & CSS https://jigsaw.w3.org/css-validator/ * * - To debug HTML, view the file in Chrome web browser's print preview which will work almost exactly as IronPDF. * * - Read our detailed documentation on pixel perfect HTML to PDF: https://ironpdf.com/tutorials/pixel-perfect-html-to-pdf/ * * @param zipFilePath Path to a Zip to be rendered as a PDF. * @param options including {@link ChromePdfRenderOptions} and `mainHtmlFile` a main .html file default: `index.html` */ public static async fromZip( zipFilePath: string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; /** * a main .html file default: `index.html` */ mainHtmlFile?: string | undefined; } | undefined ): Promise { return z.function() .args( stringSchema, z.object({ renderOptions: chromePdfRenderOptionsSchema.optional(), mainHtmlFile: stringSchema.optional() }).optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_fromZip.bind(this)) (zipFilePath, options); } /** * Creates a PDF file from a Html string, and returns it as an {@link PdfDocument} object which can be edited and saved to disk or served on a website. * * ------------------------------------------------ * * **Usage:** * ```ts * const pdf = await fromHtml(htmlStringOrHtmlFilePath, renderOptions); * ``` * * ------------------------------------------------ * * @param htmlStringOrHtmlFilePath The Html to be rendered as a PDF. * @param options including {@link ChromePdfRenderOptions} * @returns A `PdfDocument` generated from the provided HTML file. * * --- * ### Important Notes: * * 🐳 **Docker Limitation:** * This method **does not work** for **HTML file path** when the application runs inside a Docker environment * due to rendering engine restrictions. * In such cases, use `fromZip()` instead. * * 📄 **Input:** Requires access to a local HTML file on disk if htmlFilePath is passing. * * --- * ### Related Methods: * 📌 `fromZip()` — Recommended alternative for rendering from HTML file when running inside Docker. */ public static async fromHtml( htmlStringOrHtmlFilePath: string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; } | undefined ): Promise { return z.function() .args( stringSchema, z.object({ renderOptions: chromePdfRenderOptionsSchema.optional(), }).optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_fromHtml.bind(this)) (htmlStringOrHtmlFilePath, options); } /** * Converts multiple image files to a PDF document. Each image creates 1 page which matches the image * dimensions. The default PaperSize is A4. You can set it via ImageToPdfConverter.PaperSize. * Note: Imaging.ImageBehavior.CropPage will set PaperSize equal to ImageSize. * @param images The image file path name(s) or {@link ImageBuffer} object(s) * @param options including {@link ImageToPdfOptions} */ public static async fromImage( images: ImageFilePath | ImageFilePath[] | ImageBuffer | ImageBuffer[], options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ imageToPdfOptions?: ImageToPdfOptions | undefined; } ): Promise { return z.function() .args( z.union([imageFilePathSchema, z.array(imageFilePathSchema), imageBufferSchema, z.array(imageBufferSchema)]), z.object({ imageToPdfOptions: imageToPdfOptionsSchema.optional(), }).optional() ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_fromImage.bind(this)) (images, options); } /** * Static method that joins (concatenates) multiple PDF documents together into one compiled PDF document. * If the PDF contains form fields the form field in the resulting PDF's name will be appended with '_{index}' e.g. 'Name' will be 'Name_0' * @param pdfs array of PDF */ public static async mergePdf(pdfs: PdfInput[]): Promise { return z.function() .args( z.array(pdfInputSchema) ) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_mergePdf.bind(this)) (pdfs); } /** * Saves the PdfDocument to a file. * @param filePath Target file path * @param saveOptions see {@link SaveOptions} */ public saveAs(filePath: string, saveOptions?: SaveOptions | undefined): Promise { return z.function() .args( stringSchema, saveOptionsSchema.optional() ) .returns(z.promise(z.void())) .implement(this.internal_saveAs.bind(this)) (filePath, saveOptions); } /** * Saves the PdfDocument to a binary (Buffer) * @param saveOptions see {@link SaveOptions} */ public async saveAsBuffer(saveOptions?: SaveOptions | undefined): Promise { return z.function() .args( saveOptionsSchema.optional() ) .returns(z.promise(bufferSchema)) .implement(this.internal_saveAsBuffer.bind(this)) (saveOptions); } //#endregion //#region compress /** * Compress existing PDF images using JPG encoding and the specified settings. * @deprecated Use {@link compressAndSaveAs}, {@link compressPdfToBytes}, or {@link compressPdfToStream} instead for better compression results. * @param imageQuality Quality (1 - 100) to use during compression * @param scaleToVisibleSize Scale down the image resolution according to its visible size in the PDF document */ public async compressSize( imageQuality: number, scaleToVisibleSize = false ): Promise { return await z.function() .args( numberSchema, booleanSchema.optional() ) .returns(z.promise(z.void())) .implement(this.internal_compressSize.bind(this)) (imageQuality, scaleToVisibleSize); } /** * Remove document struct tree information which describes the logical layout of the document. * Removing the "structure tree" can significantly reduce the disk space used by the document. * Removing the "structure tree" of a complicated document can negatively impact text selection. */ public async compressStructTree(): Promise { return this.internal_compressStructTree() } /** * Compress the PDF and return the result as a Buffer (byte array). * Uses QPdf compression which can significantly reduce file size. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. * @returns A Promise resolving to a Buffer containing the compressed PDF bytes. */ public async compressPdfToBytes( imageQuality?: number ): Promise { return await z.function() .args( numberSchema.optional() ) .returns(z.promise(z.instanceof(Buffer))) .implement(this.internal_compressPdfToBytes.bind(this)) (imageQuality); } /** * Compress the PDF and return the result as a Readable stream. * Uses QPdf compression which can significantly reduce file size. * Useful for piping directly to file streams or HTTP responses without buffering the entire PDF in memory. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. * @returns A Promise resolving to a Readable stream of the compressed PDF bytes. */ public async compressPdfToStream( imageQuality?: number ): Promise { return await z.function() .args( numberSchema.optional() ) .returns(z.promise(z.any())) .implement(this.internal_compressPdfToStream.bind(this)) (imageQuality); } /** * Compress the PDF and save the result directly to a file. * Uses QPdf compression which can significantly reduce file size. * @param filePath The output file path to save the compressed PDF. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. */ public async compressAndSaveAs( filePath: string, imageQuality?: number ): Promise { return await z.function() .args( stringSchema, numberSchema.optional() ) .returns(z.promise(z.void())) .implement(this.internal_compressAndSaveAs.bind(this)) (filePath, imageQuality); } //#endregion //#region page /** * Gets information of all pages in the PdfDocument */ public async getPagesInfo(): Promise { return this.internal_getPagesInfo() } /** * Gets the number of pages in the PdfDocument. */ public async getPageCount(): Promise { return this.internal_getPageCount() } /** * Set the page orientation. * @param pageRotation see {@link PageRotation} * @param options including {@link PdfPageSelection} */ public async setRotation( pageRotation: PageRotation, options?: { /** * @default "all" */ pdfPageSelection?: PdfPageSelection | undefined; } | undefined ) { return z.function() .args( pageRotationSchema, z.object({pdfPageSelection: pdfPageSelectionSchema.optional()}).optional() ) .returns(z.promise(z.void())) .implement(this.internal_setRotation.bind(this)) (pageRotation, options); } /** * Resize a page to the specified dimensions * @param newSize {@link PdfPaperSize} * @param options including {@link PdfPageSelection} */ public async resize( newSize: PdfPaperSize, options?: { /** * @default "all" */ pdfPageSelection?: PdfPageSelection | undefined; } | undefined ): Promise { return z.function() .args( pdfPaperSizeSchema, z.object({pdfPageSelection: pdfPageSelectionSchema.optional()}).optional() ) .returns(z.promise(z.void())) .implement(this.internal_resize.bind(this)) (newSize, options); } /** * Adds another PDF to the beginning of the current PdfDocument * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument PdfDocument to prepend */ public async prependAnotherPdf( fromPdfDocument: PdfDocument ): Promise { return z.function() .args(pdfDocumentSchema) .returns(z.promise(z.void())) .implement(this.internal_prependAnotherPdf.bind(this)) (fromPdfDocument); } /** * Appends another PDF to the end of the current * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument PdfDocument to Append */ public async appendAnotherPdf(fromPdfDocument: PdfDocument): Promise { return z.function() .args(pdfDocumentSchema) .returns(z.promise(z.void())) .implement(this.internal_appendAnotherPdf.bind(this)) (fromPdfDocument); } /** * Inserts another PDF into the current PdfDocument, starting at a given Page Index. * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument Another PdfDocument * @param insertAtPageIndex Index at which to insert the new content. Note: Page 1 has index 0... */ public async insertPagesFromAnotherPdf( fromPdfDocument: PdfDocument, insertAtPageIndex: number ): Promise { return z.function() .args(pdfDocumentSchema, numberSchema.describe("insertAtPageIndex: number")) .returns(z.promise(z.void())) .implement(this.internal_insertPagesFromAnotherPdf.bind(this)) (fromPdfDocument, insertAtPageIndex); } /** * Removes a range of pages from the PDF * @param pages pages to remove */ public async removePage(pages: PdfPageSelection): Promise { return z.function() .args(pdfPageSelectionSchema) .returns(z.promise(z.void())) .implement(this.internal_removePage.bind(this)) (pages); } /** * Creates a new PDF by copying a range of pages from this {@link PdfDocument}. * @param pages pages to copy (default "all") */ public async duplicate( pages: PdfPageSelection = "all" ): Promise { return z.function() .args(pdfPageSelectionSchema) .returns(z.promise(pdfDocumentSchema)) .implement(this.internal_duplicate.bind(this)) (pages); } //#endregion //#region image /** * Finds all embedded Images from within a specified pages in the PDF and returns them as Buffer * @param options including {@link PdfPageSelection} */ public async extractRawImages(options?: { /** * @default "all" */ fromPages?: PdfPageSelection; } | undefined): Promise { return z.function() .args( z.object({fromPages: pdfPageSelectionSchema.optional()}).optional() ) .returns(z.promise(bufferArraySchema)) .implement(this.internal_extractRawImages.bind(this)) (options); } /** * Renders the PDF and exports image Files in convenient formats. 1 image file is created for each * page. * * @param options including {@link PdfPageSelection} {@link ImageType} * * @return array of images as Buffer[] */ public async rasterizeToImageBuffers(options?: { /** * @default "all" */ fromPages?: PdfPageSelection | undefined; /** * @default {@link ImageType.PNG} */ imageType?: ImageType | undefined; } | undefined): Promise { return z.function() .args( z.object({ fromPages: pdfPageSelectionSchema.optional(), imageType: imageTypeSchema.optional() }).optional() ) .returns(z.promise(bufferArraySchema)) .implement(this.internal_rasterizeToImageBuffers.bind(this)) (options); } /** * Renders the PDF and exports image Files in convenient formats. 1 image file is created for each * page. Running number will append output file path. * * @param filePath output file path. * @param options including {@link PdfPageSelection} {@link ImageType} * * @return array of images file name as string[] */ public async rasterizeToImageFiles( filePath: string, options?: { /** * @default "all" */ fromPages?: PdfPageSelection | undefined; /** * @default {@link ImageType.PNG} */ type?: ImageType | undefined; } | undefined ): Promise { return z.function() .args( filePathSchema, z.object({ fromPages: pdfPageSelectionSchema.optional(), type: imageTypeSchema.optional() }).optional() ) .returns(z.promise(stringArraySchema)) .implement(this.internal_rasterizeToImageFiles.bind(this)) (filePath, options); } //#endregion //#region text /** * Replace the specified old text with new text on a given page * @param oldText Old text to remove * @param newText New text to add * @param onPages Page index to search for old text to replace (default "all") */ public async replaceText( oldText: string, newText: string, onPages?: PdfPageSelection | undefined ): Promise { return z.function() .args( z.string({description: "oldText: string"}), z.string({description: "newText: string"}), pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_replaceText.bind(this)) (oldText, newText, onPages); } public async extractText( onPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(pdfPageSelectionSchema.optional()) .returns(z.promise(z.string())) .implement(this.internal_extractText.bind(this)) (onPages); } //#endregion //#region pdfA /** * Convert the current document into the specified PDF-A standard format * @param pdfaVersion The PDF/A version to convert to (default: PdfA3b) * @param customICC (Optional) Custom color profile file path */ public async convertToPdfA(pdfaVersion: PdfAVersions = PdfAVersions.PdfA3b, customICC?: string | undefined): Promise { return z.function() .args( z.nativeEnum(PdfAVersions, {description: "pdfaVersion: PdfAVersions"}), z.string({description: "customICC: string"}).optional() ) .returns(z.promise(z.void())) .implement(this.internal_convertToPdfA.bind(this)) (pdfaVersion, customICC); } // TODO: Re-enable once IronPdfEngine handler for Pdfium_ConvertToPdfUAForScreenReader // is fixed to call HtmlHelper.HtmlStructTreeDOM() and ConvertToPdfUAForScreenReader(). // Currently the engine handler ignores the HTML and falls back to basic ConvertToPdfUA, // producing a flat tag tree instead of proper semantic structure. // See: IronPdfServiceHandler.cs:97-108 // // public static async fromHtmlAsPdfUA( // html: string, // naturalLanguages: NaturalLanguages = NaturalLanguages.English, // options?: { // renderOptions?: ChromePdfRenderOptions | undefined; // } | undefined // ): Promise { // const pdf = await PdfDocument.fromHtml(html, options); // await toPdfUAForScreenReader(await pdf.internal_getId(), html, naturalLanguages); // return pdf; // } /** * Convert the current document into the specified PDF/UA standard format */ public async convertToPdfUA(naturalLanguages: NaturalLanguages, pdfUaVersion: PdfUAVersions = PdfUAVersions.PdfUA1): Promise { return this.internal_convertToPdfUA(naturalLanguages, pdfUaVersion) } //#endregion //#region metadata /** * Gets a Map of metadata properties */ public async getMetadata(): Promise> { return this.internal_getMetadata() } /** * Add or Update a single metadata property * @param key * @param value */ public async addOrUpdateMetadata( key: string, value: string ): Promise { return z.function() .args(z.string({description: "key: string"}), z.string({description: "value: string"})) .returns(z.promise(z.void())) .implement(this.internal_addOrUpdateMetadata.bind(this)) (key, value); } /** * Remove a single metadata property * @param key */ public async removeMetadata(key: string): Promise { return z.function() .args(z.string({description: "key: string"})) .returns(z.promise(z.void())) .implement(this.internal_removeMetadata.bind(this)) (key); } /** * Sets a whole metadata properties Map (override all the metadata property) * @param newMetadataDictionary new metadata properties Map */ public async overrideMetadata( newMetadataDictionary: Map ): Promise { return z.function() .args(mapStringSchema) .returns(z.promise(z.void())) .implement(this.internal_overrideMetadata.bind(this)) (newMetadataDictionary); } //#endregion //#region signing /** * Sign PDF with digital signature certificate. * Note that the PDF will not be fully signed until Saved * using {@link saveAs} or {@link saveAsBuffer} * * Multiple certificates may be used. * @param signature see {@link DigitalSignature} */ public async signDigitalSignature(signature: DigitalSignature) { return z.function() .args(digitalSignatureSchema) .returns(z.promise(z.void())) .implement(this.internal_signDigitalSignature.bind(this)) (signature); } /** * Check if PdfDocument was signed or not */ public async isSigned(): Promise { return this.internal_isSigned() } /** * Count the number signature that signed to this PdfDocument */ public async signatureCount(): Promise { return this.internal_signatureCount() } /** * Get all verified digital signatures from this PdfDocument. * Returns details including signature name, signer contact, reason, location, date, and validity. * @returns A Promise resolving to an array of {@link VerifiedSignature} objects. */ public async getVerifiedSignatures(): Promise { return this.internal_getVerifiedSignatures() } //#endregion //#region header/footer (affix) /** * Apply page header on top of an existing Pdf. * @param header {@link TextAffix} * @param toPages {@link PdfPageSelection} */ public async addTextHeader( header: TextAffix, toPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(textAffixSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addTextHeader.bind(this)) (header, toPages); } /** * Apply page footer on top of an existing Pdf. * @param footer {@link TextAffix} * @param toPages {@link PdfPageSelection} */ public async addTextFooter( footer: TextAffix, toPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(textAffixSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addTextFooter.bind(this)) (footer, toPages); } /** * Apply HTML header on top of an existing Pdf. * @param header {@link HtmlAffix} * @param toPages {@link PdfPageSelection} */ public async addHtmlHeader( header: HtmlAffix, toPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(htmlAffixSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addHtmlHeader.bind(this)) (header, toPages); } /** * Apply HTML footer on top of an existing Pdf. * @param footer {@link HtmlAffix} * @param toPages {@link PdfPageSelection} */ public async addHtmlFooter( footer: HtmlAffix, toPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(htmlAffixSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addHtmlFooter.bind(this)) (footer, toPages); } //#endregion //#region stamp /** * Edits the PDF by applying the HTML's rendered to only selected page(s). * @param htmlStringOrHtmlFilePath * @param options including {@link HtmlStampOptions} {@link PdfPageSelection} */ public async stampHtml( htmlStringOrHtmlFilePath: HtmlFilePath | HtmlString, options?: { htmlStampOptions?: HtmlStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { return z.function() .args(z.union([htmlFilePathSchema, htmlStringSchema]), z.object({ htmlStampOptions: htmlStampOptionsSchema.optional(), toPages: pdfPageSelectionSchema.optional() }).optional()) .returns(z.promise(z.void())) .implement(this.internal_stampHtml.bind(this)) (htmlStringOrHtmlFilePath, options); } /** * Edits the PDF by applying the image to only selected page(s). * @param image image file path or image buffer * @param options including {@link ImageStampOptions} {@link PdfPageSelection} */ public async stampImage( image: ImageFilePath | ImageBuffer, options?: { imageStampOptions?: ImageStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { return z.function() .args(z.union([imageFilePathSchema, imageBufferSchema]), z.object({ imageStampOptions: imageStampOptionsSchema.optional(), toPages: pdfPageSelectionSchema.optional() }).optional()) .returns(z.promise(z.void())) .implement(this.internal_stampImage.bind(this)) (image, options); } /** * Edits the PDF by applying the text to only selected page(s). * @param text text to stamp * @param options including {@link TextStampOptions} {@link PdfPageSelection} */ public async stampText( text: string, options?: { textStampOptions?: TextStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { return z.function() .args(stringSchema, z.object({ textStampOptions: textStampOptionsSchema.optional(), toPages: pdfPageSelectionSchema.optional() }).optional()) .returns(z.promise(z.void())) .implement(this.internal_stampText.bind(this)) (text, options); } /** * Edits the PDF by applying the barcode to only selected page(s). * @param barcodeValue barcode * @param options including {@link BarcodeType} {@link BarcodeStampOptions} {@link PdfPageSelection} */ public async stampBarcode( barcodeValue: string, options?: { barcodeEncoding: BarcodeType; barcodeStampOptions?: BarcodeStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { return z.function() .args(stringSchema, z.object({ barcodeEncoding: barcodeTypeSchema, barcodeStampOptions: barcodeStampOptionsSchema.optional(), toPages: pdfPageSelectionSchema.optional() }).optional()) .returns(z.promise(z.void())) .implement(this.internal_stampBarcode.bind(this)) (barcodeValue, options); } //#endregion //#region background/foreground /** * Adds a background to each page of this PDF. The background is copied from a first page in the * backgroundPdf document. * * @param fromPdf background PDF document * @param sourcePageIndex Index (zero-based page number) of the page to copy from the Background/Foreground PDF. Default is 0. * @param applyToPages PageSelection to which the background/foreground will be added. Default is "all" */ public async addBackgroundFromAnotherPdf( fromPdf: PdfDocument, sourcePageIndex = 0, applyToPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(pdfDocumentSchema, numberSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addBackgroundFromAnotherPdf.bind(this)) (fromPdf, sourcePageIndex, applyToPages); } /** * Adds a foreground to each page of this PDF. The background is copied from a first page in the * backgroundPdf document. * * @param fromPdf foreground PDF document * @param sourcePageIndex Index (zero-based page number) of the page to copy from the Background/Foreground PDF. Default is 0. * @param applyToPages PageSelection to which the background/foreground will be added. Default is "all" */ public async addForegroundFromAnotherPdf( fromPdf: PdfDocument, sourcePageIndex = 0, applyToPages?: PdfPageSelection | undefined ): Promise { return z.function() .args(pdfDocumentSchema, numberSchema, pdfPageSelectionSchema.optional()) .returns(z.promise(z.void())) .implement(this.internal_addForegroundFromAnotherPdf.bind(this)) (fromPdf, sourcePageIndex, applyToPages); } //#endregion //#region security /** * Removes all user and owner password security for a PDF document. Also disables content * encryption. * If content is encrypted at 128 bit, copy and paste of content, annotations and form editing may be disabled. */ public async removePasswordsAndEncryption(): Promise { return this.internal_removePasswordsAndEncryption() } /** * Sets the user password and enables 128Bit encryption of PDF content. * A user password is a password that each user must enter to open or print the PDF document. */ public async setUserPassword(userPassword: string): Promise { return z.function() .args(z.string({description: "userPassword: string"})) .returns(z.promise(z.void())) .implement(this.internal_setUserPassword.bind(this)) (userPassword); } /** * Sets the owner password and enables 128Bit encryption of PDF content. An owner password is one used to * enable and disable all other security settings. OwnerPassword must be set to a non-empty string * value for {@link PdfPermission.AllowAccessibilityExtractContent} , {@link PdfPermission.AllowAnnotations} , * {@link PdfPermission.AllowFillForms}, {@link PdfPermission.AllowPrint}, {@link PdfPermission.AllowModify} to be * restricted. */ public async setOwnerPassword(ownerPassword: string): Promise { return z.function() .args(z.string({description: "ownerPassword: string"})) .returns(z.promise(z.void())) .implement(this.internal_setOwnerPassword.bind(this)) (ownerPassword); } /** * Sets the permissions of this PdfDocument * @param permissions see {@link PdfPermission} */ public async setPermission(permissions: PdfPermission): Promise { return z.function() .args(pdfPermissionSchema) .returns(z.promise(z.void())) .implement(this.internal_setPermission.bind(this)) (permissions); } /** * Gets the current permissions of this PdfDocument * @return {@link PdfPermission} */ public async getPermission(): Promise { return this.internal_getPermission() } /** * Makes this PDF document read only such that: Content is encrypted at 128 bit. Copy and paste of * content is disallowed. Annotations and form editing are disabled. * @param ownerPassword The owner password for the PDF. A string for owner password is required to enable PDF encryption and * all document security options. */ public async makePdfDocumentReadOnly(ownerPassword: string): Promise { return z.function() .args(z.string({description: "ownerPassword: string"})) .returns(z.promise(z.void())) .implement(this.internal_makePdfDocumentReadOnly.bind(this)) (ownerPassword); } //#endregion //#region close /** * Dispose this PdfDocument object (clean up the resource) * This is necessary to free the memory used by PdfDocument. See {@link cleanUp} * Once this method was called this PdfDocument object no longer usable. */ public async close() { return this.internal_close() } //#endregion //#region ALL_INTERNAL_STUFF /** * Internal PDF document ID * @private */ private pdfDocumentId?: string | undefined; /** * @private */ private readonly promiseDocumentId?: Promise | undefined; /** * @private */ private pdfPassword?: PdfPassword | undefined; /** * Create a PdfDocument object from a {@link PdfInput} * For more specific way to create/open PdfDocument see {@link fromUrl} {@link fromZip} {@link fromHtml} {@link fromImage} {@link open} * * @param pdfInput see {@link PdfInput} (required) (pdfInput is {@link PdfFilePath} or {@link Buffer}) * @param password a password to open the PDF required if PDF file was private. * @param trackChanges Optionally track changes to the document (for use with incremental saves) */ constructor(pdfInput?: PdfInput | undefined, password?: PdfPassword | undefined, trackChanges?: ChangeTrackingModes | undefined) { if (pdfInput) { this.pdfDocumentId = undefined; const input = separatePdfInput(pdfInput); switch (input.type) { case "htmlFile": this.promiseDocumentId = renderHtmlFileToPdf(input.htmlFile); break; case "htmlString": this.promiseDocumentId = renderHtmlToPdf(input.htmlString); break; case "zipFile": this.promiseDocumentId = renderHtmlZipToPdf(input.zipFile); break; case "buffer": this.promiseDocumentId = openPdfFileBuffer( input.buffer, {userPassword: password?.userPassword, ownerPassword: password?.ownerPassword, trackChanges: trackChanges} ); break; case "pdfFile": this.pdfPassword = password; this.promiseDocumentId = openPdfFileBuffer( fs.readFileSync(input.pdfFile), {userPassword: password?.userPassword, ownerPassword: password?.ownerPassword, trackChanges: trackChanges} ); break; case "url": this.promiseDocumentId = renderUrlToPdf(input.url); break; case "pdfDocument": this.pdfDocumentId = input.pdfDocument.pdfDocumentId; this.promiseDocumentId = input.pdfDocument.promiseDocumentId; break; } if (this.pdfDocumentId) { Access.usedDocumentIds.add(this.pdfDocumentId); } this.promiseDocumentId?.then((id) => Access.usedDocumentIds.add(id) ); } } /** * Dispose this PdfDocument object (clean up the resource) * This is necessary to free the memory used by PdfDocument. See {@link cleanUp} * Once this method was called this PdfDocument object no longer usable. */ private async internal_close() { await disposePdf(await this.internal_getId()); } /** * @private */ private async internal_getId(): Promise { if (this.pdfDocumentId) { return Promise.resolve(this.pdfDocumentId) ; } else if (this.promiseDocumentId) { this.pdfDocumentId = await this.promiseDocumentId; return Promise.resolve(this.pdfDocumentId); } else { throw new Error("Cannot Get PdfDocumentId"); } } //#region io /** * Open or Create a PdfDocument from a {@link PdfInput} * @param pdfInput {@link PdfInput} * @param options including {@link PdfPassword} {@link ChromePdfRenderOptions} {@link HttpLoginCredentials} mainHtmlFile */ private static async internal_open( pdfInput: PdfInput, options?: { /** * required for open a private PDF file * @default undefined */ password?: PdfPassword | undefined; /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; /** * Apply httpLoginCredentials if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ httpLoginCredentials?: HttpLoginCredentials | undefined; /** * Apply mainHtmlFile if PdfInput is {@link ZipFilePath} * @default index.html */ mainHtmlFile?: string | undefined; /** * Optionally track changes to the document (for use with incremental saves) * @default {@link ChangeTrackingModes.AutoChangeTracking} */ trackChanges?: ChangeTrackingModes | undefined; // /** // * Apply baseUrl if // * The HTML base URL for which references to external CSS, Javascript and Image files will be relative. // * @default undefined // */ // baseUrl ?: string | undefined; //not supported } | undefined ): Promise { if (pdfInput) { const input = separatePdfInput(pdfInput); switch (input.type) { case "htmlFile": const newHtmlFilePdf = new PdfDocument(); newHtmlFilePdf.pdfDocumentId = await renderHtmlFileToPdf( input.htmlFile, options?.renderOptions ); return newHtmlFilePdf; case "htmlString": const newHtmlStringPdf = new PdfDocument(); newHtmlStringPdf.pdfDocumentId = await renderHtmlToPdf( input.htmlString, options?.renderOptions ); return newHtmlStringPdf; case "zipFile": const newZipFilePdf = new PdfDocument(); newZipFilePdf.pdfDocumentId = await renderHtmlZipToPdf( input.zipFile, options?.mainHtmlFile, options?.renderOptions ); return newZipFilePdf; case "buffer": const newBufferPdf = new PdfDocument( undefined, options?.password, options?.trackChanges ); newBufferPdf.pdfDocumentId = await openPdfFileBuffer( input.buffer,{ userPassword: options?.password?.userPassword, ownerPassword: options?.password?.ownerPassword, trackChanges: options?.trackChanges } ); return newBufferPdf; case "pdfFile": const newPdfFilePdf = new PdfDocument( undefined, options?.password ); newPdfFilePdf.pdfDocumentId = await openPdfFileBuffer( fs.readFileSync(input.pdfFile), { userPassword: options?.password?.userPassword, ownerPassword: options?.password?.ownerPassword, trackChanges: options?.trackChanges } ); return newPdfFilePdf; case "url": const newUrlPdf = new PdfDocument(); newUrlPdf.pdfDocumentId = await renderUrlToPdf(input.url, { renderOptions: options?.renderOptions, httpLoginCredentials: options?.httpLoginCredentials, }); return newUrlPdf; case "pdfDocument": return Promise.resolve(input.pdfDocument); } } throw new Error(`cannot create PdfDocument object from ${pdfInput}`); } /** * Open a PdfDocument from .pdf file * @param pdfFilePath A path to .pdf file * @param Optionally track changes to the document (for use with incremental saves) */ private static async internal_fromFile( pdfFilePath: string, trackChanges?: ChangeTrackingModes | undefined ): Promise { return this.internal_open(pdfFilePath, {trackChanges: trackChanges}); } /** * Create a PdfDocument from an Url * @param url A website Url * @param options including {@link ChromePdfRenderOptions} */ private static async internal_fromUrl( url: URL | string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; } | undefined ): Promise { return this.internal_open(url, options); } /** * Creates a PDF file from a local Zip file, and returns it as a {@link PdfDocument}. * IronPDF is a W3C standards compliant HTML rendering based on Google's Chromium browser. * If your output PDF does not look as expected: * * - Validate your HTML file using https://validator.w3.org/ & CSS https://jigsaw.w3.org/css-validator/ * * - To debug HTML, view the file in Chrome web browser's print preview which will work almost exactly as IronPDF. * * - Read our detailed documentation on pixel perfect HTML to PDF: https://ironpdf.com/tutorials/pixel-perfect-html-to-pdf/ * * @param zipFilePath Path to a Zip to be rendered as a PDF. * @param options including {@link ChromePdfRenderOptions} and `mainHtmlFile` a main .html file default: `index.html` */ private static async internal_fromZip( zipFilePath: string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; /** * a main .html file default: `index.html` */ mainHtmlFile?: string | undefined; } | undefined ): Promise { return this.internal_open(zipFilePath, options); } /** * Creates a PDF file from a Html string, and returns it as an {@link PdfDocument} object which can be edited and saved to disk or served on a website. * @param htmlStringOrHtmlFilePath The Html to be rendered as a PDF. * @param options including {@link ChromePdfRenderOptions} */ private static async internal_fromHtml( htmlStringOrHtmlFilePath: string, options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ renderOptions?: ChromePdfRenderOptions | undefined; } | undefined ): Promise { return this.internal_open(htmlStringOrHtmlFilePath, options); } /** * Converts multiple image files to a PDF document. Each image creates 1 page which matches the image * dimensions. The default PaperSize is A4. You can set it via ImageToPdfConverter.PaperSize. * Note: Imaging.ImageBehavior.CropPage will set PaperSize equal to ImageSize. * @param images The image file path name(s) or {@link ImageBuffer} object(s) * @param options including {@link ImageToPdfOptions} */ private static async internal_fromImage( images: ImageFilePath | ImageFilePath[] | ImageBuffer | ImageBuffer[], options?: { /** * Apply renderOptions if PdfInput is a {@link HtmlString} or {@link HtmlFilePath} or {@link ZipFilePath} or {@link Url}} * @default undefined */ imageToPdfOptions?: ImageToPdfOptions | undefined; } | undefined ): Promise { let temp: Promise; if (Array.isArray(images)) { // const imageArray = images as Array; if(images[0]){ const t = separateImageBufferOrImagePathInput(images[0]); switch (t.type) { case "imageBuffer": temp = renderImagesBufferToPdf( images as Buffer[], options?.imageToPdfOptions ); break; case "imageFilePath": temp = renderImagesFilesToPdf( images as string[], options?.imageToPdfOptions ); break; } }else{ throw new Error("imageToPdf input Array is Empty"); } } else { const image = separateImageBufferOrImagePathInput(images); switch (image.type) { case "imageBuffer": temp = renderImagesBufferToPdf( [image.imageBuffer], options?.imageToPdfOptions ); break; case "imageFilePath": temp = renderImagesFilesToPdf( [image.imageFilePath], options?.imageToPdfOptions ); break; } } if (!temp) { throw new Error(`cannot read image: ${images}`); } const newUrlPdf = new PdfDocument(); newUrlPdf.pdfDocumentId = await temp; return newUrlPdf; } /** * Static method that joins (concatenates) multiple PDF documents together into one compiled PDF document. * If the PDF contains form fields the form field in the resulting PDF's name will be appended with '_{index}' e.g. 'Name' will be 'Name_0' * @param pdfs array of PDF */ private static async internal_mergePdf(pdfs: PdfInput[]): Promise { const ids = await Promise.all( pdfs.map(async (x) => (await PdfDocument.open(x)).internal_getId()) ); const newDocId = mergePdfs(ids); const newUrlPdf = new PdfDocument(); newUrlPdf.pdfDocumentId = await newDocId; return newUrlPdf; } /** * Saves the PdfDocument to a file. * @param filePath Target file path * @param saveOptions see {@link SaveOptions} */ private async internal_saveAs(filePath: string, saveOptions?: SaveOptions | undefined): Promise { return this.internal_saveAsBuffer(saveOptions).then((pdfFileBuffer) => { fs.writeFile(filePath, pdfFileBuffer, "binary", (err) => { if (err) throw err; }); }); } /** * Saves the PdfDocument to a binary (Buffer) * @param saveOptions see {@link SaveOptions} */ private async internal_saveAsBuffer(saveOptions?: SaveOptions | undefined): Promise { return getBinaryData(await this.internal_getId(), saveOptions); } //#endregion //#region compress /** * Compress existing PDF images using JPG encoding and the specified settings * @param imageQuality Quality (1 - 100) to use during compression * @param scaleToVisibleSize Scale down the image resolution according to its visible size in the PDF document */ private async internal_compressSize( imageQuality: number, scaleToVisibleSize = false ): Promise { if (imageQuality < 1 || imageQuality > 100) throw new Error( `Invalid quality specifier (${imageQuality}) when compressing images. Quality must be between 1 and 100.` ); return await compressImage( await this.internal_getId(), imageQuality, scaleToVisibleSize ); } /** * Remove document struct tree information which describes the logical layout of the document. * Removing the "structure tree" can significantly reduce the disk space used by the document. * Removing the "structure tree" of a complicated document can negatively impact text selection. */ private async internal_compressStructTree(): Promise { return await compressStructTree(await this.internal_getId()); } /** * Compress the PDF and return the result as a Buffer (byte array). * Uses QPdf compression which can significantly reduce file size. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. */ private async internal_compressPdfToBytes( imageQuality?: number ): Promise { if (imageQuality !== undefined && (imageQuality < 1 || imageQuality > 100)) throw new Error( `Invalid quality specifier (${imageQuality}) when compressing PDF. Quality must be between 1 and 100.` ); return await compressInMemory( await this.internal_getId(), imageQuality ); } /** * Compress the PDF and return the result as a Readable stream. * Uses QPdf compression which can significantly reduce file size. * Useful for piping directly to file streams or HTTP responses without buffering the entire PDF in memory. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. */ private async internal_compressPdfToStream( imageQuality?: number ): Promise { if (imageQuality !== undefined && (imageQuality < 1 || imageQuality > 100)) throw new Error( `Invalid quality specifier (${imageQuality}) when compressing PDF. Quality must be between 1 and 100.` ); return await compressInMemoryStream( await this.internal_getId(), imageQuality ); } /** * Compress the PDF and save the result directly to a file. * Uses QPdf compression which can significantly reduce file size. * @param filePath The output file path to save the compressed PDF. * @param imageQuality Optional JPEG quality (1-100) for image compression. If omitted, default compression is applied. */ private async internal_compressAndSaveAs( filePath: string, imageQuality?: number ): Promise { if (imageQuality !== undefined && (imageQuality < 1 || imageQuality > 100)) throw new Error( `Invalid quality specifier (${imageQuality}) when compressing PDF. Quality must be between 1 and 100.` ); return await compressAndSaveAs( await this.internal_getId(), filePath, imageQuality ); } //#endregion //#region page /** * Gets information of all pages in the PdfDocument */ private async internal_getPagesInfo(): Promise { return await getPageInfo(await this.internal_getId()); } /** * Gets the number of pages in the PdfDocument. */ private async internal_getPageCount(): Promise { return (await this.internal_getPagesInfo()).length; } /** * Set the page orientation. * @param pageRotation see {@link PageRotation} * @param options including {@link PdfPageSelection} */ private async internal_setRotation( pageRotation: PageRotation, options?: { /** * @default "all" */ pdfPageSelection?: PdfPageSelection | undefined; } | undefined ) { return await setPageRotation(await this.internal_getId(), pageRotation, options); } /** * Resize a page to the specified dimensions * @param newSize {@link PdfPaperSize} * @param options including {@link PdfPageSelection} */ private async internal_resize( newSize: PdfPaperSize, options?: { /** * @default "all" */ pdfPageSelection?: PdfPageSelection | undefined; } | undefined ): Promise { return await resizePage(await this.internal_getId(), newSize, options); } /** * Adds another PDF to the beginning of the current PdfDocument * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument PdfDocument to prepend */ private async internal_prependAnotherPdf( fromPdfDocument: PdfDocument ): Promise { await this.internal_insertPagesFromAnotherPdf(fromPdfDocument, 0); } /** * Appends another PDF to the end of the current * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument PdfDocument to Append */ private async internal_appendAnotherPdf(fromPdfDocument: PdfDocument): Promise { await this.internal_insertPagesFromAnotherPdf( fromPdfDocument, (await this.internal_getPageCount()) ); } /** * Inserts another PDF into the current PdfDocument, starting at a given Page Index. * If AnotherPdfFile contains form fields, those fields will be appended with '_' in the resulting PDF. e.g. 'Name' will be 'Name_' * @param fromPdfDocument Another PdfDocument * @param insertAtPageIndex Index at which to insert the new content. Note: Page 1 has index 0... */ private async internal_insertPagesFromAnotherPdf( fromPdfDocument: PdfDocument, insertAtPageIndex: number ): Promise { await insertPdf( await this.internal_getId(), await fromPdfDocument.internal_getId(), insertAtPageIndex ); } /** * Removes a range of pages from the PDF * @param pages pages to remove */ private async internal_removePage(pages: PdfPageSelection): Promise { await removePage(await this.internal_getId(), {PdfPageSelection: pages}); } /** * Creates a new PDF by copying a range of pages from this {@link PdfDocument}. * @param pages pages to copy (default "all") */ private async internal_duplicate( pages: PdfPageSelection = "all" ): Promise { const newPdf = new PdfDocument(); newPdf.pdfDocumentId = await duplicate(await this.internal_getId(), { PdfPageSelection: pages, }); return newPdf; } //#endregion //#region image /** * Finds all embedded Images from within a specified pages in the PDF and returns them as Buffer * @param options including {@link PdfPageSelection} */ private async internal_extractRawImages(options?: { /** * @default "all" */ fromPages?: PdfPageSelection | undefined; } | undefined): Promise { return extractRawImages( await this.internal_getId(), options?.fromPages ?? "all" ); } /** * Renders the PDF and exports image Files in convenient formats. 1 image file is created for each * page. * * @param options including {@link PdfPageSelection} {@link ImageType} * * @return array of images as Buffer[] */ private async internal_rasterizeToImageBuffers(options?: { /** * @default "all" */ fromPages?: PdfPageSelection | undefined; /** * @default {@link ImageType.PNG} */ imageType?: ImageType | undefined; }): Promise { const images = await rasterizeToImageBuffers( await this.internal_getId(), options?.fromPages ?? "all" ); const jimpImageType: "image/bmp" | "image/png" | "image/jpeg" = (() => { switch (options?.imageType) { case ImageType.BMP: return Jimp.MIME_BMP; case ImageType.PNG: return Jimp.MIME_PNG; case ImageType.JPG: return Jimp.MIME_JPEG; default: return Jimp.MIME_PNG; } })(); return Promise.all( images.map(async (imageBuffer) => { //convert output type const jimp = await Jimp.read(imageBuffer); return await jimp.getBufferAsync(jimpImageType); }) ); } /** * Renders the PDF and exports image Files in convenient formats. 1 image file is created for each * page. Running number will append output file path. * * @param filePath output file path. * @param options including {@link PdfPageSelection} {@link ImageType} * * @return array of images file name as string[] */ private async internal_rasterizeToImageFiles( filePath: string, options?: { /** * @default "all" */ fromPages?: PdfPageSelection | undefined; /** * @default {@link ImageType.PNG} */ type?: ImageType | undefined; } | undefined ): Promise { const images = await rasterizeToImageBuffers( await this.internal_getId(), options?.fromPages ?? "all" ); const promises = images.map(async (imageBuffer, index) => { const outputFileName = getFileName(filePath,index.toString(),getImageExtType(options?.type),"image"); await Jimp.read(imageBuffer).then((value) => { return value.write(outputFileName); }); return outputFileName; }); return await Promise.all(promises); } //#endregion //#region text /** * Replace the specified old text with new text on a given page * @param oldText Old text to remove * @param newText New text to add * @param onPages Page index to search for old text to replace (default "all") */ private async internal_replaceText( oldText: string, newText: string, onPages?: PdfPageSelection | undefined ): Promise { return replaceText(await this.internal_getId(), oldText, newText, onPages); } private async internal_extractText( onPages?: PdfPageSelection | undefined ): Promise { return extractAllText(await this.internal_getId(), onPages); } //#endregion //#region pdfA /** * Convert the current document into the specified PDF-A standard format * @param pdfaVersion The PDF/A version to convert to * @param customICC (Optional) Custom color profile file path */ private async internal_convertToPdfA(pdfaVersion: PdfAVersions, customICC?: string | undefined): Promise { return await toPdfA(await this.internal_getId(), pdfaVersion, customICC); } /** * Convert the current document into the specified PDF/UA standard format */ private async internal_convertToPdfUA(naturalLanguages: NaturalLanguages, pdfUaVersion: PdfUAVersions = PdfUAVersions.PdfUA1): Promise { return await toPdfUA(await this.internal_getId(), naturalLanguages, pdfUaVersion); } //#endregion //#region metadata /** * Gets a Map of metadata properties */ private async internal_getMetadata(): Promise> { return getMetadataDict(await this.internal_getId()); } /** * Add or Update a single metadata property * @param key * @param value */ private async internal_addOrUpdateMetadata( key: string, value: string ): Promise { return setMetadata(await this.internal_getId(), key, value); } /** * Remove a single metadata property * @param key */ private async internal_removeMetadata(key: string): Promise { return removeMetadata(await this.internal_getId(), key); } /** * Sets a whole metadata properties Map (override all the metadata property) * @param newMetadataDictionary new metadata properties Map */ private async internal_overrideMetadata( newMetadataDictionary: Map ): Promise { return setMetadataDict(await this.internal_getId(), newMetadataDictionary); } //#endregion //#region signing /** * Sign PDF with digital signature certificate. * Note that the PDF will not be fully signed until Saved * using {@link saveAs} or {@link saveAsBuffer} * * Multiple certificates may be used. * @param signature see {@link DigitalSignature} */ private async internal_signDigitalSignature(signature: DigitalSignature) { return await signPdf(await this.internal_getId(), signature); } /** * Check if PdfDocument was signed or not */ private async internal_isSigned(): Promise { const signatureCount = await getSignatureCount(await this.internal_getId()); return signatureCount > 0; } /** * Count the number signature that signed to this PdfDocument */ private async internal_signatureCount(): Promise { return await getSignatureCount(await this.internal_getId()); } /** * Get all verified digital signatures from this PdfDocument. */ private async internal_getVerifiedSignatures(): Promise { return await getVerifiedSignatures(await this.internal_getId()); } //#endregion //#region header/footer (affix) /** * Apply page header on top of an existing Pdf. * @param header {@link TextAffix} * @param toPages {@link PdfPageSelection} */ private async internal_addTextHeader( header: TextAffix, toPages?: PdfPageSelection | undefined ): Promise { await addTextAffix(await this.internal_getId(), toPages, header, true); } /** * Apply page footer on top of an existing Pdf. * @param footer {@link TextAffix} * @param toPages {@link PdfPageSelection} */ private async internal_addTextFooter( footer: TextAffix, toPages?: PdfPageSelection | undefined ): Promise { await addTextAffix(await this.internal_getId(), toPages, footer, false); } /** * Apply HTML header on top of an existing Pdf. * @param header {@link HtmlAffix} * @param toPages {@link PdfPageSelection} */ private async internal_addHtmlHeader( header: HtmlAffix, toPages?: PdfPageSelection | undefined ): Promise { await addHtmlAffix(await this.internal_getId(), toPages, header, true); } /** * Apply HTML footer on top of an existing Pdf. * @param footer {@link HtmlAffix} * @param toPages {@link PdfPageSelection} */ private async internal_addHtmlFooter( footer: HtmlAffix, toPages?: PdfPageSelection | undefined ): Promise { await addHtmlAffix(await this.internal_getId(), toPages, footer, false); } //#endregion //#region stamp /** * Edits the PDF by applying the HTML's rendered to only selected page(s). * @param htmlStringOrHtmlFilePath * @param options including {@link HtmlStampOptions} {@link PdfPageSelection} */ private async internal_stampHtml( htmlStringOrHtmlFilePath: HtmlFilePath | HtmlString, options?: { htmlStampOptions?: HtmlStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { const html = htmlStringOrHtmlFilePath.endsWith(".html") || htmlStringOrHtmlFilePath.endsWith(".htm") ? fs.readFileSync(htmlStringOrHtmlFilePath).toString() : htmlStringOrHtmlFilePath; await stampHtml(await this.internal_getId(), html, { password: this.pdfPassword, htmlStampOptions: options?.htmlStampOptions, pageSelection: options?.toPages, }); } /** * Edits the PDF by applying the image to only selected page(s). * @param image image file path or image buffer * @param options including {@link ImageStampOptions} {@link PdfPageSelection} */ private async internal_stampImage( image: ImageFilePath | ImageBuffer, options?: { imageStampOptions?: ImageStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { const imageBuffer = image instanceof Buffer ? image : fs.readFileSync(image); await stampImage(await this.internal_getId(), imageBuffer, { password: this.pdfPassword, imageStampOptions: options?.imageStampOptions, pageSelection: options?.toPages, }); } /** * Edits the PDF by applying the text to only selected page(s). * @param text text to stamp * @param options including {@link TextStampOptions} {@link PdfPageSelection} */ private async internal_stampText( text: string, options?: { textStampOptions?: TextStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { await stampText(await this.internal_getId(), text, { password: this.pdfPassword, textStampOptions: options?.textStampOptions, pageSelection: options?.toPages, }); } /** * Edits the PDF by applying the barcode to only selected page(s). * @param barcodeValue barcode * @param options including {@link BarcodeType} {@link BarcodeStampOptions} {@link PdfPageSelection} */ private async internal_stampBarcode( barcodeValue: string, options?: { barcodeEncoding: BarcodeType; barcodeStampOptions?: BarcodeStampOptions | undefined; toPages?: PdfPageSelection | undefined; } | undefined ) { await stampBarcode( await this.internal_getId(), barcodeValue, { password: this.pdfPassword, barcodeStampOptions: options?.barcodeStampOptions, pageSelection: options?.toPages, } ); } //#endregion //#region background/foreground /** * Adds a background to each page of this PDF. The background is copied from a first page in the * backgroundPdf document. * * @param fromPdf background PDF document * @param sourcePageIndex Index (zero-based page number) of the page to copy from the Background/Foreground PDF. Default is 0. * @param applyToPages PageSelection to which the background/foreground will be added. Default is "all" */ private async internal_addBackgroundFromAnotherPdf( fromPdf: PdfDocument, sourcePageIndex = 0, applyToPages?: PdfPageSelection | undefined ): Promise { return await addBackgroundForeground( await this.internal_getId(), await fromPdf.internal_getId(), sourcePageIndex, true, applyToPages ); } /** * Adds a foreground to each page of this PDF. The background is copied from a first page in the * backgroundPdf document. * * @param fromPdf foreground PDF document * @param sourcePageIndex Index (zero-based page number) of the page to copy from the Background/Foreground PDF. Default is 0. * @param applyToPages PageSelection to which the background/foreground will be added. Default is "all" */ private async internal_addForegroundFromAnotherPdf( fromPdf: PdfDocument, sourcePageIndex = 0, applyToPages?: PdfPageSelection | undefined ): Promise { return await addBackgroundForeground( await this.internal_getId(), await fromPdf.internal_getId(), sourcePageIndex, false, applyToPages ); } //#endregion //#region security /** * Removes all user and owner password security for a PDF document. Also disables content * encryption. * If content is encrypted at 128 bit, copy and paste of content, annotations and form editing may be disabled. */ private async internal_removePasswordsAndEncryption(): Promise { await removePasswordsAndEncryption(await this.internal_getId()); } /** * Sets the user password and enables 128Bit encryption of PDF content. * A user password is a password that each user must enter to open or print the PDF document. */ private async internal_setUserPassword(userPassword: string): Promise { if (!this.pdfPassword) this.pdfPassword = {userPassword: userPassword}; else this.pdfPassword.userPassword = userPassword; this.pdfDocumentId = await setUserPasswords( await this.internal_getId(), userPassword ); } /** * Sets the owner password and enables 128Bit encryption of PDF content. An owner password is one used to * enable and disable all other security settings. OwnerPassword must be set to a non-empty string * value for {@link PdfPermission.AllowAccessibilityExtractContent} , {@link PdfPermission.AllowAnnotations} , * {@link PdfPermission.AllowFillForms}, {@link PdfPermission.AllowPrint}, {@link PdfPermission.AllowModify} to be * restricted. */ private async internal_setOwnerPassword(ownerPassword: string): Promise { if (!this.pdfPassword) this.pdfPassword = {ownerPassword: ownerPassword}; else this.pdfPassword.ownerPassword = ownerPassword; this.pdfDocumentId = await setOwnerPasswords( await this.internal_getId(), ownerPassword ); } /** * Sets the permissions of this PdfDocument * @param permissions see {@link PdfPermission} */ private async internal_setPermission(permissions: PdfPermission): Promise { this.pdfDocumentId = await setSecurity(await this.internal_getId(), permissions); } /** * Gets the current permissions of this PdfDocument * @return {@link PdfPermission} */ private async internal_getPermission(): Promise { return await getPermission(await this.internal_getId()); } /** * Makes this PDF document read only such that: Content is encrypted at 128 bit. Copy and paste of * content is disallowed. Annotations and form editing are disabled. * @param ownerPassword The owner password for the PDF. A string for owner password is required to enable PDF encryption and * all document security options. */ private async internal_makePdfDocumentReadOnly(ownerPassword: string): Promise { await this.internal_setOwnerPassword(ownerPassword); await this.internal_setPermission({ AllowExtractContent: false, AllowAccessibilityExtractContent: false, AllowAnnotations: false, AllowModify: false, AllowAssembleDocument: false, AllowFillForms: false, }); } //#endregion //#endregion }