BoxLang 🚀 A New JVM Dynamic Language Learn More...

BoxLang PDF Module

v1.6.3+6 BoxLang Modules

⚡︎ BoxLang+ Module: BoxLang PDF Module

|:------------------------------------------------------:  |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive
|:------------------------------------------------------:  |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com

Overview

This module provides comprehensive PDF manipulation and generation functionality for BoxLang, including:

  • PDF Document Generation - Create PDF documents from HTML content
  • PDF Form Manipulation - Populate and extract data from PDF forms
  • PDF Document Processing - Advanced PDF operations like merging, splitting, watermarking
  • CFML Compatibility - Full compatibility with CFML PDF tags

Installation

{% hint style="danger" %} This module is only available to +/++ subscribers only but can be installed in conjunction with the bx-plus Module with a limited trial. {% endhint %}

# For Operating Systems using our Quick Installer
install-bx-module bx-pdf

# Using CommandBox to install for web servers
box install bx-pdf

Components

This module contributes the following components to the BoxLang runtime:

Document Generation Components

  • document - Main component for creating PDF documents from HTML
  • documentitem - Specifies headers, footers, and page breaks
  • documentsection - Divides documents into sections with unique properties

PDF Manipulation Components

  • pdf - Advanced PDF operations (merge, split, watermark, etc.)
  • pdfparam - Parameters for PDF operations like attachments

PDF Form Components

  • pdfform - Manipulate PDF forms (populate/read form fields)
  • pdfformparam - Specify individual form field values

Document Component

The document component creates PDF documents from HTML content with extensive customization options.

When rendering remote HTTP/HTTPS images, the module uses bounded connect/read timeouts so unavailable endpoints fail instead of hanging PDF generation.

Attributes

