diff --git a/Document-Processing-toc.html b/Document-Processing-toc.html index 8cfa27d02a..0b4a7d143c 100644 --- a/Document-Processing-toc.html +++ b/Document-Processing-toc.html @@ -3459,6 +3459,7 @@
  • Shapes
  • Annotations
  • Form Fields
  • +
  • Encryption
  • Digital Signature
  • Bookmarks
  • Hyperlinks
  • diff --git a/Document-Processing/PDF/PDF-Library/javascript/Annotations.md b/Document-Processing/PDF/PDF-Library/javascript/Annotations.md index 8ae876e087..4b9eb62c29 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Annotations.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Annotations.md @@ -1019,6 +1019,60 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Cloud Border Style Annotation + +A cloud border style can be applied to rectangle, polygon, circle, ellipse and freeText annotations in an existing PDF document by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. Set the `intensity` property to control the intensity of the cloud effect and set the `style` property to `PdfBorderEffectStyle.cloudy`. + +The following code example demonstrates how to apply a cloud border style to an existing rectangle annotation in a PDF document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import {PdfBorderEffect, PdfBorderEffectStyle, PdfDocument, PdfPage, PdfRectangleAnnotation} from '@syncfusion/ej2-pdf'; + +// Load an existing PDF document +let document: PdfDocument = new PdfDocument(data, password); +// Get the first page +let page: PdfPage = document.getPage(0) as PdfPage; +// Get the first rectangle annotation of the page +let annotation: PdfRectangleAnnotation = page.annotations.at(0) as PdfRectangleAnnotation; +// Initialize a new instance of the `PdfBorderEffect` class +let borderEffect: PdfBorderEffect = new PdfBorderEffect(); +// Set the intensity of the annotation border +borderEffect.intensity = 2; +// Set the cloud style of the annotation border +borderEffect.style = PdfBorderEffectStyle.cloudy; +// Set the border effect to the annotation +annotation.borderEffect = borderEffect; +// Save the document +document.save('Output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document +var document = new ej.pdf.PdfDocument(data, password); +// Get the first page +var page = document.getPage(0); +// Get the first rectangle annotation of the page +var annotation = page.annotations.at(0); +// Initialize a new instance of the PdfBorderEffect class +var borderEffect = new ej.pdf.PdfBorderEffect(); +// Set the intensity of the annotation border +borderEffect.intensity = 2; +// Set the cloud style of the annotation border +borderEffect.style = ej.pdf.PdfBorderEffectStyle.cloudy; +// Set the border effect to the annotation +annotation.borderEffect = borderEffect; +// Save the document +document.save('Output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} ## Custom appearance in stamp annotation diff --git a/Document-Processing/PDF/PDF-Library/javascript/Create-PDF-document-angular.md b/Document-Processing/PDF/PDF-Library/javascript/Create-PDF-document-angular.md index 156584bbc1..1526e8258b 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Create-PDF-document-angular.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Create-PDF-document-angular.md @@ -15,6 +15,12 @@ The [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript- This guide explains how to integrate the [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript-pdf-library) into an Angular application that runs in the browser. The generated PDF is downloaded directly from the browser; no server-side PDF rendering is involved. +## Video Tutorial + +Watch the following video to learn how to create a PDF file in an Angular application using the JavaScript PDF Library. + +{% youtube "https://www.youtube.com/watch?v=cJHZz4k6fZM" %} + ## Prerequisites Before you begin, make sure you have the following installed: diff --git a/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md b/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md index 5796f43144..cc00ba37f3 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md +++ b/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md @@ -422,6 +422,284 @@ var signedDocumentData = ej.pdf.PdfSignature.replaceEmptySignature( N> The two-step process is required when the signing operation cannot complete inside the `PdfSignature.create(...)` callback — for example, when the private key lives on a remote HSM with high latency. First, reserve the signature field with an empty signature dictionary; then, after the remote signer returns the signed bytes, call `replaceEmptySignature(...)` to embed them in the previously reserved field. +## Long-Term Validation (LTV) + +The JavaScript PDF Library supports Long-Term Validation for digital signatures through the [enableLTV()](https://ej2.syncfusion.com/documentation/api/pdf/pdfsignature#enableltv) method of the `PdfSignature` class. LTV helps preserve signature validity by embedding revocation information such as OCSP and CRL responses into the document. + +### Enable Long Term Validation (LTV) PDF signature + +The JavaScript PDF Library supports creating long-term signature validation while digitally signing a PDF document. LTV allows the signature to be validated long after the document was signed by embedding the required certificate and revocation information in the PDF document. + +The following code example explains how to create a digital signature and enable LTV using the [enableLTV()](https://ej2.syncfusion.com/documentation/api/pdf/pdfsignature#enableltv) method of the [PdfSignature](https://ej2.syncfusion.com/documentation/api/pdf/pdfsignature) class. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument, PdfPage, PdfForm, PdfSignatureField, PdfSignature, DigestAlgorithm, CryptographicStandard } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document +let document: PdfDocument = new PdfDocument(); +// Add a new page to the document +let page: PdfPage = document.addPage(); +// Access the PDF form +let form: PdfForm = document.form; +// Create a new signature field +let field: PdfSignatureField = new PdfSignatureField(page, 'Signature', { x: 10, y: 10, width: 100, height: 50 }); +// Create a digital signature using PFX data and a private key +let signature: PdfSignature = PdfSignature.create(certData, password, { cryptographicStandard: CryptographicStandard.cms, digestAlgorithm: DigestAlgorithm.sha256 }); +// Set the signature to the field +field.setSignature(signature); +// Add the signature field to the PDF form +form.add(field); +// Retrieve the OCSP or CRL response requested by the library +async function longTermValidationCallback(url: string, requestBytes?: Uint8Array): Promise<{ response: Uint8Array }> { + // Send requestBytes to the supplied URL and return the actual response bytes + return { response: new Uint8Array() }; +} +// Enable LTV for the created signature +let ltvEnabled: boolean = await signature.enableLTV(longTermValidationCallback); +// Save the document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document +var document = new ej.pdf.PdfDocument(); +// Add a new page to the document +var page = document.addPage(); +// Access the PDF form +var form = document.form; +// Create a new signature field +var field = new ej.pdf.PdfSignatureField(page, 'Signature', { x: 10, y: 10, width: 100, height: 50 }); +// Create a digital signature using PFX data and a private key +var signature = ej.pdf.PdfSignature.create(certData, password, { cryptographicStandard: ej.pdf.CryptographicStandard.cms, digestAlgorithm: ej.pdf.DigestAlgorithm.sha256 }); +// Set the signature to the field +field.setSignature(signature); +// Add the signature field to the PDF form +form.add(field); +// Retrieve the OCSP or CRL response requested by the library +var longTermValidationCallback = async function (url, requestBytes) { + // Send requestBytes to the supplied URL and return the actual response bytes + return { response: new Uint8Array() }; +}; +// Enable LTV for the created signature +var ltvEnabled = await signature.enableLTV(longTermValidationCallback); +// Save the document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + + +### Create Long Term Validation (LTV) when signing PDF documents externally + +You can create Long Term Validation (LTV) after externally signing a PDF document by using the public certificate chain. The PDF document must first be signed and saved. Then, reload the signed document, retrieve the created signature, and call the [enableLTV()](https://ej2.syncfusion.com/documentation/api/pdf/pdfsignature#enableltv) method of the [`PdfSignature`](https://ej2.syncfusion.com/documentation/api/pdf/pdfsignature) class to embed the required revocation information. + +The callback supplied to `enableLTV()` must retrieve the actual OCSP or CRL response requested by the library and return the response bytes as a `Uint8Array`. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument, PdfPage, PdfSignatureField, PdfSignature, DigestAlgorithm, CryptographicStandard, RevocationType } from '@syncfusion/ej2-pdf'; + +// Define a callback function for external signing +function externalSignatureCallback(data: Uint8Array, options: { algorithm: DigestAlgorithm, cryptographicStandard: CryptographicStandard }): { signedData: Uint8Array; timestampData?: Uint8Array } { + // Sign the supplied document data using an external signing service + return { signedData: externalSignedData }; +} +// Define a callback function to retrieve OCSP or CRL responses +async function longTermValidationCallback(url: string, requestBytes?: Uint8Array): Promise<{ response: Uint8Array }> { + // Send requestBytes to the supplied URL and return the actual OCSP or CRL response + return { response: revocationResponse }; +} +// Create a new PDF document +let document: PdfDocument = new PdfDocument(); +// Add a new page to the document +let page: PdfPage = document.addPage(); +// Create a signature field +let field: PdfSignatureField = new PdfSignatureField(page, 'Signature', { x: 50, y: 50, width: 100, height: 100 }); +// Create a signature using the external-signing callback +let signature: PdfSignature = PdfSignature.create(externalSignatureCallback, { cryptographicStandard: CryptographicStandard.cms, digestAlgorithm: DigestAlgorithm.sha256, contactInfo: 'johndoe@owned.us', locationInfo: 'Honolulu, Hawaii', reason: 'I am author of this document.', signedName: 'Signature' }); +// Add the signature field to the PDF form +document.form.add(field); +// Set the signature to the field +field.setSignature(signature); +// Save the externally signed PDF document +let data: Uint8Array = document.save(); +// Destroy the document +document.destroy(); + +// Load the externally signed PDF document +document = new PdfDocument(data); +// Get the created signature field +field = document.form.fieldAt(0) as PdfSignatureField; +// Get the created signature +signature = field.getSignature(); +// Define the public certificate chain used for long-term validation +let publicCertificates: Uint8Array[] = [publicCertificate1, publicCertificate2]; +// Enable LTV using the available OCSP or CRL response +let ltvEnabled: boolean = await signature.enableLTV(publicCertificates, RevocationType.ocspOrCrl, longTermValidationCallback); +// Save the LTV-enabled PDF document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Define a callback function for external signing +function externalSignatureCallback(data, options) { + // Sign the supplied document data using an external signing service + return { signedData: externalSignedData }; +} +// Define a callback function to retrieve OCSP or CRL responses +async function longTermValidationCallback(url, requestBytes) { + // Send requestBytes to the supplied URL and return the actual OCSP or CRL response + return { response: revocationResponse }; +} +// Create a new PDF document +var document = new ej.pdf.PdfDocument(); +// Add a new page to the document +var page = document.addPage(); +// Create a signature field +var field = new ej.pdf.PdfSignatureField(page, 'Signature', { x: 50, y: 50, width: 100, height: 100 }); +// Create a signature using the external-signing callback +var signature = ej.pdf.PdfSignature.create(externalSignatureCallback, { cryptographicStandard: ej.pdf.CryptographicStandard.cms, digestAlgorithm: ej.pdf.DigestAlgorithm.sha256, contactInfo: 'johndoe@owned.us', locationInfo: 'Honolulu, Hawaii', reason: 'I am author of this document.', signedName: 'Signature' }); +// Add the signature field to the PDF form +document.form.add(field); +// Set the signature to the field +field.setSignature(signature); +// Save the externally signed PDF document +var data = document.save(); +// Destroy the document +document.destroy(); + +// Load the externally signed PDF document +document = new ej.pdf.PdfDocument(data); +// Get the created signature field +field = document.form.fieldAt(0); +// Get the created signature +signature = field.getSignature(); +// Define the public certificate chain used for long-term validation +var publicCertificates = [publicCertificate1, publicCertificate2]; +// Enable LTV using the available OCSP or CRL response +var ltvEnabled = await signature.enableLTV(publicCertificates, ej.pdf.RevocationType.ocspOrCrl, longTermValidationCallback); +// Save the LTV-enabled PDF document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> Enable LTV only after the externally signed PDF document has been saved and the created signature has been loaded from the document. When a PDF document contains multiple signatures, call `enableLTV()` for each signature that requires long-term validation. + +### Enable Long Term Validation (LTV) with public certificates + +You can provide the public certificate chain while enabling LTV for an externally signed PDF document. The PDF document must first be signed and saved. Then, reload the signed document, retrieve the created signature, and call `enableLTV()` with the public certificates and the callback that returns the requested OCSP or CRL response. + +The following code example creates an external signature, reloads the signed PDF document, and enables LTV using the supplied public certificate chain. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument, PdfPage, PdfSignatureField, PdfSignature, DigestAlgorithm, CryptographicStandard } from '@syncfusion/ej2-pdf'; + +// Define a callback function for external signing +function externalSignatureCallback(data: Uint8Array, options: { algorithm: DigestAlgorithm, cryptographicStandard: CryptographicStandard }): { signedData: Uint8Array; timestampData?: Uint8Array } { + // Sign the supplied document data using an external signing service + return { signedData: externalSignedData }; +} +// Define a callback function to retrieve OCSP or CRL responses +async function longTermValidationCallback(url: string, requestBytes?: Uint8Array): Promise<{ response: Uint8Array }> { + // Send requestBytes to the supplied URL and return the actual OCSP or CRL response + return { response: revocationResponse }; +} +// Create a new PDF document +let document: PdfDocument = new PdfDocument(); +// Add a new page to the document +let page: PdfPage = document.addPage(); +// Create a signature field +let field: PdfSignatureField = new PdfSignatureField(page, 'Signature', { x: 50, y: 50, width: 100, height: 100 }); +// Create a signature using the external-signing callback +let signature: PdfSignature = PdfSignature.create(externalSignatureCallback, { cryptographicStandard: CryptographicStandard.cms, digestAlgorithm: DigestAlgorithm.sha256, contactInfo: 'johndoe@owned.us', locationInfo: 'Honolulu, Hawaii', reason: 'I am author of this document.', signedName: 'Signature' }); +// Add the signature field to the PDF form +document.form.add(field); +// Set the signature to the field +field.setSignature(signature); +// Save the externally signed PDF document +let data: Uint8Array = document.save(); +// Destroy the document +document.destroy(); + +// Load the externally signed PDF document +document = new PdfDocument(data); +// Get the created signature field +field = document.form.fieldAt(0) as PdfSignatureField; +// Get the created signature +signature = field.getSignature(); +// Define the public certificate chain used for long-term validation +let publicCertificates: Uint8Array[] = [publicCertificate1, publicCertificate2]; +// Enable LTV using the public certificate chain +let ltvEnabled: boolean = await signature.enableLTV(publicCertificates, longTermValidationCallback); +// Save the LTV-enabled PDF document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Define a callback function for external signing +function externalSignatureCallback(data, options) { + // Sign the supplied document data using an external signing service + return { signedData: externalSignedData }; +} +// Define a callback function to retrieve OCSP or CRL responses +async function longTermValidationCallback(url, requestBytes) { + // Send requestBytes to the supplied URL and return the actual OCSP or CRL response + return { response: revocationResponse }; +} +// Create a new PDF document +var document = new ej.pdf.PdfDocument(); +// Add a new page to the document +var page = document.addPage(); +// Create a signature field +var field = new ej.pdf.PdfSignatureField(page, 'Signature', { x: 50, y: 50, width: 100, height: 100 }); +// Create a signature using the external-signing callback +var signature = ej.pdf.PdfSignature.create(externalSignatureCallback, { cryptographicStandard: ej.pdf.CryptographicStandard.cms, digestAlgorithm: ej.pdf.DigestAlgorithm.sha256, contactInfo: 'johndoe@owned.us', locationInfo: 'Honolulu, Hawaii', reason: 'I am author of this document.', signedName: 'Signature' }); +// Add the signature field to the PDF form +document.form.add(field); +// Set the signature to the field +field.setSignature(signature); +// Save the externally signed PDF document +var data = document.save(); +// Destroy the document +document.destroy(); + +// Load the externally signed PDF document +document = new ej.pdf.PdfDocument(data); +// Get the created signature field +field = document.form.fieldAt(0); +// Get the created signature +signature = field.getSignature(); +// Define the public certificate chain used for long-term validation +var publicCertificates = [publicCertificate1, publicCertificate2]; +// Enable LTV using the public certificate chain +var ltvEnabled = await signature.enableLTV(publicCertificates, longTermValidationCallback); +// Save the LTV-enabled PDF document +document.save('output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> The callback must return the actual OCSP or CRL response received from the supplied revocation service URL. Placeholder or empty response bytes do not provide long-term validation. + ## Signature options The following examples demonstrate the signature-creation options available in `PdfSignatureOptions`. @@ -803,6 +1081,155 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Digital signature validation + +The JavaScript PDF Library supports validating digital signatures in an existing PDF document. Digital signature validation verifies the following information to determine the validity of each signature: + +* Document modifications made after signing. +* The certificate chain against the provided trusted certificates. +* Timestamp information associated with the signature. +* Certificate revocation status using Online Certificate Status Protocol (OCSP) and Certificate Revocation List (CRL) information. +* Multiple digital signatures available in the PDF document. + +## Validate a signature from a signature field + +You can validate an individual digital signature by accessing a specific signature field and validating its associated signature. This approach is useful when you need to check the validity of a particular signature in a document. + +The following code example demonstrates how to retrieve a signature field, extract its signature, and validate it using trusted certificates. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfSignatureField, PdfSignature, PdfSignatureValidationOptions } from '@syncfusion/ej2-pdf'; + +// Load the signed PDF document. +const document: PdfDocument = new PdfDocument(documentData); +// Get the first signature field from the form. +const field: PdfSignatureField = document.form.fieldAt(0) as PdfSignatureField; +// Get the signature from the field. +const signature: PdfSignature = field.getSignature(); +// Configure the signature validation options. +const options: PdfSignatureValidationOptions = { + trustedCertificates: [certificateData], + passwords: ['syncfusion'] +}; +// Validate the signature. +const validationResult = signature.validate(options); +// Check the validation result. +console.log('Signature name: ' + validationResult.signatureName); +console.log('Signature valid: ' + validationResult.isSignatureValid); +console.log('Signature status: ' + validationResult.signatureStatus); +console.log('Document modified: ' + validationResult.isDocumentModified); +console.log('Revocation result: ', validationResult.revocationResult); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the signed PDF document. +const document = new ej.pdf.PdfDocument(documentData); +// Get the first signature field from the form. +const field = document.form.fieldAt(0); +// Get the signature from the field. +const signature = field.getSignature(); +// Configure the signature validation options. +const options = { + trustedCertificates: [certificateData], + passwords: ['syncfusion'] +}; +// Validate the signature. +const validationResult = signature.validate(options); +// Check the validation result. +console.log('Signature name: ' + validationResult.signatureName); +console.log('Signature valid: ' + validationResult.isSignatureValid); +console.log('Signature status: ' + validationResult.signatureStatus); +console.log('Document modified: ' + validationResult.isDocumentModified); +console.log('Revocation result: ', validationResult.revocationResult); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} + +{% endtabs %} + +## Validate all signatures in a PDF document + +You can validate all digital signatures in a PDF document by calling the `validateSignatures` method. The method validates every signature field in the document and returns the individual results through the `results` collection. + +The following code example shows how to validate all signatures and determine whether the complete PDF document has valid signatures. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfSignatureValidationOptions } from '@syncfusion/ej2-pdf'; + +// Load the PDF document that contains multiple signatures. +const document: PdfDocument = new PdfDocument(documentData); +// Configure the validation options. +const options: PdfSignatureValidationOptions = { + trustedCertificates: [certificateData], + passwords: ['syncfusion'] +}; +// Validate all signatures in the PDF document. +const validationResult = document.form.validateSignatures(options); +if (validationResult.results !== null && + validationResult.results !== undefined) { + console.log( + 'Number of validated signatures: ' + + validationResult.results.length + ); + validationResult.results.forEach((result) => { + console.log( + `${result.signatureName}: ${result.isSignatureValid}` + ); + }); +} +// Determine whether all signatures are valid. +if (validationResult.isValid) { + console.log('All signatures in the PDF document are valid.'); +} else { + console.log('One or more signatures in the PDF document are invalid.'); +} +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the PDF document that contains multiple signatures. +const document = new PdfDocument(documentData); +// Configure the validation options. +const options = { + trustedCertificates: [certificateData], + passwords: ['syncfusion'] +}; +// Validate all signatures in the PDF document. +const validationResult = document.form.validateSignatures(options); +if (validationResult.results !== null && + validationResult.results !== undefined) { + console.log( + 'Number of validated signatures: ' + + validationResult.results.length + ); + validationResult.results.forEach((result) => { + console.log( + `${result.signatureName}: ${result.isSignatureValid}` + ); + }); +} +// Determine whether all signatures are valid. +if (validationResult.isValid) { + console.log('All signatures in the PDF document are valid.'); +} else { + console.log('One or more signatures in the PDF document are invalid.'); +} +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% endtabs %} + ## Inspecting signatures The following examples demonstrate how to read information from existing signatures in a PDF document. diff --git a/Document-Processing/PDF/PDF-Library/javascript/Encryption.md b/Document-Processing/PDF/PDF-Library/javascript/Encryption.md new file mode 100644 index 0000000000..f3eba441e6 --- /dev/null +++ b/Document-Processing/PDF/PDF-Library/javascript/Encryption.md @@ -0,0 +1,564 @@ +--- +title: Encryption in JavaScript PDF Library | Syncfusion +description: Learn how to protect PDF documents with encryption and set permissions for printing, editing, and copying using Syncfusion JavaScript PDF Library. +platform: document-processing +control: PDF +documentation: UG +--- + +# Encryption in JavaScript PDF Library + +The Syncfusion JavaScript PDF Library allows you to secure PDF documents using RC4 and AES encryption algorithms. You can also apply user and owner passwords and define permissions for operations such as printing, editing, copying content, filling form fields, and assembling documents. + +A **user password** controls whether a user can open the PDF document. An **owner password** controls whether a user can change the document permissions. When both passwords are used, specify different values for better security. + +The supported encryption algorithms are: + +- Rivest Cipher 4 (RC4) - Legacy encryption standard, suitable for backward compatibility +- Advanced Encryption Standard (AES) - Modern encryption standard, recommended for new applications + +## Working with RC4 encryption + +RC4 encryption is a legacy encryption standard that provides 40-bit and 128-bit encryption strength. Use RC4 encryption when you need to maintain compatibility with older PDF readers or legacy systems that don't support AES encryption. For new applications, consider using AES encryption instead, as it offers stronger security. + +**Use cases for RC4 encryption:** +- Maintaining compatibility with PDF readers from before 2006 +- Legacy systems that explicitly require RC4 encryption +- Quick protection for non-critical documents that need basic encryption + +You can encrypt a PDF document using 40-bit or 128-bit RC4 encryption by setting the `encryptionType` property of `PdfSecurityOptions` to `PdfEncryptionType.rc4Bit40` or `PdfEncryptionType.rc4Bit128`. + +The following example encrypts a new PDF document using RC4 128-bit encryption and a user password. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBrush, PdfDocument, PdfEncryptionType, PdfFontFamily, PdfFontStyle, PdfSecurityOptions, PdfStandardFont } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document +const document: PdfDocument = new PdfDocument(); +// Add a page to the document +const page = document.addPage(); +// Embed the standard font used to draw text +const font: PdfStandardFont = document.embedFont(PdfFontFamily.helvetica, 12, PdfFontStyle.regular); +// Draw text on the page +page.graphics.drawString( + 'Encrypted with RC4 128-bit encryption', + font, + { x: 10, y: 20, width: 300, height: 50 }, + new PdfBrush({ r: 0, g: 0, b: 0 }) +); +// Configure RC4 security using a user password +const options: PdfSecurityOptions = { + encryptionType: PdfEncryptionType.rc4Bit128, + userPassword: 'password' +}; +document.setSecurity(options); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document +const document = new ej.pdf.PdfDocument(); +// Add a page to the document +const page = document.addPage(); +// Embed the standard font used to draw text +const font = document.embedFont(ej.pdf.PdfFontFamily.helvetica, 12, ej.pdf.PdfFontStyle.regular); +// Draw text on the page +page.graphics.drawString( + 'Encrypted with RC4 128-bit encryption', + font, + { x: 10, y: 20, width: 300, height: 50 }, + new ej.pdf.PdfBrush({ r: 0, g: 0, b: 0 }) +); +// Configure RC4 security using a user password +document.setSecurity({ + encryptionType: ej.pdf.PdfEncryptionType.rc4Bit128, + userPassword: 'password' +}); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +You can restrict document operations by specifying an owner password and permission flags. The following example encrypts a new PDF document using RC4 128-bit encryption and permits only printing and accessibility-based content copying. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfEncryptionType, PdfPermissionFlag, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document +const document: PdfDocument = new PdfDocument(); +// Add a page to the document +document.addPage(); +// Restrict the document operations using an owner password and permission flags +// This allows only printing and accessibility-based content copying +const options: PdfSecurityOptions = { + encryptionType: PdfEncryptionType.rc4Bit128, + ownerPassword: 'ownerPassword', + userPassword: 'userPassword', + permissions: PdfPermissionFlag.print | + PdfPermissionFlag.accessibilityCopyContent +}; +document.setSecurity(options); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document +const document = new ej.pdf.PdfDocument(); +// Add a page to the document +document.addPage(); +// Restrict the document operations using an owner password and permission flags +// This allows only printing and accessibility-based content copying +document.setSecurity({ + encryptionType: ej.pdf.PdfEncryptionType.rc4Bit128, + ownerPassword: 'ownerPassword', + userPassword: 'userPassword', + permissions: ej.pdf.PdfPermissionFlag.print | + ej.pdf.PdfPermissionFlag.accessibilityCopyContent +}); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> When both user and owner passwords are specified, use different values for the two passwords. + +## Working with AES encryption + +AES (Advanced Encryption Standard) encryption provides modern, strong encryption for your PDF documents. It offers multiple bit strengths (128-bit, 256-bit Revision 5, and 256-bit Revision 6) to balance security requirements with compatibility. AES is the recommended encryption method for new applications and sensitive documents. + +**Use cases for AES encryption:** +- Protecting confidential or sensitive documents +- Meeting compliance requirements (GDPR, HIPAA, etc.) +- Ensuring long-term document security +- Applications requiring strong, modern encryption standards +- Archival documents that need maximum security + +You can encrypt a PDF document using AES encryption by setting the `encryptionType` property to a supported AES value such as `PdfEncryptionType.aesBit128`, `PdfEncryptionType.aesBit256Rev5`, or `PdfEncryptionType.aesBit256Rev6`. + +The following example encrypts a new PDF document using AES 256-bit Revision 5 encryption and an owner password. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfEncryptionType, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document +const document: PdfDocument = new PdfDocument(); +// Add a page to the document +document.addPage(); + +// Configure AES 256-bit encryption with owner password +// This provides strong, modern encryption recommended for sensitive documents +const options: PdfSecurityOptions = { + encryptionType: PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword' +}; +document.setSecurity(options); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document +const document = new ej.pdf.PdfDocument(); +// Add a page to the document +document.addPage(); + +// Configure AES 256-bit encryption with owner password +// This provides strong, modern encryption recommended for sensitive documents +document.setSecurity({ + encryptionType: ej.pdf.PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword' +}); +// Save the encrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Decrypting an encrypted PDF document + +Decryption allows you to remove password protection from a PDF document by clearing both the user and owner passwords and restoring full permissions. This is useful when you need to access or modify a previously secured document, or when you need to change the security settings. + +**Use cases for decryption:** +- Removing security from documents you own +- Preparing documents for unrestricted distribution +- Converting from one encryption method to another +- Restoring full permissions to previously restricted documents + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfPermissionFlag, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Open the encrypted document using a valid password +const document: PdfDocument = new PdfDocument(inputData, 'password'); +// Clear the passwords and restore all supported permissions +const options: PdfSecurityOptions = { + userPassword: '', + ownerPassword: '', + permissions: PdfPermissionFlag.default +}; +document.setSecurity(options); +// Save the decrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the encrypted PDF document using the current password +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Clear the passwords and restore all supported permissions +document.setSecurity({ + userPassword: '', + ownerPassword: '', + permissions: ej.pdf.PdfPermissionFlag.default +}); +// Save the decrypted PDF document +document.save('Output.pdf'); +// Destroy the document and release its resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Protect an existing PDF document + +This approach allows you to add encryption to documents that were previously unencrypted. It's useful when you already have PDF files and need to secure them retroactively. + +**Use cases for protecting existing documents:** +- Securing previously unencrypted documents +- Upgrading to stronger encryption on existing PDFs +- Adding access control to documents already in use +- Batch-protecting multiple documents with consistent security settings + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfEncryptionType, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load an existing PDF document that is currently unencrypted +const document: PdfDocument = new PdfDocument(inputData); +// Configure encryption settings with both user and owner passwords +// User password: Required to open the document +// Owner password: Controls document permissions and modifications +const securityOptions: PdfSecurityOptions = { + encryptionType: PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword256', + userPassword: 'userPassword256' +}; +// Apply encryption to the document +document.setSecurity(securityOptions); +// Save the now-encrypted document +document.save('ProtectedDocument.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document that is currently unencrypted +const document = new ej.pdf.PdfDocument(inputData); +// Configure encryption settings with both user and owner passwords +// User password: Required to open the document +// Owner password: Controls document permissions and modifications +document.setSecurity({ + encryptionType: ej.pdf.PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword256', + userPassword: 'userPassword256' +}); +// Save the now-encrypted document +document.save('ProtectedDocument.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Changing the password of a PDF document + +Update the security credentials of an existing encrypted document without modifying other security settings. This allows users or administrators to refresh authentication credentials periodically. + +**Use cases for password changes:** +- Periodic security credential rotation +- Responding to password compromise +- Updating passwords when personnel change +- Enforcing new password policies + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load the password-protected PDF document with the current password +const document: PdfDocument = new PdfDocument(inputData, 'password'); +// Create new security options with the updated user password +// All other encryption settings remain unchanged +const securityOptions: PdfSecurityOptions = { + userPassword: 'NewPassword' +}; +// Apply the new password to the document +document.setSecurity(securityOptions); +// Save the document with the updated password +document.save('PasswordChanged.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the password-protected PDF document with the current password +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Create new security options with the updated user password +// All other encryption settings remain unchanged +document.setSecurity({ + userPassword: 'NewPassword' +}); +// Save the document with the updated password +document.save('PasswordChanged.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## View document permission flags + +Inspect the permissions currently set on a secured PDF document to understand which operations users can perform. This is essential for auditing document security and verifying that restrictions are correctly applied. + +**Use cases for viewing permissions:** +- Auditing document security settings +- Verifying permission restrictions before distribution +- Understanding which operations are permitted on received documents +- Programmatically checking document access levels + +The `permissions` property of `PdfDocument` returns the permission flags available in the loaded PDF document. Since `PdfPermissionFlag` is a bitwise enumeration, use the bitwise AND operator to determine whether an individual permission is enabled. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfPermissionFlag } from '@syncfusion/ej2-pdf'; + +// Load the secured PDF document with the required password +const document: PdfDocument = new PdfDocument(inputData, 'password'); +// Get the permission flags from the document +// PdfPermissionFlag is a bitwise enumeration, so use bitwise AND (&) to check each flag +const permissions: PdfPermissionFlag = document.permissions; +// Check individual permission flags +// Each permission is checked using bitwise AND operation to verify if enabled +const canPrint: boolean = (permissions & PdfPermissionFlag.print) !== 0; +const canCopyContent: boolean = (permissions & PdfPermissionFlag.copyContent) !== 0; +const canEditContent: boolean = (permissions & PdfPermissionFlag.editContent) !== 0; +const canEditAnnotations: boolean = (permissions & PdfPermissionFlag.editAnnotations) !== 0; +const canFillFields: boolean = (permissions & PdfPermissionFlag.fillFields) !== 0; +const canCopyForAccessibility: boolean = (permissions & PdfPermissionFlag.accessibilityCopyContent) !== 0; +const canAssembleDocument: boolean = (permissions & PdfPermissionFlag.assembleDocument) !== 0; +const canPrintInFullQuality: boolean = (permissions & PdfPermissionFlag.fullQualityPrint) !== 0; +// Use the permission flags for decision-making +console.log('Printing allowed: ' + canPrint); +console.log('Copying allowed: ' + canCopyContent); +console.log('Editing allowed: ' + canEditContent); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the secured PDF document with the required password +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Get the permission flags from the document +// PdfPermissionFlag is a bitwise enumeration, so use bitwise AND (&) to check each flag +const permissions = document.permissions; +// Check individual permission flags +// Each permission is checked using bitwise AND operation to verify if enabled +const canPrint = (permissions & ej.pdf.PdfPermissionFlag.print) !== 0; +const canCopyContent = (permissions & ej.pdf.PdfPermissionFlag.copyContent) !== 0; +const canEditContent = (permissions & ej.pdf.PdfPermissionFlag.editContent) !== 0; +const canEditAnnotations = (permissions & ej.pdf.PdfPermissionFlag.editAnnotations) !== 0; +const canFillFields = (permissions & ej.pdf.PdfPermissionFlag.fillFields) !== 0; +const canCopyForAccessibility = (permissions & ej.pdf.PdfPermissionFlag.accessibilityCopyContent) !== 0; +const canAssembleDocument = (permissions & ej.pdf.PdfPermissionFlag.assembleDocument) !== 0; +const canPrintInFullQuality = (permissions & ej.pdf.PdfPermissionFlag.fullQualityPrint) !== 0; +// Use the permission flags for decision-making +console.log('Printing allowed: ' + canPrint); +console.log('Copying allowed: ' + canCopyContent); +console.log('Editing allowed: ' + canEditContent); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +The following flags can be combined when configuring document permissions: + +- `PdfPermissionFlag.print` +- `PdfPermissionFlag.copyContent` +- `PdfPermissionFlag.editContent` +- `PdfPermissionFlag.editAnnotations` +- `PdfPermissionFlag.fillFields` +- `PdfPermissionFlag.accessibilityCopyContent` +- `PdfPermissionFlag.assembleDocument` +- `PdfPermissionFlag.fullQualityPrint` + +## Change the permissions of a PDF document + +Modify the access restrictions on an existing secured document to grant or restrict specific operations. This allows fine-grained control over what users can do with your PDF documents. + +**Use cases for changing permissions:** +- Restricting editing capabilities while allowing printing +- Limiting copy/paste operations to prevent content theft +- Preventing form field modifications on locked forms +- Allowing printing but restricting annotation abilities +- Disabling high-quality printing for premium documents + +Load the document using a valid password before updating the permission flags using the `permissions` property of `PdfSecurityOptions`. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfPermissionFlag, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load the secured PDF document using the owner password +// The owner password is required to modify document permissions +const document: PdfDocument = new PdfDocument(inputData, 'syncfusion'); +// Configure new permissions using bitwise OR (|) to combine multiple flags +// This example allows content copying and document assembly +// Use the bitwise OR operator to combine multiple permission flags +const securityOptions: PdfSecurityOptions = { + permissions: PdfPermissionFlag.copyContent | + PdfPermissionFlag.assembleDocument +}; +// Apply the new permission settings to the document +document.setSecurity(securityOptions); +// Save the document with updated permissions +document.save('UpdatedPermissions.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the secured PDF document using the owner password +// The owner password is required to modify document permissions +const document = new ej.pdf.PdfDocument(inputData, 'syncfusion'); +// Configure new permissions using bitwise OR (|) to combine multiple flags +// This example allows content copying and document assembly +// Use the bitwise OR operator to combine multiple permission flags +document.setSecurity({ + permissions: ej.pdf.PdfPermissionFlag.copyContent | + ej.pdf.PdfPermissionFlag.assembleDocument +}); +// Save the document with updated permissions +document.save('UpdatedPermissions.pdf'); +// Clean up resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## How to determine whether a PDF document is password protected + +To determine whether a PDF document requires a password, try loading it without a password and check if the error message indicates the document is encrypted. This approach allows you to programmatically detect password-protected documents. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument } from '@syncfusion/ej2-pdf'; + +let isPasswordProtected: boolean = false; +try { + // Attempt to load the document without providing a password + const document: PdfDocument = new PdfDocument(inputData); + // If we reach here, the document is not password protected + isPasswordProtected = false; + document.destroy(); +} catch (error: any) { + // Check if the error message indicates an encrypted document requiring a password + if (error.message === 'Cannot open an encrypted document. The password is invalid.') { + isPasswordProtected = true; + } +} +// Use isPasswordProtected to determine next action +console.log('Password protected: ' + isPasswordProtected); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +let isPasswordProtected = false; +try { + // Attempt to load the document without providing a password + const document = new ej.pdf.PdfDocument(inputData); + // If we reach here, the document is not password protected + isPasswordProtected = false; + document.destroy(); +} catch (error) { + // Check if the error message indicates an encrypted document requiring a password + if (error.message === 'Cannot open an encrypted document. The password is invalid.') { + isPasswordProtected = true; + } +} +// Use isPasswordProtected to determine next action +console.log('Password protected: ' + isPasswordProtected); + +{% endhighlight %} +{% endtabs %} + +N> A loading error can also occur for a damaged or unsupported PDF document. If an application needs to distinguish these cases, inspect the reported error and handle other load failures separately. + +## How to determine whether a PDF document is protected by a user or owner password + +The following table describes the values available after loading a secured PDF document with either its user password or owner password. No code sample is required for this behavior. + +| Document type | Opened with | User password value | Owner password value | +|----------|----------|----------|----------| +| PDF document secured with both owner and user passwords | User password | Returns the user password | Returns null | +| PDF document secured with both owner and user passwords | Owner password | Returns the user password. **Note:** Returns null for AES 256-bit and AES 256-bit Revision 6 encryption. | Returns the owner password | +| PDF document secured only with an owner password | Owner password | Returns null | Returns the owner password | +| PDF document secured only with a user password | User password | Returns the user password | Returns the owner password. The owner password is the same as the user password and grants full permission to the user. | + +## Encryption API Reference + +The following table summarizes the key methods and options for encryption operations in the JavaScript PDF Library: + +| Operation | Method/Property | Description | Use Case | +|-----------|-----------------|-------------|----------| +| **Encrypt a new document with RC4** | `PdfDocument.setSecurity({ encryptionType: PdfEncryptionType.rc4Bit128, userPassword: 'password' })` | Encrypts a document using 128-bit RC4 encryption with a user password | Legacy system compatibility, backward compatibility with older PDF readers | +| **Encrypt with permissions (RC4)** | `PdfDocument.setSecurity({ encryptionType: PdfEncryptionType.rc4Bit128, ownerPassword: 'owner', userPassword: 'user', permissions: PdfPermissionFlag.print \| ... })` | Restricts document operations using owner password and permission flags | Fine-grained access control on legacy documents | +| **Encrypt with AES (recommended)** | `PdfDocument.setSecurity({ encryptionType: PdfEncryptionType.aesBit256Rev5, ownerPassword: 'password' })` | Encrypts a document using modern AES 256-bit encryption | Securing sensitive/confidential documents, compliance requirements | +| **Decrypt a document** | `PdfDocument.setSecurity({ userPassword: '', ownerPassword: '', permissions: PdfPermissionFlag.default })` | Removes password protection and restores all permissions | Removing security from owned documents, unrestricted distribution | +| **Protect existing document** | `new PdfDocument(inputData)` + `setSecurity({ encryptionType: PdfEncryptionType.aesBit256Rev5, ... })` | Adds encryption to an unencrypted PDF document | Retroactive security, batch encryption of existing files | +| **Change password** | `new PdfDocument(inputData, 'currentPassword')` + `setSecurity({ userPassword: 'NewPassword' })` | Updates authentication credentials without changing encryption type | Credential rotation, security policy updates | +| **View permissions** | `document.permissions` + bitwise AND checks | Retrieves permission flags from an encrypted document | Auditing security settings, verifying restrictions | +| **Change permissions** | `PdfDocument.setSecurity({ permissions: PdfPermissionFlag.copyContent \| PdfPermissionFlag.assembleDocument })` | Modifies access restrictions on secured documents | Restricting editing, preventing copying, limiting operations | + +## Additional Resources + +- [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript-pdf-library) +- [JavaScript PDF Library documentation](https://help.syncfusion.com/document-processing/pdf/pdf-library/javascript/overview) +- [JavaScript PDF Library API reference](https://ej2.syncfusion.com/documentation/api/pdf) +- [JavaScript PDF Library examples](https://document.syncfusion.com/demos/pdf/javascript/#/tailwind3/pdf/default) \ No newline at end of file diff --git a/Document-Processing/PDF/PDF-Library/javascript/Lists.md b/Document-Processing/PDF/PDF-Library/javascript/Lists.md index f8070171fa..a8a9353721 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Lists.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Lists.md @@ -147,6 +147,61 @@ document.destroy(); This example demonstrates how to change the marker style of an unordered list in a PDF document using the [PdfUnorderedList](https://ej2.syncfusion.com/documentation/api/pdf/pdfunorderedlist) class. The marker defines the symbol that appears before each list item. You can choose from the predefined marker styles listed below to visually distinguish different list types or emphasize specific content. +### Set image marker + +You can use an image as the marker for an unordered list by creating a `PdfImageMarker` with a `PdfBitmap` and passing it to the `setMarker` method of `PdfUnorderedList`. + +The following code example shows how to create a PDF document, add an unordered list, set an image as the list marker, and save the document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBitmap, PdfDocument, PdfImageMarker, PdfListItemCollection, PdfUnorderedList } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document. +const document: PdfDocument = new PdfDocument(); +// Add a new page to the document. +const page = document.addPage(); +// Create the items for the unordered list. +const items: PdfListItemCollection = new PdfListItemCollection([ 'Essential PDF', 'Essential DocIO', 'Essential XlsIO']); +// Create an unordered list. +const unorderedList: PdfUnorderedList = new PdfUnorderedList(items); +// Create an image marker using the loaded image. +const imageMarker: PdfImageMarker = {image: new PdfBitmap(imageData)}; +// Set the image as the marker for the unordered list. +unorderedList.setMarker(imageMarker); +// Draw the unordered list on the PDF page. +unorderedList.draw(page, { x: 10,y: 20, width: page.graphics.clientSize.width - 20, height: page.graphics.clientSize.height - 40}); +// Save the PDF document. +document.save('SetImageMarker.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document. +const document = new ej.pdf.PdfDocument(); +// Add a new page to the document. +const page = document.addPage(); +// Create the items for the unordered list. +const items = new ej.pdf.PdfListItemCollection([ 'Essential PDF', 'Essential DocIO', 'Essential XlsIO']); +// Create an unordered list. +const unorderedList = new ej.pdf.PdfUnorderedList(items); +// Create an image marker using the loaded image. +const imageMarker = { image: new ej.pdf.PdfBitmap(imageData)}; +// Set the image as the marker for the unordered list. +unorderedList.setMarker(imageMarker); +// Draw the unordered list on the PDF page. +unorderedList.draw(page, {x: 10, y: 20, width: page.graphics.clientSize.width - 20, height: page.graphics.clientSize.height - 40 }); +// Save the PDF document. +document.save('SetImageMarker.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% endtabs %} + ### PdfUnorderedListStyle values | Value | Rendered marker | diff --git a/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md b/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md index 666aaf3ca5..eb54659637 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md @@ -18,9 +18,11 @@ The JavaScript PDF library allows you to extract text from a particular page or N> The `@syncfusion/ej2-pdf-data-extract` add-on package also powers the redaction features available in the JavaScript PDF Library. -## Working with basic text extraction +## Working with basic text extraction synchronously -This example demonstrates how to extract plain text from a PDF document using the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class. Basic text extraction retrieves text content from the entire PDF document. +The `extractTextSync` method provides the simplest way to retrieve all text content from a PDF document in a single operation. This synchronous approach is ideal when you need immediate access to the complete text and your document size permits blocking execution. + +The following example demonstrates how to extract plain text from a PDF document synchronously using the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -32,8 +34,8 @@ import { PdfDataExtractor } from '@syncfusion/ej2-pdf-data-extract'; let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract text content from the PDF document. -let text: string = extractor.extractText(); +// Extract text content from the PDF document synchronously. +let text: string = extractor.extractTextSync(); // Save the document document.save('Output.pdf'); // Close the document @@ -46,8 +48,8 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the PdfDataExtractor class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract text content from the PDF document -var text = extractor.extractText(); +// Extract text content from the PDF document synchronously +var text = extractor.extractTextSync(); // Save the document document.save('Output.pdf'); // Close the document @@ -56,9 +58,16 @@ document.destroy(); {% endhighlight %} {% endtabs %} -## Extract text from specific page range in a PDF document +## Extract text from a specific page range in a PDF document synchronously + +When working with large PDF documents, you may want to extract text from specific pages rather than processing the entire document. The `extractTextSync` method accepts optional parameters to define the start and end page indices, allowing you to retrieve text content from a targeted page range. + +This approach is useful for: +- Processing specific chapters or sections of a document +- Reducing memory usage with large files +- Focusing extraction on relevant content -This example demonstrates how to extract text from a PDF document by specifying a start and end page index. This approach allows you to retrieve text content from a defined range of pages for processing or analysis. +The following example shows how to extract text from a defined page range synchronously: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -69,8 +78,8 @@ import { PdfDataExtractor } from '@syncfusion/ej2-pdf-data-extract'; let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract text content from the specified page range -let text: string = extractor.extractText({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract text content from the specified page range synchronously +let text: string = extractor.extractTextSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); // Release document resources document.destroy(); @@ -81,17 +90,19 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract text content from the specified page range -var text = extractor.extractText({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract text content from the specified page range synchronously +var text = extractor.extractTextSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); // Release document resources document.destroy(); {% endhighlight %} {% endtabs %} -## Working with layout-based text extraction +## Working with layout-based text extraction synchronously -This example demonstrates how to extract text from a PDF document using the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class with layout-based options. Layout-based extraction preserves the visual structure of the source document, including line breaks and spacing. +For documents where the visual structure and formatting are important to the extracted content, use layout-based text extraction. This method preserves the original document layout, including line breaks, spacing, and paragraph structure—making the extracted text more readable and maintaining its logical organization. + +The following example demonstrates how to extract text with layout preservation using the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -102,8 +113,8 @@ import { PdfDataExtractor } from '@syncfusion/ej2-pdf-data-extract'; let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract text from the PDF page based on its layout -let text: string = extractor.extractText({ isLayout: true }); +// Extract text from the PDF page based on its layout synchronously +let text: string = extractor.extractTextSync({ isLayout: true }); // Release document resources document.destroy(); @@ -114,23 +125,39 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract text from the PDF page based on its layout -var text = extractor.extractText({ isLayout: true }); +// Extract text from the PDF page based on its layout synchronously +var text = extractor.extractTextSync({ isLayout: true }); // Release document resources document.destroy(); {% endhighlight %} {% endtabs %} -N> Layout-based text extraction may take additional processing time when compared to the basic extraction mode. - ## Text extraction with bounds -The following sections describe how to extract text along with positional and typographic information using the [extractTextLines](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlines) method. The method returns a hierarchical collection of [TextLine](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textline), [TextWord](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textword), and [TextGlyph](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textglyph) objects. +For advanced use cases that require precise spatial information about text content, use bounds-based extraction. This method returns detailed hierarchical information including positional coordinates (bounds), font properties, size, style, and color for each text element. + +Bounds-based extraction is essential for: +- Highlighting or annotating specific text locations +- Implementing search result highlighting +- Applying redactions to sensitive content +- Programmatically identifying text regions for document analysis +- Building custom search interfaces with visual feedback -### Working with lines +The [extractTextLinesSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlinessync) and [extractTextLines](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlines) methods return hierarchical collections of [TextLine](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textline), [TextWord](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textword), and [TextGlyph](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textglyph) objects, allowing you to work with text at different levels of granularity. -This example demonstrates how to extract text from a PDF page based on individual lines. The [extractTextLines](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlines) method returns a collection of [TextLine](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textline) objects, allowing precise access to text content line by line. +### Working with Lines + +Line-level extraction provides structured text content organized by line, with position and formatting information for each line. This granularity is useful for analyzing text structure, implementing line-based highlighting, or processing documents with multi-column layouts. + +The [extractTextLinesSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlinessync) method returns a collection of [TextLine](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textline) objects. Each TextLine object contains: +- **text**: The complete text content of the line +- **bounds**: The rectangular region occupied by the line on the page +- **pageIndex**: Which page the line appears on +- **fontName, fontStyle, fontSize**: Typographic information for the line +- **words**: A collection of word-level objects within the line + +The following example demonstrates line-level text extraction: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -141,8 +168,8 @@ import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle, Rectangl let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -let textLines: Array = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +let textLines: Array = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); // Iterate through each text line in the collection textLines.forEach((textLine: TextLine) => { // Gets the bounds of the text line @@ -170,8 +197,8 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -var textLines = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +var textLines = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); // Iterate through each text line in the collection textLines.forEach((textLine) => { // Gets the bounds of the text line @@ -195,9 +222,17 @@ document.destroy(); {% endhighlight %} {% endtabs %} -### Working with words +### Working with Words -This example demonstrates how to extract words from a PDF document using the [extractTextLines](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlines) method. Each line contains a collection of [TextWord](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textword) objects. +Word-level extraction provides fine-grained access to individual words with their positions and properties. This is particularly useful for text highlighting, word-based search result visualization, spell-checking integration, or linguistic analysis. + +Each [TextLine](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textline) contains a collection of [TextWord](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textword) objects. Each TextWord object includes: +- **text**: The word content +- **bounds**: The position of the word on the page +- **fontName, fontStyle, fontSize**: Font properties for the word +- **glyphs**: Individual character-level data within the word + +The following example demonstrates how to access and process word-level data: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -208,8 +243,8 @@ import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle, Rectangl let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -let textLines: Array = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +let textLines: Array = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine: TextLine) => { textLine.words.forEach((textWord: TextWord) => { // Gets the bounds of the text word @@ -236,8 +271,8 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -var textLines = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +var textLines = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine) => { textLine.words.forEach((textWord) => { // Gets the bounds of the text word @@ -260,9 +295,22 @@ document.destroy(); {% endhighlight %} {% endtabs %} -### Working with characters +### Working with characters synchronously + +Character-level (glyph) extraction provides the most granular level of detail, allowing you to access individual characters with their exact positions, colors, and font properties. This level of detail is essential for: +- Precise text highlighting at the character level +- Color-aware text extraction +- Detecting rotated or specially formatted characters +- Building advanced search and annotation features -You can retrieve a single character and its properties, including bounds, font name, font size, and text color, using the [extractTextLines](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlines) method. Refer to the code sample below. +Use the [extractTextLinesSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlinessync) method to retrieve character-level data. Each [TextGlyph](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textglyph) object contains: +- **text**: The character content +- **bounds**: Precise position of the character +- **fontName, fontStyle, fontSize**: Font properties +- **color**: The text color +- **isRotated**: Whether the character is rotated + +The following example demonstrates character-level extraction: {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -273,8 +321,8 @@ import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle } from '@ let document: PdfDocument = new PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class let extractor: PdfDataExtractor = new PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -let textLines: Array = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +let textLines: Array = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine: TextLine) => { textLine.words.forEach((textWord: TextWord) => { textWord.glyphs.forEach((textGlyph: TextGlyph) => { @@ -305,8 +353,8 @@ document.destroy(); var document = new ej.pdf.PdfDocument(data); // Initialize a new instance of the `PdfDataExtractor` class var extractor = new ej.pdfdataextract.PdfDataExtractor(document); -// Extract `TextLine` objects from the PDF document -var textLines = extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Extract `TextLine` objects from the PDF document synchronously +var textLines = extractor.extractTextLinesSync({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine) => { textLine.words.forEach((textWord) => { textWord.glyphs.forEach((textGlyph) => { @@ -333,6 +381,150 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Text Extraction API Reference + +The following table provides a comprehensive overview of all text extraction methods available in the `PdfDataExtractor` class: + +| Process | Method Signature | Return Type | Description | +|---|---|---|---| +| **Extract Text** | `extractTextSync()` | `string` | Extracts plain text synchronously from the entire PDF document. | +| **Extract Text** | `extractText()` | `Promise` | Extracts plain text asynchronously from the entire PDF document. | +| **Extract Text (Page Range)** | `extractTextSync(options: { startPageIndex: number; endPageIndex: number })` | `string` | Extracts plain text synchronously from a specified page range using start and end page indices. | +| **Extract Text (Page Range)** | `extractText(options: { startPageIndex: number; endPageIndex: number })` | `Promise` | Extracts plain text asynchronously from a specified page range using start and end page indices. | +| **Extract Layout Text** | `extractTextSync(options: { isLayout: boolean })` | `string` | Extracts layout-based text synchronously, preserving the visual structure and spacing of the source document. | +| **Extract Layout Text** | `extractText(options: { isLayout: boolean })` | `Promise` | Extracts layout-based text asynchronously, preserving the visual structure and spacing of the source document. | +| **Extract Text with Bounds** | `extractTextLinesSync(options?: { startPageIndex?: number; endPageIndex?: number })` | `TextLine[]` | Extracts text synchronously with hierarchical line, word, and character-level information including positional bounds. | +| **Extract Text with Bounds** | `extractTextLines(options?: { startPageIndex?: number; endPageIndex?: number })` | `Promise` | Extracts text asynchronously with hierarchical line, word, and character-level information including positional bounds. | + +### Find text + +The `findTextSync` method of the `PdfDataExtractor` class locates specific text in a PDF document. The method returns the page index and rectangular bounds of each matching text occurrence synchronously. These details are useful for highlighting text, applying redaction, adding annotations, navigating between search results, and building custom search features. + +The following code example demonstrates how to search for text synchronously in a PDF document. + +{% tabs %} + +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument } from '@syncfusion/ej2-pdf'; +import { PdfDataExtractor } from '@syncfusion/ej2-pdf-data-extract'; + +// Load an existing PDF document +let document: PdfDocument = new PdfDocument(data); +// Initialize a new instance of the `PdfDataExtractor` class +let extractor: PdfDataExtractor = new PdfDataExtractor(document); +// Search for the specified text and retrieve the matching occurrences synchronously +let searchResults = extractor.findTextSync('PDF', { caseSensitive: false, wholeWord: false, startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Display the search results +console.log(searchResults); +// Release document resources +document.destroy(); + +{% endhighlight %} + +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document +var document = new ej.pdf.PdfDocument(data); +// Initialize a new instance of the PdfDataExtractor class +var extractor = new ej.pdfdataextract.PdfDataExtractor(document); +// Search for the specified text and retrieve the matching occurrences synchronously +var searchResults = extractor.findTextSync('PDF', { caseSensitive: false, wholeWord: false, startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Release document resources +document.destroy(); +// Display the search results +console.log(searchResults); + +{% endhighlight %} + +{% endtabs %} + +N> Use `findTextSync` when the search result is required immediately. For large PDF documents, use the asynchronous `findText` method to avoid blocking execution. + +## Search for multiple text values and get the bounds + +You can search for multiple text values in a PDF document and retrieve the location of every occurrence using the `findTextSync` and `findText` methods of the `PdfDataExtractor` class. + +The `findTextSync` method searches the PDF document synchronously, while the `findText` method performs the search asynchronously. Both methods accept optional text-search settings and return the searched text together with the bounding rectangles of all matching occurrences grouped by page number. The returned bounds can be used for highlighting, redaction, annotation, and document navigation. + +The following code example demonstrates how to search for multiple text values synchronously using optional search parameters and retrieve the bounds of all matching occurrences in a PDF document. + +{% tabs %} + +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument } from '@syncfusion/ej2-pdf'; +import { PdfDataExtractor, TextSearchResult, Rectangle } from '@syncfusion/ej2-pdf-data-extract'; + +// Load an existing PDF document +let document: PdfDocument = new PdfDocument(data); +// Initialize a new instance of the PdfDataExtractor class +let extractor: PdfDataExtractor = new PdfDataExtractor(document); +// Search for multiple text values synchronously using optional search parameters +let textSearchResults: TextSearchResult[] = extractor.findTextSync(['hello', 'world', 'PDF'], { caseSensitive: false, wholeWord: true, startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Iterate through each search result +textSearchResults.forEach((textSearch: TextSearchResult) => { + // Get the searched text + let searchText: string = textSearch.searchText; + // Get the matching bounds grouped by page number + let searchResults: Map; = textSearch.searchResults; + // Process the results for each search term + searchResults.forEach((bounds: Rectangle[], pageIndex: number) => { + // Access bounds for each matching occurrence + bounds.forEach((bound: Rectangle) => { + console.log(`Found "${searchText}" on page ${pageIndex} at bounds:`, bound); + }); + }); +}); +// Release document resources +document.destroy(); + +{% endhighlight %} + +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document +var document = new ej.pdf.PdfDocument(data); +// Initialize a new instance of the PdfDataExtractor class +var extractor = new ej.pdfdataextract.PdfDataExtractor(document); +// Search for multiple text values synchronously using optional search parameters +var textSearchResults = extractor.findTextSync(['hello', 'world', 'PDF'], { caseSensitive: false, wholeWord: true, startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Iterate through each search result +textSearchResults.forEach((textSearch) => { + // Get the searched text + var searchText = textSearch.searchText; + // Get the matching bounds grouped by page number + var searchResults = textSearch.searchResults; + // Process the results for each search term + searchResults.forEach((bounds, pageIndex) => { + // Access bounds for each matching occurrence + bounds.forEach((bound) => { + console.log(`Found "${searchText}" on page ${pageIndex} at bounds:`, bound); + }); + }); +}); +// Release document resources +document.destroy(); + +{% endhighlight %} + +{% endtabs %} + +N> The `findTextSync()` and `findText()` methods also accept a collection of text values as a `string[]`. When multiple text values are provided, `findTextSync()` returns a `TextSearchResult[]`, while `findText()` returns a `Promise`. Each item in the returned collection corresponds to one input text value and contains the searched text in `searchText` and the matching bounding rectangles grouped by page number in `searchResults`. + +## FindText Module API Reference + +Use the following table to select the text-search method that matches your requirement. + +| Method | Return Type | Description | +|---|---|---| +| `findText(text: string)` | Promise | Searches for the specified text asynchronously throughout the PDF document and returns all matching occurrences with their page indexes and bounds. | +| `findText(text: string, options)` | Promise | Searches for the specified text asynchronously using the supplied text-search options and returns the matching occurrences. | +| `findTextSync(text: string)` | Text search result collection | Searches for the specified text synchronously throughout the PDF document and returns all matching occurrences with their page indexes and bounds. | +| `findTextSync(text: string, options)` | Text search result collection | Searches for the specified text synchronously using the supplied text-search options and returns the matching occurrences. | + +Use the following table for text search options in the find text method. | + ## Additional Resources - [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript-pdf-library)