BoxLang 🚀 A New JVM Dynamic Language Learn More...
|:------------------------------------------------------: |
| ⚡︎ B o x L a n g ⚡︎
| Dynamic : Modular : Productive
|:------------------------------------------------------: |
Copyright Since 2023 by Ortus Solutions, Corp
www.boxlang.io | www.ortussolutions.com
This module provides comprehensive PDF manipulation and generation functionality for BoxLang, including:
{% 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
This module contributes the following components to the BoxLang runtime:
document
- Main component for creating PDF documents from HTMLdocumentitem
- Specifies headers, footers, and page breaksdocumentsection
- Divides documents into sections with unique propertiespdf
- Advanced PDF operations (merge, split, watermark, etc.)pdfparam
- Parameters for PDF operations like attachmentspdfform
- Manipulate PDF forms (populate/read form fields)pdfformparam
- Specify individual form field valuesThe 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.
| 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
| Numeric | 100 | Scaling percentage (≤100) |
backgroundVisible
| Boolean | true | Show background elements |
bookmark
| Boolean | true | Generate bookmarks |
htmlBookmark
| Boolean | false | Convert HTML anchors to bookmarks |
fontEmbed
| Boolean | true | Embed fonts in document |
fontDirectory
| String | - | Custom font directory |
localUrl
| Boolean | false | Allow 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
| Boolean | false | Generate PDF/A compliant document |
saveAsName
| String | - | Browser save filename |
overwrite
| Boolean | false | Overwrite 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" |
The following attributes are not currently implemented and will throw an error if used:
permissions - Granular permissibility is not yet supportedpermissionspassword - Granular permissibility is not
yet supporteduserPassword - Granular permissibility is not yet supportedauthPassword - Authentication password not supportedauthUser - Authentication user not supporteduserAgent - HTTP user agent identifier not supportedproxyHost - Proxy server configuration not supportedproxyPassword - Proxy authentication not supportedproxyPort - Proxy port configuration not supportedproxyUser - Proxy user authentication not supportedtagged - ACF OpenOffice integration not supportedformfields - Form field attributes not implemented in
standard moduleformsType - Form type specification not implemented in
standard moduleSpecifies headers, footers, and page breaks within PDF documents.
| Attribute | Type | Required | Description |
|---|---|---|---|
type
| String | Yes | Item type: "header", "footer", "pagebreak" |
evalAtPrint
| Boolean | No | ⚠️ Deprecated - content always evaluated |
Divides PDF documents into sections with unique headers, footers, and page numbering.
| Attribute | Type | Description |
|---|---|---|
name
| String | Section name (used for bookmarks) |
marginTop
| Numeric | Section top margin |
marginBottom
| Numeric | Section bottom margin |
marginLeft
| Numeric | Section left margin |
marginRight
| Numeric | Section right margin |
src
| String | URL or relative path to content |
srcfile
| String | Absolute path to content file |
mimeType
| String | Content MIME type |
The following attributes are not currently implemented and will throw an error if used:
userAgent - HTTP user agent identifier for URL fetchingauthPassword - Authentication password for URL contentauthUser - Authentication username for URL contentManipulates PDF forms created in Adobe Acrobat and Adobe LiveCycle Designer. Supports both populating form fields and extracting form data.
| Attribute | Type | Required | Description |
|---|---|---|---|
action
| String | Yes | "populate" or "read" |
source
| Any | Yes | Source PDF form (file path, byte array, or variable) |
destination
| String | No | Output file path (populate action) |
result
| String | No | Variable name for extracted data (read action) |
overwrite
| Boolean | No | Overwrite existing files (default: false) |
overwriteData
| Boolean | No | Overwrite existing form data (default: false) |
fdfdata
| String | No | FDF file path for import/export |
XMLdata
| String | No | ⏳ XML data (planned feature) |
<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>
<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#" />
<!-- 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" />
Specifies individual form field values when populating PDF forms.
Must be nested within a pdfform component.
| Attribute | Type | Required | Description |
|---|---|---|---|
name
| String | Yes | Form field name |
value
| String | Yes | Value to assign to the field |
index
| Integer | No | Field index for LiveCycle forms (default: 1) |
index is not applicableindex to distinguish them<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>
Performs advanced PDF operations like merging, splitting, watermarking, and form manipulation.
| 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 |
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.
| Attribute | Type | Description |
|---|---|---|
action
| String | Operation to perform (see actions above) |
source
| Any | Source PDF(s) - file path, binary data, or variable |
destination
| String | Output file path |
pages
| String | Page selection: "1-5", "1,3,5", "*" |
overwrite
| Boolean | Overwrite existing files |
password
| String | Password for encrypted PDFs |
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.
<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>
<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>
<bx:pdf action="extractText"
source="/documents/report.pdf"
destination="/extracted/report.txt"
pages="1-10">
</bx:pdf>
<bx:pdf action="protect"
source="/documents/sensitive.pdf"
destination="/documents/protected.pdf"
newOwnerPassword="admin123"
newUserPassword="user123"
permissions="print,copy">
</bx:pdf>
<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>
Specifies parameters for PDF operations, particularly for merge and attachment operations.
| Attribute | Type | Description |
|---|---|---|
source
| String | Source file path |
filename
| String | Attachment filename |
encoding
| String | File encoding (default: UTF-8) |
mimeType
| String | File MIME type |
description
| String | Attachment description |
password
| String | Password for encrypted files |
<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>
<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>
<!-- 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>
This repo includes a test-only GitHub Models integration stub for comparing two static images:
src/test/java/ortus/boxlang/modules/pdf/ai/BaseAIIntegrationTest.java
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.
BX_PDF_AI_TESTS=true to enable the AI integration testsBX_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.
.env.example to .env
BX_PDF_AI_TOKEN
BX_PDF_AI_TESTS=true
No shell export is required for VS Code because the test helper reads
the local .env file automatically.
$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.
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.
<!-- 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>
This module provides full compatibility with CFML PDF tags:
cfdocument → bx:document
cfdocumentitem → bx:documentitem
cfdocumentsection → bx:documentsection
cfpdf → bx:pdf
cfpdfparam → bx:pdfparam
cfpdfform → bx:pdfform
cfpdfformparam → bx:pdfformparam
Migration from ColdFusion requires only prefix changes
(cf → bx).
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.
sign, processddx and removeWatermarksource 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).top, bottom, middle) in the align attribute of the PDF component for backwards compatibility with Adobe ColdFusionpages attribute is no longer required for the addHeader and addFooter PDF component actionsPDFDocument no longer throws an NPE when extracting document info from an in-memory document with no file metadataPDFDocument 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 actionsisPDFFile and isPDFObject validation BIFsPDF Component - Boxlang+ license requiredPDFForm Component - Boxlang+ license requiredPDFFormParam Component - Boxlang+ license required<<<<<<< HEAD
=======
development
$
box install bx-pdf