Attribute Type Default Description
format String"pdf"Document format (PDF only)
filename String-Output file path
variable String-Variable name to store PDF binary
encryption String"none"Encryption level: "128-bit", "40-bit", "none"
orientation String"portrait"Page orientation: "portrait", "landscape"
pageType String"A4"Page size (A4, LETTER, LEGAL, etc.)
pageWidth Numeric-Custom page width in inches
pageHeight Numeric-Custom page height in inches
marginTop Numeric-Top margin
marginBottom Numeric-Bottom margin
marginLeft Numeric-Left margin
marginRight Numeric-Right margin
scale Numeric100Scaling percentage (≤100)
backgroundVisible BooleantrueShow background elements
bookmark BooleantrueGenerate bookmarks
htmlBookmark BooleanfalseConvert HTML anchors to bookmarks
fontEmbed BooleantrueEmbed fonts in document
fontDirectory String-Custom font directory
localUrl BooleanfalseAllow local file URLs/paths in HTML assets (supports Windows paths, file:/// URIs, and relative paths)
openpassword String-Password to open document
ownerPassword String-Owner password for restrictions
pdfa BooleanfalseGenerate PDF/A compliant document
saveAsName String-Browser save filename
overwrite BooleanfalseOverwrite existing files
src String-URL or path to HTML content
srcfile String-Absolute path to HTML file
mimeType String"text/html"Source content MIME type
unit String"inches"Measurement unit: "in", "cm"

Unsupported Attributes

The following attributes are not currently implemented and will throw an error if used:

  • permissions - Granular permissibility is not yet supported
  • permissionspassword - Granular permissibility is not yet supported
  • userPassword - Granular permissibility is not yet supported
  • authPassword - Authentication password not supported
  • authUser - Authentication user not supported
  • userAgent - HTTP user agent identifier not supported
  • proxyHost - Proxy server configuration not supported
  • proxyPassword - Proxy authentication not supported
  • proxyPort - Proxy port configuration not supported
  • proxyUser - Proxy user authentication not supported
  • tagged - ACF OpenOffice integration not supported
  • formfields - Form field attributes not implemented in standard module
  • formsType - Form type specification not implemented in standard module

DocumentItem Component

Specifies headers, footers, and page breaks within PDF documents.

Attributes

Attribute Type Required Description
type StringYesItem type: "header", "footer", "pagebreak"
evalAtPrint BooleanNo⚠️ Deprecated - content always evaluated

DocumentSection Component

Divides PDF documents into sections with unique headers, footers, and page numbering.

Attributes

Attribute Type Description
name StringSection name (used for bookmarks)
marginTop NumericSection top margin
marginBottom NumericSection bottom margin
marginLeft NumericSection left margin
marginRight NumericSection right margin
src StringURL or relative path to content
srcfile StringAbsolute path to content file
mimeType StringContent MIME type

Unsupported Attributes

The following attributes are not currently implemented and will throw an error if used:

  • userAgent - HTTP user agent identifier for URL fetching
  • authPassword - Authentication password for URL content
  • authUser - Authentication username for URL content

PDFForm Component

Manipulates PDF forms created in Adobe Acrobat and Adobe LiveCycle Designer. Supports both populating form fields and extracting form data.

Actions

  • populate - Fill form fields with data
  • read - Extract form field data to structures or files

Attributes

Attribute Type Required Description
action StringYes"populate" or "read"
source AnyYesSource PDF form (file path, byte array, or variable)
destination StringNoOutput file path (populate action)
result StringNoVariable name for extracted data (read action)
overwrite BooleanNoOverwrite existing files (default: false)
overwriteData BooleanNoOverwrite existing form data (default: false)
fdfdata StringNoFDF file path for import/export
XMLdata StringNo⏳ XML data (planned feature)

Examples

Populating Form Fields

<bx:pdfform action="populate" 
            source="/forms/employee-form.pdf" 
            destination="/completed/employee-123.pdf"
            overwrite="true">
    
    <bx:pdfformparam name="employeeId" value="EMP-123" />
    <bx:pdfformparam name="firstName" value="John" />
    <bx:pdfformparam name="lastName" value="Smith" />
    <bx:pdfformparam name="department" value="Engineering" />
    <bx:pdfformparam name="salary" value="$85,000" />
    <bx:pdfformparam name="startDate" value="2024-01-15" />
    
</bx:pdfform>

Reading Form Data

<bx:pdfform action="read" 
            source="/submitted/employee-form-filled.pdf" 
            result="employeeData" />

<!-- Access extracted data -->
<bx:output>
    Employee: #employeeData.firstName# #employeeData.lastName#<br>
    ID: #employeeData.employeeId#<br>
    Department: #employeeData.department#
</bx:output>

<bx:dump var="#employeeData#" />

FDF Data Operations

<!-- Export form data to FDF -->
<bx:pdfform action="read"
            source="/filled-forms/survey.pdf"
            fdfdata="/exported-data/survey-data.fdf" />

<!-- Import FDF data to populate form -->
<bx:pdfform action="populate"
            source="/templates/survey-template.pdf"
            destination="/completed/survey-filled.pdf"
            fdfdata="/data/survey-responses.fdf" />

PDFFormParam Component

Specifies individual form field values when populating PDF forms. Must be nested within a pdfform component.

Attributes

Attribute Type Required Description
name StringYesForm field name
value StringYesValue to assign to the field
index IntegerNoField index for LiveCycle forms (default: 1)

Usage Notes

  • Acrobat Forms: Cannot have multiple fields with the same name, so index is not applicable
  • LiveCycle Forms: Support multiple fields with the same name, use index to distinguish them
  • Case Sensitivity: Field values are case-sensitive
  • Data Types: Component handles various field types (text, checkbox, radio, dropdown, etc.)

Example

<bx:pdfform action="populate" source="registration-form.pdf" destination="completed-form.pdf">
    
    <!-- Text fields -->
    <bx:pdfformparam name="fullName" value="Jane Doe" />
    <bx:pdfformparam name="email" value="[email protected]" />
    
    <!-- Checkbox (requires specific values like "Yes"/"No" or "On"/"Off") -->
    <bx:pdfformparam name="agreeToTerms" value="Yes" />
    
    <!-- Dropdown selection -->
    <bx:pdfformparam name="country" value="United States" />
    
    <!-- Radio button -->
    <bx:pdfformparam name="gender" value="Female" />
    
    <!-- Date field -->
    <bx:pdfformparam name="birthDate" value="1985-03-15" />
    
    <!-- Numeric field -->
    <bx:pdfformparam name="yearsExperience" value="8" />
    
</bx:pdfform>

PDF Component

Performs advanced PDF operations like merging, splitting, watermarking, and form manipulation.

Supported Actions

Action Description
addAttachments Add file attachments to PDF
addHeader Add headers to pages
addFooter Add footers to pages
addWatermark Add watermark to pages
deletePages Remove specific pages
export Export form data (FDF/XFDF)
extractText Extract text content
extractimage Extract embedded images
getInfo Get PDF metadata
import Import form data
merge Combine multiple PDFs
protect Add password protection
removePassword Remove password protection
removeWatermark Remove watermarks
removeHeaderFooter Remove headers/footers
thumbnail Generate page thumbnails
transform Transform/manipulate pages
unsign Remove digital signatures
validatesignature Validate signatures
write Save PDF to file

Header/Footer Removal Notes

When using addHeader and addFooter, the stamped content is written as PDF Artifact marked content where supported, which aligns with standard PDF semantics for non-body content. The removeHeaderFooter action removes header/footer output for selected pages and is also compatible with document-rendered header/footer flows (for example documentitem header/footer output) by clearing the header/footer render bands.

Key Attributes

Attribute Type Description
action StringOperation to perform (see actions above)
source AnySource PDF(s) - file path, binary data, or variable
destination StringOutput file path
pages StringPage selection: "1-5", "1,3,5", "*"
overwrite BooleanOverwrite existing files
password StringPassword for encrypted PDFs

Header/Footer Placeholders

When using addHeader or addFooter actions, the following placeholders can be used in the text attribute:

Placeholder Description Example
_PAGENUMBER Replaced with the current page number"Page _PAGENUMBER" → "Page 1", "Page 2", etc.
_LASTPAGENUMBER Replaced with the total number of pages"Page _LASTPAGENUMBER" → "Page 10" (if 10 pages total)

Combined Example: "Page _PAGENUMBER of _LASTPAGENUMBER" becomes "Page 1 of 10", "Page 2 of 10", etc.

Note: Placeholders are only supported in addHeader and addFooter actions. They are not available in other PDF operations like watermarks or stamps.

Examples

Merging PDFs

<bx:pdf action="merge" 
        destination="/combined/merged-document.pdf" 
        overwrite="true">
    
    <bx:pdfparam source="/docs/doc1.pdf" />
    <bx:pdfparam source="/docs/doc2.pdf" />
    <bx:pdfparam source="/docs/doc3.pdf" />
    
</bx:pdf>

Adding Watermarks

<bx:pdf action="addWatermark"
        source="/documents/report.pdf"
        destination="/documents/watermarked-report.pdf"
        image="/images/confidential.png"
        opacity="0.3"
        position="center"
        rotation="45">
</bx:pdf>

Extracting Text

<bx:pdf action="extractText"
        source="/documents/report.pdf"
        destination="/extracted/report.txt"
        pages="1-10">
</bx:pdf>

Password Protection

<bx:pdf action="protect"
        source="/documents/sensitive.pdf"
        destination="/documents/protected.pdf"
        newOwnerPassword="admin123"
        newUserPassword="user123"
        permissions="print,copy">
</bx:pdf>

Adding Headers and Footers with Page Numbers

<bx:pdf action="addFooter"
        source="/documents/report.pdf"
        destination="/documents/report-paginated.pdf"
        text="Page _PAGENUMBER of _LASTPAGENUMBER"
        align="center"
        pages="*">
</bx:pdf>
<bx:pdf action="addHeader"
        source="/documents/report.pdf"
        destination="/documents/report-with-header.pdf"
        text="CONFIDENTIAL - Page _PAGENUMBER"
        align="right"
        pages="*">
</bx:pdf>

PDFParam Component

Specifies parameters for PDF operations, particularly for merge and attachment operations.

Attributes

Attribute Type Description
source StringSource file path
filename StringAttachment filename
encoding StringFile encoding (default: UTF-8)
mimeType StringFile MIME type
description StringAttachment description
password StringPassword for encrypted files

Example

<bx:pdf action="addAttachments" 
        source="/base/document.pdf" 
        destination="/enhanced/document.pdf">
    
    <bx:pdfparam source="/files/spreadsheet.xlsx"
                 filename="data.xlsx" 
                 mimeType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                 description="Supporting data analysis" />
    
    <bx:pdfparam source="/images/chart.png"
                 filename="sales-chart.png"
                 mimeType="image/png" 
                 description="Q4 Sales Performance Chart" />
    
</bx:pdf>

Advanced Examples

Complete Document Generation

<bx:set testImage = "https://ortus-public.s3.amazonaws.com/logos/ortus-medium.jpg"/>
<bx:document format="pdf" 
             filename="/reports/annual-report.pdf"
             pageType="A4"
             orientation="portrait"
             encryption="128-bit"
             openpassword="company2024"
             fontEmbed="true">
    
    <!-- Global Header -->
    <bx:documentitem type="header">
        <div style="text-align: center; border-bottom: 2px solid #333; padding: 10px;">
            <h2>Annual Business Report 2024</h2>
        </div>
    </bx:documentitem>
    
    <!-- Global Footer -->
    <bx:documentitem type="footer">
        <div style="text-align: center; font-size: 10px;">
            Page #bxdocument.currentpagenumber# of #bxdocument.totalpages#
        </div>
    </bx:documentitem>
    
    <!-- Executive Summary Section -->
    <bx:documentsection name="Executive Summary">
        <h1>Executive Summary</h1>
        <p>This report provides an overview of our performance...</p>
    </bx:documentsection>
    
    <!-- Charts Section -->
    <bx:documentsection name="Performance Charts" src="#testImage#" />
    
</bx:document>

PDF Processing Pipeline

<!-- Step 1: Merge quarterly reports -->
<bx:pdf action="merge" destination="/temp/combined-quarterly.pdf">
    <bx:pdfparam source="/reports/q1-2024.pdf" />
    <bx:pdfparam source="/reports/q2-2024.pdf" />
    <bx:pdfparam source="/reports/q3-2024.pdf" />
    <bx:pdfparam source="/reports/q4-2024.pdf" />
</bx:pdf>

<!-- Step 2: Add company watermark -->
<bx:pdf action="addWatermark"
        source="/temp/combined-quarterly.pdf"
        destination="/temp/watermarked-report.pdf"
        image="/assets/company-watermark.png"
        opacity="0.2"
        pages="*">
</bx:pdf>

<!-- Step 3: Add password protection -->
<bx:pdf action="protect"
        source="/temp/watermarked-report.pdf"
        destination="/final/annual-report-protected.pdf"
        newOwnerPassword="admin2024"
        newUserPassword="view2024"
        permissions="print">
</bx:pdf>

AI Visual Comparison Test Stub

This repo includes a test-only GitHub Models integration stub for comparing two static images:

  • Base helper: src/test/java/ortus/boxlang/modules/pdf/ai/BaseAIIntegrationTest.java
  • Concrete comparison tests: src/test/java/ortus/boxlang/modules/pdf/ai/PDFRenderingComparisonTest.java

The test is opt-in and skipped by default.

For VS Code test runs, the test helper now auto-loads a repo-root .env file if it exists.

Required Environment Variables

  • BX_PDF_AI_TESTS=true to enable the AI integration tests
  • BX_PDF_AI_TOKEN (preferred) or BX_PDF_AI_GITHUB_TOKEN

Optional:

  • BX_PDF_AI_MODEL (default: gpt-4.1)
  • BX_PDF_AI_ENDPOINT (default: https://models.inference.ai.azure.com/chat/completions)

For LM Studio (OpenAI-compatible local server), set:

  • BX_PDF_AI_ENDPOINT=http://localhost:1234/v1/chat/completions

If /chat/completions is configured by mistake, the test helper now retries once against /v1/chat/completions when the server reports an endpoint mismatch.

Local VS Code Usage

  1. Copy .env.example to .env
  2. Put your real GitHub token in BX_PDF_AI_TOKEN
  3. Leave BX_PDF_AI_TESTS=true
  4. Run the test from the VS Code Testing panel

No shell export is required for VS Code because the test helper reads the local .env file automatically.

Local Usage Example (PowerShell)

$env:BX_PDF_AI_TESTS = "true"
$env:BX_PDF_AI_TOKEN = "<your-token>"
./gradlew compileTestJava

This shell-based approach is optional now; it is only needed if you do not want to use the local properties file.

CI Usage

Set the BX_PDF_AI_TOKEN secret in CI and run the same test suite. BX_PDF_AI_TESTS is already enabled in the reusable tests workflow for CI. The API call path is identical between local and CI; only the credential source changes.

Form Processing Workflow

<!-- Process submitted form data -->
<bx:pdfform action="read" 
            source="/submissions/application-#url.id#.pdf" 
            result="applicationData" />

<!-- Validate and process data -->
<bx:if applicationData.status eq "pending">
    
    <!-- Update form with approval stamp -->
    <bx:pdfform action="populate"
                source="/submissions/application-#url.id#.pdf"
                destination="/processed/approved-application-#url.id#.pdf"
                overwriteData="true">
        
        <bx:pdfformparam name="status" value="APPROVED" />
        <bx:pdfformparam name="approvedBy" value="#session.user.name#" />
        <bx:pdfformparam name="approvalDate" value="#dateFormat(now(), 'yyyy-mm-dd')#" />
        
    </bx:pdfform>
    
</bx:if>

CFML Compatibility

This module provides full compatibility with CFML PDF tags:

  • cfdocumentbx:document
  • cfdocumentitembx:documentitem
  • cfdocumentsectionbx:documentsection
  • cfpdfbx:pdf
  • cfpdfparambx:pdfparam
  • cfpdfformbx:pdfform
  • cfpdfformparambx:pdfformparam

Migration from ColdFusion requires only prefix changes (cfbx).

Technical Requirements

  • BoxLang Runtime 1.0.0+
  • Java 21+

Support and Documentation

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.


Unreleased

1.6.3 - 2026-07-10

Added

  • Added support for PDF component actions sign, processddx and removeWatermark
  • BLMODULES-199 - Change to use non-XHTML parsing for all PDF HTML parsing
  • BLMODULES-200 - Compat updates to ensure tables scale to page width in portrait
  • PDF component source attribute now accepts an in-memory PDFDocument reference or raw byte[], and resolves bare variable names to a PDFDocument or byte[] in scope before treating the string as a file path. Mutations made to an in-memory PDFDocument are preserved across chained actions (no disk round-trip).

Fixed

  • Accept vertical alignment values (top, bottom, middle) in the align attribute of the PDF component for backwards compatibility with Adobe ColdFusion
  • pages attribute is no longer required for the addHeader and addFooter PDF component actions
  • PDFDocument no longer throws an NPE when extracting document info from an in-memory document with no file metadata
  • PDFDocument instances handed off to a caller variable via the name attribute are no longer closed by the component, so they can be reused in subsequent actions

Changed

  • Updated JSoup dependency to v1.22.2
  • Updated Flyin Saucer Library to v10.2.0
  • Updated PDFBox to v3.0.7
  • Updated XMPBox to v3.0.7

1.6.2 - 2026-03-14

Added

1.6.1 - 2026-01-09

1.6.0 - 2025-11-05

Fixed

  • BLMODULES-104 Fixed index out of bounds errors when deleting large quantities of pages

Changed

  • Updated Flying Saucer Library to v10
  • Updated Java dependencies and build actions

1.5.0 - 2025-10-27

Added

  • Added PDF Component - Boxlang+ license required
  • Added PDFForm Component - Boxlang+ license required
  • Added PDFFormParam Component - Boxlang+ license required

Fixed

  • Fixed CFDocument handling of encoding on URL includes

1.4.3 - 2025-10-03

1.4.2 - 2025-04-23

1.4.1 - 2025-03-13

1.3.1 - 2025-03-01

1.3.0 - 2025-03-01

Fixed

  • Archive classifier for shadow jar was missing

Added

  • New gradle plugin for shadow jar
  • Update all internal dependencies

1.2.0 - 2025-02-18

1.1.0 - 2025-02-14

  • Updated build processes
  • Fixed logger implementaton to latest runtime conventions
  • removed multi-version on changelogs
  • Updated Java dependencies to latest versions

1.0.0 - 2025-01-22

  • First iteration of this module

<<<<<<< HEAD

=======

development

$ box install bx-pdf

No collaborators yet.
     
  • {{ getFullDate("2024-08-06T18:22:06Z") }}
  • {{ getFullDate("2026-07-10T13:35:16Z") }}
  • 5,354
  • 27,413