diff --git a/Document-Processing-toc.html b/Document-Processing-toc.html index a51280b771..09853e47c4 100644 --- a/Document-Processing-toc.html +++ b/Document-Processing-toc.html @@ -3450,6 +3450,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..ba73e1d681 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Annotations.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Annotations.md @@ -1019,6 +1019,296 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Cloud Border Style Annotation + +A cloud border style can be applied to rectangle, polygon, circle, and ellipse 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`. + +### PdfRectangleAnnotation + +A cloud border style can be applied to an existing [PdfRectangleAnnotation](https://ej2.syncfusion.com/documentation/api/pdf/pdfrectangleannotation) by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. + +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 %} + +### PdfPolygonAnnotation + +A cloud border style can be applied to an existing [PdfPolygonAnnotation](https://ej2.syncfusion.com/documentation/api/pdf/pdfpolygonannotation) by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. + +The following code example demonstrates how to apply a cloud border style to an existing polygon annotation in a PDF document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import {PdfBorderEffect, PdfBorderEffectStyle, PdfDocument, PdfPage, PdfPolygonAnnotation} 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 polygon annotation of the page +let annotation: PdfPolygonAnnotation = page.annotations.at(0) as PdfPolygonAnnotation; +// 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 polygon 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 %} + +### PdfCircleAnnotation + +A cloud border style can be applied to an existing [PdfCircleAnnotation](https://ej2.syncfusion.com/documentation/api/pdf/pdfcircleannotation) by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. + +The following code example demonstrates how to apply a cloud border style to an existing circle annotation in a PDF document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import {PdfBorderEffect, PdfBorderEffectStyle, PdfCircleAnnotation, PdfDocument, PdfPage} 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 circle annotation of the page +let annotation: PdfCircleAnnotation = page.annotations.at(0) as PdfCircleAnnotation; +// 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// 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 circle 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// Save the document +document.save('Output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +### PdfEllipseAnnotation + +A cloud border style can be applied to an existing [PdfEllipseAnnotation](https://ej2.syncfusion.com/documentation/api/pdf/pdfellipseannotation) by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. + +The following code example demonstrates how to apply a cloud border style to an existing ellipse annotation in a PDF document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import {PdfBorderEffect, PdfBorderEffectStyle, PdfDocument, PdfEllipseAnnotation, PdfPage} 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 ellipse annotation of the page +let annotation: PdfEllipseAnnotation = page.annotations.at(0) as PdfEllipseAnnotation; +// 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// 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 ellipse 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// Save the document +document.save('Output.pdf'); +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +### PdfFreeTextAnnotation + +A cloud border style can be applied to an existing [PdfFreeTextAnnotation](https://ej2.syncfusion.com/documentation/api/pdf/pdffreetextannotation) by using the [PdfBorderEffect](https://ej2.syncfusion.com/documentation/api/pdf/pdfbordereffect) class. + +The following code example demonstrates how to apply a cloud border style to an existing free text annotation in a PDF document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBorderEffect, PdfBorderEffectStyle, PdfDocument, PdfFreeTextAnnotation, PdfPage } 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 free text annotation of the page +let annotation: PdfFreeTextAnnotation = page.annotations.at(0) as PdfFreeTextAnnotation; +// 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// 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 free text 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; +// Generate the annotation appearance +annotation.setAppearance(true); +// 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/DigitalSignature.md b/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md index 5796f43144..d82e34b6bf 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md +++ b/Document-Processing/PDF/PDF-Library/javascript/DigitalSignature.md @@ -422,6 +422,440 @@ 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. + +### 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 your public certificate chain. The following code example shows how to complete the external signing process 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. + +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, + PdfSignatureOptions, + 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 page to the document +let page: PdfPage = document.addPage(); +// Create a signature field +let field: PdfSignatureField = new PdfSignatureField( + page, + 'field', + { 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 existing signature field +field = document.form.fieldAt(0) as PdfSignatureField; +// Get the existing signature +signature = field.getSignature(); +// Get the signature options +let options: PdfSignatureOptions = signature.getSignatureOptions(); + +// 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 +); +if (ltvEnabled) { + // 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 page to the document +var page = document.addPage(); +// Create a signature field +var field = new ej.pdf.PdfSignatureField( + page, + 'field', + { 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 existing signature field +field = document.form.fieldAt(0); +// Get the existing signature +signature = field.getSignature(); +// Get the signature options +var options = signature.getSignatureOptions(); + +// 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 +); +if (ltvEnabled) { + // Save the LTV-enabled PDF document + document.save('output.pdf'); +} +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> An empty `Uint8Array` is only a placeholder. The callback must return the actual OCSP or CRL response received from the supplied revocation service URL. + +### Enable Long Term Validation (LTV) PDF signature + +The JavaScript PDF Library supports creating long-term signature validation for a signed PDF document. LTV allows a signature to be validated long after the document was signed by embedding the required certificate and revocation information in the PDF document. + +N> The resulting PDF document can be larger because the certificate chain, Certificate Revocation List (CRL), Online Certificate Status Protocol (OCSP) responses, and related validation information can be embedded in the Document Security Store (DSS). + +The following code example explains how to enable LTV for an existing signature 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, + PdfForm, + PdfSignatureField, + PdfSignature +} from '@syncfusion/ej2-pdf'; + +// Load the existing signed PDF document +let document: PdfDocument = new PdfDocument(data); +// Access the PDF form +let form: PdfForm = document.form; +// Get the existing signature field +let field: PdfSignatureField = form.fieldAt(0) as PdfSignatureField; +// Get the existing signature +let signature: PdfSignature = field.getSignature(); + +// 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 existing signature +let ltvEnabled: boolean = await signature.enableLTV(longTermValidationCallback); +if (ltvEnabled) { + // Save the LTV-enabled PDF document + document.save('output.pdf'); +} +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the existing signed PDF document +var document = new ej.pdf.PdfDocument(data); +// Access the PDF form +var form = document.form; +// Get the existing signature field +var field = form.fieldAt(0); +// Get the existing signature +var signature = field.getSignature(); + +// 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 existing signature +var ltvEnabled = await signature.enableLTV(longTermValidationCallback); +if (ltvEnabled) { + // Save the LTV-enabled PDF document + document.save('output.pdf'); +} +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> Enable LTV only after the target signature has been created or loaded from the PDF document. + +N> 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, select the revocation mode, and specify whether the certificates must be included in the PDF document while enabling LTV. + +The following code example uses CRL-based revocation information and includes the supplied public certificates in the document. +{% 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 and 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 page to the document +let page: PdfPage = document.addPage(); +// Create a signature field +let field: PdfSignatureField = new PdfSignatureField( + page, + 'field', + { 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.sha1, + 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 existing signature field +field = document.form.fieldAt(0) as PdfSignatureField; +// Get the existing signature +signature = field.getSignature(); + +// 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 +); +if (ltvEnabled) { + // 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 and 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 page to the document +var page = document.addPage(); +// Create a signature field +var field = new ej.pdf.PdfSignatureField( + page, + 'field', + { 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.sha1, + 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 existing signature field +field = document.form.fieldAt(0); +// Get the existing signature +signature = field.getSignature(); + +// 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 +); +if (ltvEnabled) { + // Save the LTV-enabled PDF document + document.save('output.pdf'); +} +// Destroy the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> Network communication, authentication, request headers, proxy configuration, and cross-origin access must be handled by the application that implements the callback. + +N> Invalid, empty, or unrelated response bytes may prevent the library from creating valid LTV information. + ## Signature options The following examples demonstrate the signature-creation options available in `PdfSignatureOptions`. 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..337ba90949 --- /dev/null +++ b/Document-Processing/PDF/PDF-Library/javascript/Encryption.md @@ -0,0 +1,480 @@ +--- +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) +- Advanced Encryption Standard (AES) + +## Working with RC4 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. +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. +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 + +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 security using an owner password. +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 security using an owner password. +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 + +The JavaScript PDF Library supports decrypting an encrypted PDF document by removing its owner or user password and restoring all supported permissions. This is particularly useful when you need to access or modify a secured PDF. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfPermissionFlag, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Open the 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.print | + PdfPermissionFlag.copyContent | + PdfPermissionFlag.editContent | + PdfPermissionFlag.editAnnotations | + PdfPermissionFlag.fillFields | + PdfPermissionFlag.accessibilityCopyContent | + PdfPermissionFlag.assembleDocument | + PdfPermissionFlag.fullQualityPrint +}; +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 data. +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Clear the passwords and restore all supported permissions. +document.setSecurity({ + userPassword: '', + ownerPassword: '', + permissions: ej.pdf.PdfPermissionFlag.print | + ej.pdf.PdfPermissionFlag.copyContent | + ej.pdf.PdfPermissionFlag.editContent | + ej.pdf.PdfPermissionFlag.editAnnotations | + ej.pdf.PdfPermissionFlag.fillFields | + ej.pdf.PdfPermissionFlag.accessibilityCopyContent | + ej.pdf.PdfPermissionFlag.assembleDocument | + ej.pdf.PdfPermissionFlag.fullQualityPrint +}); +// 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 + +You can make the existing PDF document password protected by configuring the required encryption type and passwords, and saving the document. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfEncryptionType, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load the existing PDF document +const document: PdfDocument = new PdfDocument(inputData); +// Protect the document using AES encryption. +const options: PdfSecurityOptions = { + encryptionType: PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword256', + userPassword: 'userPassword256' +}; +document.setSecurity(options); +// Save the protected PDF document. +document.save('Output.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document. +const document = new ej.pdf.PdfDocument(inputData); +// Protect the document using AES encryption. +document.setSecurity({ + encryptionType: ej.pdf.PdfEncryptionType.aesBit256Rev5, + ownerPassword: 'ownerPassword256', + userPassword: 'userPassword256' +}); +// Save the protected PDF document. +document.save('Output.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Changing the password of a PDF document + +You can change the user password of an existing encrypted PDF document by loading it with the current password and applying the new password through `setSecurity`. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load the password-protected PDF document. +const document: PdfDocument = new PdfDocument(inputData, 'password'); +// Change the user password. +const options: PdfSecurityOptions = { + userPassword: 'NewPassword' +}; +document.setSecurity(options); +// Save the password-changed PDF document. +document.save('Output.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the password-protected PDF document. +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Change the user password. +document.setSecurity({ + userPassword: 'NewPassword' +}); +// Save the password-changed PDF document. +document.save('Output.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## View document permission flags + +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. +const document: PdfDocument = new PdfDocument(inputData, 'password'); +// Get the document permission flags. +const permissions: PdfPermissionFlag = document.permissions; +// Check the required permission flags. +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; +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the secured PDF document. +const document = new ej.pdf.PdfDocument(inputData, 'password'); +// Get the document permission flags. +const permissions = document.permissions; +// Check the required permission flags. +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; +// Destroy the document and release its 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 + +You can change the permissions of an existing secured PDF document using the `permissions` property of `PdfSecurityOptions`. Load the document using a valid password before updating the permission flags. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfPermissionFlag, PdfSecurityOptions } from '@syncfusion/ej2-pdf'; + +// Load the secured PDF document. +const document: PdfDocument = new PdfDocument(inputData, 'syncfusion'); +// Allow content copying and document assembly. +const options: PdfSecurityOptions = { + permissions: PdfPermissionFlag.copyContent | + PdfPermissionFlag.assembleDocument +}; +document.setSecurity(options); +// Save the PDF document with the updated permissions. +document.save('Output.pdf'); +// Destroy the document and release its resources. +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the secured PDF document. +const document = new ej.pdf.PdfDocument(inputData, 'syncfusion'); +// Allow content copying and document assembly. +document.setSecurity({ + permissions: ej.pdf.PdfPermissionFlag.copyContent | + ej.pdf.PdfPermissionFlag.assembleDocument +}); +// Save the PDF document with the updated permissions. +document.save('Output.pdf'); +// Destroy the document and release its 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 handle the error raised for an encrypted document. Avoid depending on an exact error-message string because the message can change between versions. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument } from '@syncfusion/ej2-pdf'; + +// Load the PDF document data +let isPasswordProtected: boolean = false; +try { + // Loading without a password fails when a valid password is required. + let document = new PdfDocument(inputData); +} catch (error.message == 'Cannot open an encrypted document. The password is invalid.') { + isPasswordProtected = true; +} + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load the PDF document data. +let isPasswordProtected = false; +try { + // Loading without a password fails when a valid password is required. + let document = new ej.pdf.PdfDocument(inputData); +} catch (error.message == 'Cannot open an encrypted document. The password is invalid.') { + isPasswordProtected = true; +} + +{% 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. | + +## 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..73274e2ead 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Lists.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Lists.md @@ -147,6 +147,89 @@ 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/PdfGrid.md b/Document-Processing/PDF/PDF-Library/javascript/PdfGrid.md new file mode 100644 index 0000000000..1a9941b0e7 --- /dev/null +++ b/Document-Processing/PDF/PDF-Library/javascript/PdfGrid.md @@ -0,0 +1,928 @@ +--- +title: PdfGrid Tables in JavaScript PDF | Syncfusion +canonical_url: https://www.syncfusion.com/document-sdk/javascript-pdf-library +description: Create and customize PDF tables programmatically using PdfGrid in the Syncfusion JavaScript PDF Library. +platform: document-processing +control: PDF +documentation: UG +--- + +# PdfGrid Tables in JavaScript PDF + +The Syncfusion JavaScript PDF Library supports creating PDF tables from arrays of records or explicitly defined rows and columns. The `PdfGrid` class supports headers, custom column widths, row and column spanning, styles, images, hyperlinks, built-in styles, and pagination. + +N> The TypeScript samples use the `@syncfusion/ej2-pdf` package. The JavaScript samples use the corresponding `ej.pdf` global namespace. + +## Create a table from a data source + +Create a `PdfGrid` from an array of records and an ordered collection of `PdfColumnInformation` mappings. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfColumnInformation, PdfDocument, PdfGrid, PdfGridLayoutResult, PdfPage } from '@syncfusion/ej2-pdf'; + +// Create a new PDF document +let document: PdfDocument = new PdfDocument(); +// Add a page +let page: PdfPage = document.addPage(); +// Create the data source +let dataSource: object[] = [ + { id: 'E01', name: 'Clay' }, + { id: 'E02', name: 'Thomas' } +]; +// Define the column mappings +let columns: PdfColumnInformation[] = [ + { field: 'id', headerText: 'Employee ID', width: 90 }, + { field: 'name', headerText: 'Employee Name', width: 140 } +]; +// Create and draw the grid +let grid: PdfGrid = new PdfGrid(dataSource, columns); +let result: PdfGridLayoutResult = grid.draw(page, { x: 10, y: 10 }); +// Save and close the document +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Create a new PDF document +var document = new ej.pdf.PdfDocument(); +// Add a page +var page = document.addPage(); +// Create the data source +var dataSource = [ + { id: 'E01', name: 'Clay' }, + { id: 'E02', name: 'Thomas' } +]; +// Define the column mappings +var columns = [ + { field: 'id', headerText: 'Employee ID', width: 90 }, + { field: 'name', headerText: 'Employee Name', width: 140 } +]; +// Create and draw the grid +var grid = new ej.pdf.PdfGrid(dataSource, columns); +var result = grid.draw(page, { x: 10, y: 10 }); +// Save and close the document +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Create a table without a data source + +Define the rows, optional headers, and a zero-based column-width map directly. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridRow, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let widths: Map = new Map([[0, 90], [1, 140], [2, 100]]); +let headers: PdfGridRow[] = [{ + cells: [{ value: 'Employee ID' }, { value: 'Employee Name' }, { value: 'Salary' }] +}]; +let rows: PdfGridRow[] = [{ + cells: [{ value: 'E01' }, { value: 'Clay' }, { value: '$10,000' }] +}]; +let grid: PdfGrid = new PdfGrid(3, widths, rows, headers); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var widths = new Map([[0, 90], [1, 140], [2, 100]]); +var headers = [{ + cells: [{ value: 'Employee ID' }, { value: 'Employee Name' }, { value: 'Salary' }] +}]; +var rows = [{ + cells: [{ value: 'E01' }, { value: 'Clay' }, { value: '$10,000' }] +}]; +var grid = new ej.pdf.PdfGrid(3, widths, rows, headers); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Add rows and headers + +Use `addHeader` and `addRow` to append rows after constructing an explicit grid. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let widths: Map = new Map([[0, 90], [1, 140]]); +let grid: PdfGrid = new PdfGrid(2, widths, []); +grid.addHeader({ cells: [{ value: 'ID' }, { value: 'Name' }] }); +grid.addRow({ cells: [{ value: 'E01' }, { value: 'Clay' }] }); +grid.addRow({ cells: [{ value: 'E02' }, { value: 'Thomas' }] }); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var widths = new Map([[0, 90], [1, 140]]); +var grid = new ej.pdf.PdfGrid(2, widths, []); +grid.addHeader({ cells: [{ value: 'ID' }, { value: 'Name' }] }); +grid.addRow({ cells: [{ value: 'E01' }, { value: 'Clay' }] }); +grid.addRow({ cells: [{ value: 'E02' }, { value: 'Thomas' }] }); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Create a table in an existing PDF document + +Load an existing document, access a page, and draw the grid on that page. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfColumnInformation, PdfDocument, PdfGrid, PdfPage } from '@syncfusion/ej2-pdf'; + +// Load an existing PDF document +let document: PdfDocument = new PdfDocument(data); +let page: PdfPage = document.getPage(0); +let source: object[] = [{ id: '1', name: 'Clay' }, { id: '2', name: 'Thomas' }]; +let columns: PdfColumnInformation[] = [ + { field: 'id', headerText: 'ID', width: 60 }, + { field: 'name', headerText: 'Name', width: 120 } +]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +// Load an existing PDF document +var document = new ej.pdf.PdfDocument(data); +var page = document.getPage(0); +var source = [{ id: '1', name: 'Clay' }, { id: '2', name: 'Thomas' }]; +var columns = [ + { field: 'id', headerText: 'ID', width: 60 }, + { field: 'name', headerText: 'Name', width: 120 } +]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Customize table cells + +Apply a background, border, padding, and text color to an individual cell. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBrush, PdfDocument, PdfGrid, PdfGridRow, PdfPage, PdfPen } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let widths: Map = new Map([[0, 100], [1, 140]]); +let rows: PdfGridRow[] = [{ + height: 40, + cells: [ + { + value: 'E01', + style: { + background: new PdfBrush({ r: 255, g: 255, b: 180 }), + border: new PdfPen({ r: 255, g: 0, b: 0 }, 1), + padding: { left: 8, right: 8, top: 6, bottom: 6 }, + textProperties: { color: new PdfBrush({ r: 0, g: 0, b: 180 }) } + } + }, + { value: 'Clay' } + ] +}]; +let grid: PdfGrid = new PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var widths = new Map([[0, 100], [1, 140]]); +var rows = [{ + height: 40, + cells: [ + { + value: 'E01', + style: { + background: new ej.pdf.PdfBrush({ r: 255, g: 255, b: 180 }), + border: new ej.pdf.PdfPen({ r: 255, g: 0, b: 0 }, 1), + padding: { left: 8, right: 8, top: 6, bottom: 6 }, + textProperties: { color: new ej.pdf.PdfBrush({ r: 0, g: 0, b: 180 }) } + } + }, + { value: 'Clay' } + ] +}]; +var grid = new ej.pdf.PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Customize rows and columns + +Set a row height and style, and configure column widths and text alignment. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBrush, PdfColumnInformation, PdfDocument, PdfFontFamily, PdfGrid, PdfPage, PdfStandardFont, PdfTemplateHorizontalAlignment, PdfTemplateVerticalAlignment } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'John' }, { id: 'E02', name: 'Thomas' }]; +let columns: PdfColumnInformation[] = [ + { + field: 'id', headerText: 'Employee ID', width: 80, + style: { textProperties: { + horizontalAlignment: PdfTemplateHorizontalAlignment.center, + verticalAlignment: PdfTemplateVerticalAlignment.middle + } } + }, + { field: 'name', headerText: 'Employee Name', width: 150 } +]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.rows[0].height = 50; +grid.rows[0].style = { + background: new PdfBrush({ r: 255, g: 255, b: 200 }), + textProperties: { + font: new PdfStandardFont(PdfFontFamily.courier, 10), + color: new PdfBrush({ r: 0, g: 0, b: 255 }) + } +}; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'John' }, { id: 'E02', name: 'Thomas' }]; +var columns = [ + { + field: 'id', headerText: 'Employee ID', width: 80, + style: { textProperties: { + horizontalAlignment: ej.pdf.PdfTemplateHorizontalAlignment.center, + verticalAlignment: ej.pdf.PdfTemplateVerticalAlignment.middle + } } + }, + { field: 'name', headerText: 'Employee Name', width: 150 } +]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.rows[0].height = 50; +grid.rows[0].style = { + background: new ej.pdf.PdfBrush({ r: 255, g: 255, b: 200 }), + textProperties: { + font: new ej.pdf.PdfStandardFont(ej.pdf.PdfFontFamily.courier, 10), + color: new ej.pdf.PdfBrush({ r: 0, g: 0, b: 255 }) + } +}; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Customize the whole table + +Use the grid-level `style` property to set padding, spacing, border, and text formatting. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfFontFamily, PdfGrid, PdfPage, PdfPen, PdfStandardFont } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.style = { + padding: { left: 4, right: 4, top: 3, bottom: 3 }, + space: { left: 1, right: 1, top: 1, bottom: 1 }, + border: new PdfPen({ r: 80, g: 80, b: 80 }, 0.5), + textProperties: { font: new PdfStandardFont(PdfFontFamily.helvetica, 9) } +}; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.style = { + padding: { left: 4, right: 4, top: 3, bottom: 3 }, + space: { left: 1, right: 1, top: 1, bottom: 1 }, + border: new ej.pdf.PdfPen({ r: 80, g: 80, b: 80 }, 0.5), + textProperties: { font: new ej.pdf.PdfStandardFont(ej.pdf.PdfFontFamily.helvetica, 9) } +}; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Apply a built-in table style + +Pass a `PdfGridBuiltinStyle` value to the constructor. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridBuiltinStyle, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let grid: PdfGrid = new PdfGrid(source, columns, undefined, PdfGridBuiltinStyle.gridTable4Accent1); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var grid = new ej.pdf.PdfGrid(source, columns, undefined, ej.pdf.PdfGridBuiltinStyle.gridTable4Accent1); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Paginate a table + +Use `PdfLayoutFormat` to flow table rows across pages and repeat the header on continuation pages. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridLayoutResult, PdfLayoutBreakType, PdfLayoutFormat, PdfLayoutType, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = []; +for (let i: number = 1; i <= 100; i++) { + source.push({ id: 'E' + i, name: 'Employee ' + i }); +} +let columns = [{ field: 'id', headerText: 'ID', width: 80 }, { field: 'name', headerText: 'Name', width: 160 }]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.repeatHeader = true; +let format: PdfLayoutFormat = new PdfLayoutFormat(); +format.layout = PdfLayoutType.paginate; +format.break = PdfLayoutBreakType.fitPage; +let result: PdfGridLayoutResult = grid.draw(page, { x: 10, y: 10, width: 300, height: 500 }, format); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = []; +for (var i = 1; i <= 100; i++) { + source.push({ id: 'E' + i, name: 'Employee ' + i }); +} +var columns = [{ field: 'id', headerText: 'ID', width: 80 }, { field: 'name', headerText: 'Name', width: 160 }]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.repeatHeader = true; +var format = new ej.pdf.PdfLayoutFormat(); +format.layout = ej.pdf.PdfLayoutType.paginate; +format.break = ej.pdf.PdfLayoutBreakType.fitPage; +var result = grid.draw(page, { x: 10, y: 10, width: 300, height: 500 }, format); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Prevent row breaks across pages + +Use `PdfLayoutBreakType.fitElement` to keep each row together. If a row does not fit in the remaining space, the complete row moves to the next page. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfLayoutBreakType, PdfLayoutFormat, PdfLayoutType, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = []; +for (let i: number = 1; i <= 80; i++) { + source.push({ id: 'E' + i, description: 'Complete row content for employee ' + i }); +} +let columns = [ + { field: 'id', headerText: 'ID', width: 60 }, + { field: 'description', headerText: 'Description', width: 240 } +]; +let grid: PdfGrid = new PdfGrid(source, columns); +let format: PdfLayoutFormat = new PdfLayoutFormat(); +format.layout = PdfLayoutType.paginate; +format.break = PdfLayoutBreakType.fitElement; +grid.draw(page, { x: 10, y: 10, width: 320, height: 500 }, format); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = []; +for (var i = 1; i <= 80; i++) { + source.push({ id: 'E' + i, description: 'Complete row content for employee ' + i }); +} +var columns = [ + { field: 'id', headerText: 'ID', width: 60 }, + { field: 'description', headerText: 'Description', width: 240 } +]; +var grid = new ej.pdf.PdfGrid(source, columns); +var format = new ej.pdf.PdfLayoutFormat(); +format.layout = ej.pdf.PdfLayoutType.paginate; +format.break = ej.pdf.PdfLayoutBreakType.fitElement; +grid.draw(page, { x: 10, y: 10, width: 320, height: 500 }, format); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +N> The .NET `PaginateBounds` API used to change continuation-page margins is not available in the current JavaScript `PdfGrid` implementation. Therefore, a JavaScript sample for changing margins from the second page onwards is not included. +## Add multiple tables + +Use the page and occupied bounds returned by the first grid to position the second grid without overlap. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridLayoutResult, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let firstGrid: PdfGrid = new PdfGrid([{ id: 'E01', name: 'Clay' }], columns); +let firstResult: PdfGridLayoutResult = firstGrid.draw(page, { x: 10, y: 10 }); +let secondGrid: PdfGrid = new PdfGrid([{ id: 'E02', name: 'Thomas' }], columns); +let secondY: number = firstResult.bounds.y + firstResult.bounds.height + 20; +secondGrid.draw(firstResult.page, { x: 10, y: secondY }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var firstGrid = new ej.pdf.PdfGrid([{ id: 'E01', name: 'Clay' }], columns); +var firstResult = firstGrid.draw(page, { x: 10, y: 10 }); +var secondGrid = new ej.pdf.PdfGrid([{ id: 'E02', name: 'Thomas' }], columns); +var secondY = firstResult.bounds.y + firstResult.bounds.height + 20; +secondGrid.draw(firstResult.page, { x: 10, y: secondY }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Apply text formatting + +Apply font, color, and alignment through `textProperties`. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBrush, PdfDocument, PdfFontFamily, PdfGrid, PdfPage, PdfStandardFont, PdfTemplateHorizontalAlignment, PdfTemplateVerticalAlignment } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.style = { textProperties: { + font: new PdfStandardFont(PdfFontFamily.helvetica, 10), + color: new PdfBrush({ r: 0, g: 0, b: 120 }), + horizontalAlignment: PdfTemplateHorizontalAlignment.center, + verticalAlignment: PdfTemplateVerticalAlignment.middle +} }; +grid.draw(page, { x: 10, y: 10, width: 280, height: 200 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.style = { textProperties: { + font: new ej.pdf.PdfStandardFont(ej.pdf.PdfFontFamily.helvetica, 10), + color: new ej.pdf.PdfBrush({ r: 0, g: 0, b: 120 }), + horizontalAlignment: ej.pdf.PdfTemplateHorizontalAlignment.center, + verticalAlignment: ej.pdf.PdfTemplateVerticalAlignment.middle +} }; +grid.draw(page, { x: 10, y: 10, width: 280, height: 200 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Apply row and column spanning + +Set `rowSpan` and `columnSpan` in a cell style. Span regions cannot overlap or extend beyond the grid. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridRow, PdfPage, PdfTemplateHorizontalAlignment } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let widths: Map = new Map([[0, 100], [1, 140]]); +let rows: PdfGridRow[] = [ + { cells: [ + { value: 'Employee Details', style: { columnSpan: 2, textProperties: { horizontalAlignment: PdfTemplateHorizontalAlignment.center } } } + ] }, + { cells: [ + { value: 'E01', style: { rowSpan: 2 } }, { value: 'Clay' } + ] }, + { cells: [{ value: 'Thomas' }] } +]; +let grid: PdfGrid = new PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var widths = new Map([[0, 100], [1, 140]]); +var rows = [ + { cells: [ + { value: 'Employee Details', style: { columnSpan: 2, textProperties: { horizontalAlignment: ej.pdf.PdfTemplateHorizontalAlignment.center } } } + ] }, + { cells: [ + { value: 'E01', style: { rowSpan: 2 } }, { value: 'Clay' } + ] }, + { cells: [{ value: 'Thomas' }] } +]; +var grid = new ej.pdf.PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Insert an image in a table cell + +Assign a `PdfBitmap` as the cell value and configure its size, fit mode, and alignment. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBitmap, PdfDocument, PdfGrid, PdfGridRow, PdfPage, PdfTemplateHorizontalAlignment, PdfTemplateVerticalAlignment } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let image: PdfBitmap = new PdfBitmap(imageData); +let widths: Map = new Map([[0, 60], [1, 120]]); +let rows: PdfGridRow[] = [{ + height: 80, + cells: [ + { value: '1' }, + { value: image, style: { imageProperties: { + width: 60, height: 60, fitType: 2, + horizontalAlignment: PdfTemplateHorizontalAlignment.center, + verticalAlignment: PdfTemplateVerticalAlignment.middle + } } } + ] +}]; +let grid: PdfGrid = new PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var image = new ej.pdf.PdfBitmap(imageData); +var widths = new Map([[0, 60], [1, 120]]); +var rows = [{ + height: 80, + cells: [ + { value: '1' }, + { value: image, style: { imageProperties: { + width: 60, height: 60, fitType: 2, + horizontalAlignment: ej.pdf.PdfTemplateHorizontalAlignment.center, + verticalAlignment: ej.pdf.PdfTemplateVerticalAlignment.middle + } } } + ] +}]; +var grid = new ej.pdf.PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Add a background image to a table cell + +Set `backgroundImage` in the cell style. A `fitType` value of `3` stretches the background image to fill the content area. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfBitmap, PdfDocument, PdfGrid, PdfGridRow, PdfPage, PdfTemplateHorizontalAlignment, PdfTemplateVerticalAlignment } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let image: PdfBitmap = new PdfBitmap(imageData); +let widths: Map = new Map([[0, 140], [1, 100]]); +let rows: PdfGridRow[] = [{ + height: 70, + cells: [ + { value: 'Employee ID', style: { backgroundImage: { + image: image, + imageProperties: { + fitType: 3, + horizontalAlignment: PdfTemplateHorizontalAlignment.center, + verticalAlignment: PdfTemplateVerticalAlignment.middle + } + } } }, + { value: 'E01' } + ] +}]; +let grid: PdfGrid = new PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var image = new ej.pdf.PdfBitmap(imageData); +var widths = new Map([[0, 140], [1, 100]]); +var rows = [{ + height: 70, + cells: [ + { value: 'Employee ID', style: { backgroundImage: { + image: image, + imageProperties: { + fitType: 3, + horizontalAlignment: ej.pdf.PdfTemplateHorizontalAlignment.center, + verticalAlignment: ej.pdf.PdfTemplateVerticalAlignment.middle + } + } } }, + { value: 'E01' } + ] +}]; +var grid = new ej.pdf.PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Add hyperlinks + +A string beginning with `http://` or `https://` creates a URI annotation during page-based drawing. An explicit `PdfLink` can also be assigned. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridRow, PdfLinkType, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let widths: Map = new Map([[0, 130], [1, 180]]); +let rows: PdfGridRow[] = [ + { cells: [{ value: 'Product page' }, { value: 'https://www.syncfusion.com' }] }, + { cells: [{ value: 'Report' }, { value: 'Open file', link: { type: PdfLinkType.file, uri: 'Report.pdf' } }] } +]; +let grid: PdfGrid = new PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var widths = new Map([[0, 130], [1, 180]]); +var rows = [ + { cells: [{ value: 'Product page' }, { value: 'https://www.syncfusion.com' }] }, + { cells: [{ value: 'Report' }, { value: 'Open file', link: { type: ej.pdf.PdfLinkType.file, uri: 'Report.pdf' } }] } +]; +var grid = new ej.pdf.PdfGrid(2, widths, rows); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Draw a borderless table + +Use a zero-width border at grid level. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfGridStyle, PdfPage, PdfPen } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let style: PdfGridStyle = { border: new PdfPen({ r: 255, g: 255, b: 255 }, 0) }; +let grid: PdfGrid = new PdfGrid(source, columns, style); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var style = { border: new ej.pdf.PdfPen({ r: 255, g: 255, b: 255 }, 0) }; +var grid = new ej.pdf.PdfGrid(source, columns, style); +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Update the grid data source + +Reassign `dataSource` on a data-source grid. Generated rows are rebuilt, while manually added rows remain after them. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let grid: PdfGrid = new PdfGrid([{ id: 'E01', name: 'Clay' }], columns); +grid.addRow({ cells: [{ value: 'Manual' }, { value: 'Record' }] }); +grid.dataSource = [{ id: 'E10', name: 'Andrew' }, { id: 'E11', name: 'Michael' }]; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var grid = new ej.pdf.PdfGrid([{ id: 'E01', name: 'Clay' }], columns); +grid.addRow({ cells: [{ value: 'Manual' }, { value: 'Record' }] }); +grid.dataSource = [{ id: 'E10', name: 'Andrew' }, { id: 'E11', name: 'Michael' }]; +grid.draw(page, { x: 10, y: 10 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Draw by using a graphics context + +The graphics overload does not paginate. The complete grid must fit within the supplied bounds. + + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} + +import { PdfDocument, PdfGrid, PdfPage } from '@syncfusion/ej2-pdf'; + +let document: PdfDocument = new PdfDocument(); +let page: PdfPage = document.addPage(); +let source: object[] = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +let columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +let grid: PdfGrid = new PdfGrid(source, columns); +grid.draw(page.graphics, { x: 10, y: 10, width: 300, height: 200 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% highlight javascript tabtitle="JavaScript" %} + +var document = new ej.pdf.PdfDocument(); +var page = document.addPage(); +var source = [{ id: 'E01', name: 'Clay' }, { id: 'E02', name: 'Thomas' }]; +var columns = [{ field: 'id', headerText: 'ID' }, { field: 'name', headerText: 'Name' }]; +var grid = new ej.pdf.PdfGrid(source, columns); +grid.draw(page.graphics, { x: 10, y: 10, width: 300, height: 200 }); +document.save('Output.pdf'); +document.destroy(); + +{% endhighlight %} +{% endtabs %} + + +## JavaScript and .NET feature differences + +The following .NET PdfGrid APIs are not present in the supplied JavaScript implementation: + +- Nested `PdfGrid` objects as cell values +- `BeginCellLayout` and `BeginPageLayout` events +- Event-based table rotation +- `PdfGridBuiltinStyleSettings` +- `AllowHorizontalOverflow` +- `PaginateBounds` +- Per-side border collections such as `Borders.All` +- Direct annotation objects as cell values +- `PdfWordWrapType` and character-spacing formatting + +## 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.html) +- [JavaScript PDF examples on GitHub](https://github.com/SyncfusionExamples/javascript-pdf-examples) diff --git a/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md b/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md index 666aaf3ca5..5eb3114ce3 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Text-Extraction.md @@ -18,9 +18,9 @@ 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. +This 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 and the `extractTextSync` method. Basic text extraction retrieves text content from the entire PDF document immediately. {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -32,8 +32,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 +46,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 +56,113 @@ document.destroy(); {% endhighlight %} {% endtabs %} -## Extract text from specific page range in a PDF document +## Working with basic text extraction asynchronously -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. +This example demonstrates how to extract plain text from a PDF document asynchronously using the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class and the `extractText` method. Basic text extraction retrieves text content from the entire 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); +// Extract text content from the PDF document asynchronously. +let text: string = await extractor.extractText(); +// Save the document +document.save('Output.pdf'); +// Close the document +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); +// Extract text content from the PDF document asynchronously +var text = await extractor.extractText(); +// Save the document +document.save('Output.pdf'); +// Close the document +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Extract text from a specific page range in a PDF document synchronously + +This example demonstrates how to synchronously 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. + +{% 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); +// 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(); + +{% 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); +// 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 %} + +## Extract text from a specific page range in a PDF document asynchronously + +This example demonstrates how to asynchronously 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. + +{% 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); +// Extract text content from the specified page range asynchronously +let text: string = await extractor.extractText({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// 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); +// Extract text content from the specified page range asynchronously +var text = await extractor.extractText({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Release document resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +## Working with layout-based text extraction synchronously + +This example demonstrates how to extract text from a PDF document synchronously 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. {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -69,8 +173,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 from the PDF page based on its layout synchronously +let text: string = extractor.extractTextSync({ isLayout: true }); // Release document resources document.destroy(); @@ -81,17 +185,17 @@ 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 from the PDF page based on its layout synchronously +var text = extractor.extractTextSync({ isLayout: true }); // Release document resources document.destroy(); {% endhighlight %} {% endtabs %} -## Working with layout-based text extraction +## Working with layout-based text extraction asynchronously -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. +This example demonstrates how to extract text from a PDF document asynchronously 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. {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -102,8 +206,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 asynchronously +let text: string = await extractor.extractText({ isLayout: true }); // Release document resources document.destroy(); @@ -114,8 +218,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 from the PDF page based on its layout -var text = extractor.extractText({ isLayout: true }); +// Extract text from the PDF page based on its layout asynchronously +var text = await extractor.extractText({ isLayout: true }); // Release document resources document.destroy(); @@ -126,11 +230,11 @@ N> Layout-based text extraction may take additional processing time when compare ## 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. +The following sections describe how to extract text along with positional and typographic information using 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. 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. -### Working with lines +### Working with lines synchronously -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. +This example demonstrates how to extract text from a PDF page based on individual lines. 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, allowing precise access to text content line by line. {% tabs %} {% highlight typescript tabtitle="TypeScript" %} @@ -141,8 +245,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 +274,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,7 +299,139 @@ document.destroy(); {% endhighlight %} {% endtabs %} -### Working with words +### Working with lines asynchronously + +This example demonstrates how to extract text from a PDF page based on individual lines asynchronously. 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. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument } from '@syncfusion/ej2-pdf'; +import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle, 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); +// Extract `TextLine` objects from the PDF document asynchronously +let textLines: Array = await extractor.extractTextLines({ 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 + let lineBounds: Rectangle = textLine.bounds; + // Gets the single line of extracted text from the PDF page + let line: string = textLine.text; + // Gets the page index of the text line extracted + let pageIndex: number = textLine.pageIndex; + // Gets the collection of text words extracted from a specified page in a PDF document + let words: TextWord[] = textLine.words; + // Gets the name of the font used for a particular line of text + let fontName: string = textLine.fontName; + // Gets the font style used for a particular line of text + let fontStyle: PdfFontStyle = textLine.fontStyle; + // Gets the font size used for a particular line of text + let fontSize: number = textLine.fontSize; +}); +// 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); +// Extract `TextLine` objects from the PDF document asynchronously +var textLines = await extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); +// Iterate through each text line in the collection +textLines.forEach((textLine) => { + // Gets the bounds of the text line + var lineBounds = textLine.bounds; + // Gets the single line of extracted text from the PDF page + var line = textLine.text; + // Gets the page index of the text line extracted + var pageIndex = textLine.pageIndex; + // Gets the collection of text words extracted from a specified page in a PDF document + var words = textLine.words; + // Gets the name of the font used for a particular line of text + var fontName = textLine.fontName; + // Gets the font style used for a particular line of text + var fontStyle = textLine.fontStyle; + // Gets the font size used for a particular line of text + var fontSize = textLine.fontSize; +}); +// Release document resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +### Working with words synchronously + +This example demonstrates how to extract words from a PDF document using the [extractTextLinesSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlinessync) method. Each line contains a collection of [TextWord](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/textword) objects. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument } from '@syncfusion/ej2-pdf'; +import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle, 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); +// 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 + let wordBounds: Rectangle = textWord.bounds; + // Gets the single word of extracted text from the PDF page + let word: string = textWord.text; + // Gets the collection of text glyphs extracted from a specified page in a PDF document + let glyphs: TextGlyph[] = textWord.glyphs; + // Gets the name of the font used for a particular word + let wordFontName: string = textWord.fontName; + // Gets the style of the font used for a particular word + let wordFontStyle: PdfFontStyle = textWord.fontStyle; + // Gets the size of the font used for a particular word + let wordFontSize: number = textWord.fontSize; + }); +}); +// 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); +// 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 + var wordBounds = textWord.bounds; + // Gets the single word of extracted text from the PDF page + var word = textWord.text; + // Gets the collection of text glyphs extracted from a specified page in a PDF document + var glyphs = textWord.glyphs; + // Gets the name of the font used for a particular word + var wordFontName = textWord.fontName; + // Gets the style of the font used for a particular word + var wordFontStyle = textWord.fontStyle; + // Gets the size of the font used for a particular word + var wordFontSize = textWord.fontSize; + }); +}); +// Release document resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +### Working with words asynchronously 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. @@ -208,8 +444,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 asynchronously +let textLines: Array = await extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine: TextLine) => { textLine.words.forEach((textWord: TextWord) => { // Gets the bounds of the text word @@ -236,8 +472,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 asynchronously +var textLines = await extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine) => { textLine.words.forEach((textWord) => { // Gets the bounds of the text word @@ -260,7 +496,80 @@ document.destroy(); {% endhighlight %} {% endtabs %} -### Working with characters +### Working with characters synchronously + +You can retrieve a single character and its properties, including bounds, font name, font size, and text color, using the [extractTextLinesSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#extracttextlinessync) method. Refer to the code sample below. + +{% tabs %} +{% highlight typescript tabtitle="TypeScript" %} +import { PdfDocument, PdfColor, Rectangle } from '@syncfusion/ej2-pdf'; +import { PdfDataExtractor, TextLine, TextWord, TextGlyph, PdfFontStyle } 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); +// 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) => { + // Gets the bounds of the text glyph + let glyphBounds: Rectangle = textGlyph.bounds; + // Gets the single character of extracted text from the PDF page + let character: string = textGlyph.text; + // Gets the font size used for a particular character of the text + let fontSize: number = textGlyph.fontSize; + // Gets the name of the font used for a particular character of the text + let fontName: string = textGlyph.fontName; + // Gets the font style used for a particular character of the text + let fontStyle: PdfFontStyle = textGlyph.fontStyle; + // Gets the text color of the text glyph + let color: PdfColor = textGlyph.color; + // Gets the value indicating whether the glyph is rotated or not + let isRotated: boolean = textGlyph.isRotated; + }); + }); +}); +// 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); +// 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) => { + // Gets the bounds of the text glyph + var glyphBounds = textGlyph.bounds; + // Gets the single character of extracted text from the PDF page + var character = textGlyph.text; + // Gets the font size used for a particular character of the text + var fontSize = textGlyph.fontSize; + // Gets the name of the font used for a particular character of the text + var fontName = textGlyph.fontName; + // Gets the font style used for a particular character of the text + var fontStyle = textGlyph.fontStyle; + // Gets the text color of the text glyph + var color = textGlyph.color; + // Gets the value indicating whether the glyph is rotated or not + var isRotated = textGlyph.isRotated; + }); + }); +}); +// Release document resources +document.destroy(); + +{% endhighlight %} +{% endtabs %} + +### Working with characters asynchronously 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. @@ -273,8 +582,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 asynchronously +let textLines: Array = await extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine: TextLine) => { textLine.words.forEach((textWord: TextWord) => { textWord.glyphs.forEach((textGlyph: TextGlyph) => { @@ -305,8 +614,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 asynchronously +var textLines = await extractor.extractTextLines({ startPageIndex: 0, endPageIndex: document.pageCount - 1 }); textLines.forEach((textLine) => { textLine.words.forEach((textWord) => { textWord.glyphs.forEach((textGlyph) => { @@ -333,6 +642,102 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Find Text + +The [findText](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtext) method of the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class locates specific text in a PDF document. The method returns the page index and rectangular bounds of each matching text occurrence. 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 in a PDF document using the `findText` method. + +{% 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 +let searchResults = await extractor.findText('document'); +// 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 +var searchResults = await extractor.findText('document'); +// Release document resources +document.destroy(); + +{% endhighlight %} + +{% endtabs %} + +N> The page index returned in a text search result is zero-based. + +N> The `findText` method searches the text content available in the PDF document. It does not perform optical character recognition on scanned or image-only PDF pages. + +N> Searching a large PDF document may require additional processing time depending on the number of pages and matching text occurrences. + +### Find text synchronously + +The [findTextSync](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtextsync) method searches for text and returns the matching occurrences synchronously. + +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('document'); +// 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('document'); +// Release document resources +document.destroy(); + +{% 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. + +## 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)`](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtext) | 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)`](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtext) | Promise | Searches for the specified text asynchronously using the supplied text-search options and returns the matching occurrences. | +| [`findTextSync(text: string)`](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtextsync) | 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)`](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtextsync) | Text search result collection | Searches for the specified text synchronously using the supplied text-search options and returns the matching occurrences. | ## Additional Resources - [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript-pdf-library) diff --git a/Document-Processing/PDF/PDF-Library/javascript/Text.md b/Document-Processing/PDF/PDF-Library/javascript/Text.md index 1d78778541..c63d138dbd 100644 --- a/Document-Processing/PDF/PDF-Library/javascript/Text.md +++ b/Document-Processing/PDF/PDF-Library/javascript/Text.md @@ -583,6 +583,47 @@ document.destroy(); {% endhighlight %} {% endtabs %} +## Search and get the bounds of text in a PDF document + +You can search for specific text in a PDF document and retrieve the location of every occurrence using the [findText](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor#findtext) method of the [PdfDataExtractor](https://ej2.syncfusion.com/documentation/api/pdf-data-extract/pdfdataextractor) class. + +The `findText` method searches the PDF document for the specified text and returns the matching text occurrences along with their page index and bounding rectangles. The returned bounds can be used for operations such as highlighting, redaction, annotation, and document navigation. + +The following code example demonstrates how to search for text 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 } 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 all matching occurrences +let textSearch = extractor.findText('hello'); +// 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 all matching occurrences +var textSearch = extractor.findText('hello'); +// Release document resources +document.destroy(); + +{% endhighlight %} + +{% endtabs %} + ## Additional Resources - [JavaScript PDF Library](https://www.syncfusion.com/document-sdk/javascript-pdf-library)