@ironsoftware/ironpdf
Version:
IronPDF for Node
1,578 lines (1,477 loc) • 64.1 kB
text/typescript
import {Buffer} from "buffer";
import {
BarcodeStampOptions,
BarcodeType, ChangeTrackingModes,
ChromePdfRenderOptions,
DigitalSignature,
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} 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 {compressImage, compressStructTree} from "../internal/grpc_layer/pdfium/compress";
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 {toPdfA, toPdfUA} from "../internal/grpc_layer/pdfium/pdfa";
import {getMetadataDict, removeMetadata, setMetadata, setMetadataDict} from "../internal/grpc_layer/pdfium/metadata";
import {getSignatureCount, 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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
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.
* @param htmlStringOrHtmlFilePath The Html to be rendered as a PDF.
* @param options including {@link ChromePdfRenderOptions}
*/
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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
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<void> {
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<Buffer> {
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
* @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<void> {
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<void> {
return this.internal_compressStructTree()
}
//#endregion
//#region page
/**
* Gets information of all pages in the PdfDocument
*/
public async getPagesInfo(): Promise<PageInfo[]> {
return this.internal_getPagesInfo()
}
/**
* Gets the number of pages in the PdfDocument.
*/
public async getPageCount(): Promise<number> {
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<void> {
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<void> {
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 <see cref="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 Append
*/
public async appendAnotherPdf(fromPdfDocument: PdfDocument): Promise<void> {
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<void> {
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<void> {
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<PdfDocument> {
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<Buffer[]> {
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<Buffer[]> {
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<string[]> {
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<void> {
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<string> {
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 customICC (Optional) Custom color profile file path
*/
public async convertToPdfA(customICC?: string | undefined): Promise<void> {
return z.function()
.args(z.string({description: "customICC: string"}).optional())
.returns(z.promise(z.void()))
.implement(this.internal_convertToPdfA.bind(this))
(customICC);
}
/**
* Convert the current document into the specified PDF/UA standard format
*/
public async convertToPdfUA(naturalLanguages: NaturalLanguages): Promise<void> {
return this.internal_convertToPdfUA(naturalLanguages)
}
//#endregion
//#region metadata
/**
* Gets a Map<string, string> of metadata properties
*/
public async getMetadata(): Promise<Map<string, string>> {
return this.internal_getMetadata()
}
/**
* Add or Update a single metadata property
* @param key
* @param value
*/
public async addOrUpdateMetadata(
key: string,
value: string
): Promise<void> {
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<void> {
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<string, string> (override all the metadata property)
* @param newMetadataDictionary new metadata properties Map<string, string>
*/
public async overrideMetadata(
newMetadataDictionary: Map<string, string>
): Promise<void> {
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<boolean> {
return this.internal_isSigned()
}
/**
* Count the number signature that signed to this PdfDocument
*/
public async signatureCount(): Promise<number> {
return this.internal_signatureCount()
}
//#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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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<void> {
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. <para>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<void> {
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<void> {
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<PdfPermission> {
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<void> {
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<string> | 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":
const htmlString = fs
.readFileSync(input.htmlFile)
.toString();
this.promiseDocumentId = renderHtmlToPdf(htmlString);
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<string> {
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<PdfDocument> {
if (pdfInput) {
const input = separatePdfInput(pdfInput);
switch (input.type) {
case "htmlFile":
const htmlString = fs
.readFileSync(input.htmlFile)
.toString();
const newHtmlFilePdf = new PdfDocument();
newHtmlFilePdf.pdfDocumentId = await renderHtmlToPdf(
htmlString,
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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
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<PdfDocument> {
let temp: Promise<string>;
if (Array.isArray(images)) {
// const imageArray = images as Array<any>;
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<PdfDocument> {
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<void> {
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<Buffer> {
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<void> {
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<void> {
return await compressStructTree(await this.internal_getId());
}
//#endregion
//#region page
/**
* Gets information of all pages in the PdfDocument
*/
private async internal_getPagesInfo(): Promise<PageInfo[]> {
return await getPageInfo(await this.internal_getId());
}
/**
* Gets the number of pages in the PdfDocument.
*/
private async internal_getPageCount(): Promise<number> {
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<void> {
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<void> {
await this.internal_insertPagesFromAnotherPdf(fromPdfDocument, 0);
}
/**
* Appends another PDF to the end of the current <see cref="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 Append
*/
private async internal_appendAnotherPdf(fromPdfDocument: PdfDocument): Promise<void> {
await this.internal_insertPagesFromAnotherPdf(
fromPdfDocument,
(await this.internal_getPageCount()) - 1
);
}
/**
* 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<void> {
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<void> {
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<PdfDocument> {
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 |