1. ACF-Plugin Functions for PDF Documents
- ACF-Plugin Functions for PDF Documents
- Commands and Functions
1.1. Introduction ↑
The ACF-Plugin introduces PDF generation functions in plugin version 1.8.0.3. These functions create PDF documents directly from ACF code, with support for text, Markdown in table columns, tables, streamed tables, headers, footers, images, drawing primitives, page breaks, metadata, and embedded fonts.
Plugin version 1.8.0.4 extends the PDF text layout engine with rotated text, stretch alignment, paragraph spacing, multi-column text boxes, text wrapping around floating objects, locale-aware line breaking, and retrieval of unplaced text from fixed-height boxes.
Native FileMaker layouts can already print and save PDFs, but this functionality gives an alternate route for generating PDF documents directly. It is useful for reports that contain mixed content, conditional sections, data from several sources, streamed rows, dynamic tables, or layouts that are difficult to maintain with traditional layout printing and sliding objects.
The PDF commands are designed for report generation. A document is created with pdf_create, drawing commands are added to the document, and the document is written with pdf_close or close_pdf.
PDF coordinates are measured in points. The origin is the upper-left corner of the page. The default page size is A4 portrait, 595 x 842 points.
2. Commands and Functions ↑
2.1. Functions for Creating and Managing PDF Files ↑
2.1.1. pdf_create ↑
- Syntax:
int pdf_create(string path) - Description: Creates a new PDF document and returns a PDF ID.
- Parameters:
path: The output path for the PDF file.
- Returns: A
PDF_IDto reference the created PDF document. - Note: The PDF producer metadata is set internally by the plugin. From version 1.8.0.3 this is written as
ACF Plugin ver <plugin version>.
Example:
int pdf = pdf_create("~/Desktop/MyReport.pdf");
2.1.2. pdf_close ↑
- Syntax:
pdf_close(int PDF_ID) - Alternative Syntax:
close_pdf(int PDF_ID) - Description: Finalizes the PDF file, writes all pending objects, and closes the document.
- Parameters:
PDF_ID: The ID returned frompdf_create.
- Note: A document cannot be used after it has been closed.
Example:
pdf_close(pdf);
2.1.3. pdf_newPage ↑
- Syntax:
pdf_newPage(int PDF_ID) - Description: Ends the current page and starts a new page. Headers and footers are applied automatically.
- Parameters:
PDF_ID: The ID returned frompdf_create.
- Note: This command cannot be used while a streamed table is active. Call
pdf_drawTableEndfirst.
Example:
pdf_drawText(pdf, "First page", JSON("x", 50, "width", 495));
pdf_newPage(pdf);
pdf_drawText(pdf, "Second page", JSON("x", 50, "width", 495));
2.2. Page Setup and Metadata ↑
2.2.1. pdf_setPageOptions ↑
- Syntax:
pdf_setPageOptions(int PDF_ID, JSON options) - Description: Sets document-level options. This must be called before drawing starts.
- Parameters:
PDF_ID: The ID returned frompdf_create.options: JSON object with document options.
Common options:
title: PDF title metadata.author: PDF author metadata.pageSize: Named page size, such as"A4","Letter", or"Ledger".width: Page width in points.height: Page height in points.orientation:"portrait"or"landscape".topMargin: Body start position if no header is used.bottomMargin: Bottom margin.flowGap: Default vertical gap after flow commands.- Note: If
pageSizeand explicitwidthorheightare both supplied, the explicit numeric values override the named size.
Example:
pdf_setPageOptions(pdf, JSON(
"title", "Order confirmation",
"author", "ACF report",
"pageSize", "A4",
"orientation", "landscape",
"topMargin", 50,
"bottomMargin", 50
));
Supported named page sizes:
| Name | Size | PDF points |
|---|---|---|
A0 |
841 x 1189 mm | 2383.94 x 3370.39 |
A1 |
594 x 841 mm | 1683.78 x 2383.94 |
A2 |
420 x 594 mm | 1190.55 x 1683.78 |
A3 |
297 x 420 mm | 841.89 x 1190.55 |
A4 |
210 x 297 mm | 595.28 x 841.89 |
A5 |
148 x 210 mm | 419.53 x 595.28 |
A6 |
105 x 148 mm | 297.64 x 419.53 |
A7 |
74 x 105 mm | 209.76 x 297.64 |
A8 |
52 x 74 mm | 147.40 x 209.76 |
A9 |
37 x 52 mm | 104.88 x 147.40 |
Letter, US Letter |
8.5 x 11 in | 612 x 792 |
Legal, US Legal |
8.5 x 14 in | 612 x 1008 |
Tabloid |
11 x 17 in | 792 x 1224 |
Ledger |
17 x 11 in | 1224 x 792 |
Executive |
7.25 x 10.5 in | 522 x 756 |
Statement, Half Letter |
5.5 x 8.5 in | 396 x 612 |
2.2.2. pdf_setPageHeader ↑
- Syntax:
pdf_setPageHeader(int PDF_ID, JSON header {, string mode}) - Description: Defines drawing commands for the page header.
- Parameters:
PDF_ID: The ID returned frompdf_create.header: JSON object containing acommandsarray.mode: Optional."first","next","second","continuation","all", or"both".
- Note: If
modeis omitted, the header is used for the first page block.
Header object fields:
commands: Array of drawing command JSON objects.height: Height of the header block.bodyGap: Space between the header and the body flow area.enabled: Optional boolean.
Example:
pdf_setPageHeader(pdf, JSON(
"height", 76,
"bodyGap", 20,
"commands", JSONarray(
JSON("op", "rect", "x", 0, "y", 0, "width", 595, "height", 76, "mode", "fill"),
JSON("op", "text", "x", 50, "y", 32, "size", 18, "value", "Sales report")
)
), "all");
2.2.3. pdf_setPageFooter ↑
- Syntax:
pdf_setPageFooter(int PDF_ID, JSON footer {, string mode}) - Description: Defines drawing commands for the page footer.
- Parameters:
PDF_ID: The ID returned frompdf_create.footer: JSON object containing acommandsarray.mode: Optional."first","next","second","continuation","all", or"both".
- Note: If
modeis omitted, the footer is used for the first page block. Text values can use{page}and{pages}placeholders.{pages}is resolved when the PDF is finalized.
Example:
pdf_setPageFooter(pdf, JSON(
"height", 42,
"commands", JSONarray(
JSON("op", "line", "x1", 50, "y1", 0, "x2", 545, "y2", 0,
"lineStyle", "thin", "color", "#B8B8B8"),
JSON("op", "text", "x", 50, "y", 24, "size", 9,
"value", "Generated by ACF"),
JSON("op", "text", "x", 50, "y", 24, "width", 495, "size", 9,
"align", "right", "value", "Page {page} of {pages}")
)
), "all");
2.3. Font Handling ↑
2.3.1. pdf_setFont ↑
- Syntax:
pdf_setFont(int PDF_ID, JSON fontOptions) - Description: Sets the current default font used by later text and table commands.
- Parameters:
PDF_ID: The ID returned frompdf_create.fontOptions: JSON object describing the font.
Common font options:
name: Font family or PDF base font name.font: Alternative key forname.embed: Boolean. When true, the font is embedded and subsetted.size: Optional default size used by commands that do not specify their own size.
Example:
pdf_setFont(pdf, JSON("name", "Arial", "embed", true));
pdf_drawText(pdf, "ÆØÅ éüñ €", JSON("x", 50, "width", 495, "size", 12));
2.4. Text Commands ↑
2.4.1. pdf_drawText ↑
- Syntax:
pdf_drawText(int PDF_ID, string text, JSON options) - Description: Draws text into the PDF. Long text wraps within the given width and can flow to the next page.
- Parameters:
PDF_ID: The ID returned frompdf_create.text: The text to draw.options: JSON object with position and style.
Common options:
x: Left position.y: Top position. If omitted, the current vertical position is used.width: Text width. If omitted, the right page margin is used as fallback.height: Optional maximum height.size: Font size.lineHeight: Line height.align:"left","right","center","centre", or"stretch".rotateorrotation: Rotates the whole text block in degrees around the command'sx,yanchor.padding,paddingTop,paddingRight,paddingBottom,paddingLeft: Adds spacing around the command.marginBottom: Space after the command.wrap: Optional floating object or array of floating objects that the text should flow around. See "Wrapping Text Around Floating Objects" below.
Example:
pdf_drawText(pdf,
"This text wraps naturally inside the available width.",
JSON("x", 50, "width", 495, "size", 11, "lineHeight", 15)
);
2.4.2. pdf_drawTextBox ↑
- Syntax:
pdf_drawTextBox(int PDF_ID, string text, float x, float y, float width, float height, JSON options) - Description: Draws text inside an explicit rectangle.
- Parameters:
PDF_ID: The ID returned frompdf_create.text: The text to draw.x: Left position.y: Top position.width: Box width.
height: Box height.options: JSON object with style options.
Common options:
size: Font size.lineHeight: Line height.align:"left","right","center","centre", or"stretch".rotateorrotation: Rotates the whole text box in degrees around the boxx,yanchor.columns: Number of text columns inside the box.gutter: Space between columns in points.balanceColumns: When true, and all text fits inside the box, lines are divided more evenly between columns.paragraphSpacing: Extra vertical space after each paragraph. If omitted, a sensible default based on line height is used.wrap: Optional floating object or array of floating objects that the text should flow around when the command is used as flowed body text.
Example:
pdf_drawTextBox(pdf,
"Customer address line 1\nCustomer address line 2",
50, 160, 220, 70,
JSON("size", 10, "lineHeight", 13)
);
Stretch alignment distributes extra spacing between words on each non-final line in a paragraph. The final line of each paragraph keeps natural spacing.
Two-column article style example:
pdf_drawTextBox(pdf, bodyText, 50, 260, 495, 300, JSON(
"size", 10.5,
"lineHeight", 14,
"align", "stretch",
"paragraphSpacing", 7,
"columns", 2,
"gutter", 14,
"balanceColumns", true
));
If a fixed-height box cannot place all text, the unplaced part can be retrieved with pdf_getUnplacedRest(...).
2.4.3. Wrapping Text Around Floating Objects ↑
Plain flowed pdf_drawText(...) and pdf_drawTextBox(...) can wrap around floating objects by using the wrap option. The wrap value may be one object or an array of objects.
Supported floating object types:
imagetextBoxtable
Common wrap object fields:
type:"image","textBox", or"table".align:"left"or"right".width: Floating object width.height: Floating object height, when relevant.margin: Either one number for all sides, or an object withtop,right,bottom,leftor short keyst,r,b,l.
Image wrap example:
pdf_drawText(pdf, productText, JSON(
"x", 56,
"width", 483,
"size", 11,
"lineHeight", 14,
"wrap", JSON(
"type", "image",
"imageId", productImage,
"align", "right",
"width", 150,
"height", 82,
"margin", JSON("t", 0, "r", 0, "b", 6, "l", 10)
)
));
Multiple wrap objects can be supplied with JSONarray(...), for example an image with a small table below it:
pdf_drawText(pdf, productText, JSON(
"x", 56,
"width", 483,
"size", 11,
"lineHeight", 14,
"wrap", JSONarray(
JSON("type", "image", "imageId", productImage, "align", "right",
"width", 150, "height", 82, "margin", JSON("t", 0, "l", 10, "b", 6)),
JSON("type", "table", "align", "right", "width", 150,
"margin", JSON("t", 4, "l", 10, "b", 10),
"columns", JSONarray(
JSON("key", "label", "width", 66),
JSON("key", "value", "width", 84, "align", "right")
),
"values", JSONarray(
JSON("label", "SKU", "value", "PNG-140"),
JSON("label", "Stock", "value", "42")
),
"tableProperties", JSON("showHeader", false, "fontSize", 8,
"rowHeight", 14, "padding", 2))
)
));
When the floating object has no explicit y, margin.t controls how it lines up with the current text flow. Use margin.t set to 0 when the image should start at the top of the text.
2.4.4. Markdown Text in Tables ↑
Markdown text is supported in table columns by setting "markdown", true on a column.
Example column:
JSON("key", "comment", "title", "Comment", "width", 300, "markdown", true)
2.5. Drawing Commands ↑
2.5.1. pdf_drawRect ↑
- Syntax:
pdf_drawRect(int PDF_ID, float x, float y, float width, float height {, JSON options}) - Description: Draws a rectangle.
Example:
pdf_drawRect(pdf, 50, 120, 200, 80, JSON("mode", "stroke"));
2.5.2. pdf_drawOval ↑
- Syntax:
pdf_drawOval(int PDF_ID, float x, float y, float width, float height {, JSON options}) - Description: Draws an oval inside the given rectangle.
Example:
pdf_drawOval(pdf, 50, 220, 120, 60, JSON("mode", "stroke"));
2.5.3. pdf_drawCircle ↑
- Syntax:
pdf_drawCircle(int PDF_ID, float centerX, float centerY, float radius {, JSON options}) - Description: Draws a circle.
Example:
pdf_drawCircle(pdf, 120, 340, 30, JSON("mode", "stroke"));
2.5.4. pdf_drawLine ↑
- Syntax:
pdf_drawLine(int PDF_ID, float x1, float y1, float x2, float y2 {, JSON options}) - Description: Draws a line.
- Note:
lineStylecan use the same style names as Excel borders, such as"thin","medium","thick","dashed","dotted","dashDot", and"double".
Example:
pdf_drawLine(pdf, 50, 400, 545, 400,
JSON("lineStyle", "thin", "color", "#606060")
);
2.5.5. pdf_drawPolyline ↑
- Syntax:
pdf_drawPolyline(int PDF_ID, JSON polyline {, JSON options}) - Description: Draws a connected set of line segments.
- Parameters:
polyline: JSON object withpoints.options: Optional JSON object merged into the command.
Example:
pdf_drawPolyline(pdf,
JSON("points", JSONarray(50, 460, 120, 480, 180, 450)),
JSON("lineStyle", "medium")
);
2.6. Colors ↑
Colors can be specified as:
- Hex strings:
"#1A4D7A","1A4D7A","#ABC", or"ABC". - RGB arrays with values from 0 to 1:
JSONarray(0.1, 0.3, 0.5). - RGB objects:
JSON("r", 0.1, "g", 0.3, "b", 0.5).
Example:
pdf_drawLine(pdf, 50, 80, 545, 80, JSON("color", "#A8B4C0"));
2.7. Images ↑
2.7.1. pdf_addImage ↑
- Syntax:
int pdf_addImage(int PDF_ID, string path {, string fileType}) - Alternative Syntax:
int pdf_addImage(int PDF_ID, container image {, string fileType}) - Description: Adds an image to the PDF and returns an image ID.
- Parameters:
PDF_ID: The ID returned frompdf_create.path: A path to an image file.image: A FileMaker container value.fileType: Optional. Used when the type cannot be detected from path or container filename.
- Returns: An image ID used by
pdf_placeImage.
Example:
int logoId = pdf_addImage(pdf, logoContainer);
2.7.2. pdf_placeImage ↑
- Syntax:
pdf_placeImage(int PDF_ID, int imageID, float x, float y, float width, float height {, JSON options}) - Description: Places an image previously added with
pdf_addImage. - Parameters:
PDF_ID: The ID returned frompdf_create.imageID: The image ID returned frompdf_addImage.x: Left position.y: Top position.width: Image width.height: Image height.options: Optional JSON object.
Example:
int logoId = pdf_addImage(pdf, logoContainer);
pdf_placeImage(pdf, logoId, 400, 40, 140, 60, JSON());
2.8. Tables ↑
2.8.1. pdf_drawTable ↑
- Syntax:
pdf_drawTable(int PDF_ID, JSON table {, JSON options}) - Description: Draws a complete table from one JSON definition.
- Parameters:
PDF_ID: The ID returned frompdf_create.table: JSON object containing columns, values, table properties, and optional footer.options: Optional JSON object merged into the table command.
Table object fields:
x: Left position.y: Top position. If omitted, the current vertical position is used.width: Total table width.columns: Array of column objects.values: Array of row arrays or row objects.tableProperties: Optional styling object.footer: Optional footer row object.continuationNote: Optional text drawn before a page break when the table continues.
Column fields:
key: Field name used when rows are JSON objects.title: Header title.width: Column width.align:"left","right","center", or"centre".markdown: Boolean. Enables Markdown rendering in this column.hidden: Boolean. Hides the column.resizeMode:"move"or"expand". Hidden columns give their width to the nearest expandable column.
Table property fields:
fontSize,headerFontSize,footerFontSize.rowHeight,headerHeight,footerHeight.padding.borderWidth,borderColor.textColor,headerTextColor,footerTextColor.headerFill,footerFill,rowFill,alternateFill.alternateRows.showHeader.
Example:
json tableDef = JSON(
"x", 50,
"width", 495,
"columns", JSONarray(
JSON("key", "item", "title", "Item", "width", 320, "resizeMode", "expand"),
JSON("key", "qty", "title", "Qty", "width", 55, "align", "right"),
JSON("key", "amount", "title", "Amount", "width", 120, "align", "right")
),
"values", JSONarray(
JSON("item", "Curtains", "qty", "2", "amount", "25 000,00"),
JSON("item", "Mounting", "qty", "1", "amount", "6 250,00")
),
"tableProperties", JSON(
"fontSize", 10,
"rowHeight", 24,
"alternateRows", true,
"headerFill", "#DCEAF7",
"alternateFill", "#EEF6FF",
"borderColor", "#A8B4C0"
),
"footer", JSON(
"cells", JSONarray(
JSON("text", "Total", "colSpan", 2, "align", "right"),
JSON("text", "31 250,00", "align", "right")
)
)
);
pdf_drawTable(pdf, tableDef);
2.8.2. Cell Borders ↑
Cells can override table borders by using a cell object with text or value and a border property.
Border can be a side string such as "tb" or an object:
JSON("text", "**Sum total:**", "border", JSON(
"sides", "tb",
"lineStyle", "thin",
"color", "#404040",
"width", 0.5
))
Supported side letters are:
t: Top.b: Bottom.l: Left.r: Right.
2.9. Streamed Tables ↑
For long reports, a table can be started, rows can be added in chunks, and the table can be ended later. This is useful when the PDF is created by several ACF calls or while looping records in FileMaker.
The odd/even row state is preserved between pdf_drawTableRows calls, so alternating row colors continue correctly across chunks.
2.9.1. pdf_drawTableStart ↑
- Syntax:
pdf_drawTableStart(int PDF_ID, JSON tableHeaderAndProperties) - Description: Starts a streamed table. The JSON should contain columns, table properties, and positioning.
2.9.2. pdf_drawTableRows ↑
- Syntax:
pdf_drawTableRows(int PDF_ID, JSON tableRows) - Description: Adds rows to the active streamed table.
- Parameters:
tableRows: Either a JSON array of rows, or a JSON object containingvalues.
2.9.3. pdf_drawTableEnd ↑
- Syntax:
pdf_drawTableEnd(int PDF_ID {, JSON tableFooter}) - Description: Ends the active streamed table and optionally draws the footer.
Example:
json tableDef = JSON(
"x", 50,
"width", 495,
"columns", JSONarray(
JSON("key", "nr", "title", "#", "width", 42, "align", "right"),
JSON("key", "text", "title", "Text", "width", 378, "resizeMode", "expand"),
JSON("key", "amount", "title", "Amount", "width", 75, "align", "right")
),
"tableProperties", JSON(
"fontSize", 10,
"rowHeight", 24,
"headerHeight", 26,
"alternateRows", true,
"alternateFill", "#EEF6FF"
),
"continuationNote", "Continues on the next page"
);
pdf_drawTableStart(pdf, tableDef);
pdf_drawTableRows(pdf, JSONarray(
JSON("nr", "1", "text", "First streamed row", "amount", "100,00"),
JSON("nr", "2", "text", "Second streamed row", "amount", "200,00")
));
pdf_drawTableRows(pdf, JSONarray(
JSON("nr", "3", "text", "Third streamed row", "amount", "300,00")
));
pdf_drawTableEnd(pdf, JSON(
"footer", JSON(
"cells", JSONarray(
JSON("text", "Total rows", "colSpan", 2, "align", "right"),
JSON("text", "3", "align", "right")
)
)
));
2.10. Information Functions ↑
2.10.1. pdf_getCurrentPage ↑
- Syntax:
int pdf_getCurrentPage(int PDF_ID) - Description: Returns the current page number.
Example:
int pageNo = pdf_getCurrentPage(pdf);
2.10.2. pdf_getCursorPos ↑
- Syntax:
float pdf_getCursorPos(int PDF_ID) - Description: Returns the current vertical cursor position.
Example:
float y = pdf_getCursorPos(pdf);
2.10.3. pdf_getUnplacedRest ↑
- Syntax:
string pdf_getUnplacedRest(int PDF_ID) - Description: Returns the most recent unplaced text from a fixed-height
pdf_drawTextBox(...)call. - Use case: Draw part of a text in a fixed box, then continue the remaining text on another page or in another region.
- Note: The unplaced buffer is updated by text box drawing. Read it immediately after the drawing command whose overflow you want to handle.
Example:
pdf_drawTextBox(pdf, articleText, 50, 180, 495, 220, JSON(
"size", 10.5,
"lineHeight", 14,
"columns", 2,
"gutter", 14,
"align", "stretch"
));
string rest = pdf_getUnplacedRest(pdf);
if (rest != "") then
pdf_newPage(pdf);
pdf_drawTextBox(pdf, rest, 50, 80, 495, 680, JSON(
"size", 10.5,
"lineHeight", 14,
"columns", 2,
"gutter", 14,
"align", "stretch"
));
end if
2.11. Complete Example ↑
package pdfExample "PDF example";
function PdfExample(container logo)
string outPath = "~/Desktop/acf-pdf-example.pdf";
int pdf = pdf_create(outPath);
pdf_setPageOptions(pdf, JSON(
"title", "ACF PDF example",
"author", "ACF Plugin",
"topMargin", 50,
"bottomMargin", 50
));
pdf_setPageHeader(pdf, JSON(
"height", 76,
"bodyGap", 20,
"commands", JSONarray(
JSON("op", "setFillColor", "color", "#E8EEF5"),
JSON("op", "rect", "x", 0, "y", 0, "width", 595, "height", 76, "mode", "fill"),
JSON("op", "setFillColor", "color", "#1A2433"),
JSON("op", "text", "x", 50, "y", 32, "size", 18, "value", "PDF report")
)
), "all");
pdf_setPageFooter(pdf, JSON(
"height", 42,
"commands", JSONarray(
JSON("op", "line", "x1", 50, "y1", 0, "x2", 545, "y2", 0, "color", "#B8B8B8"),
JSON("op", "text", "x", 50, "y", 24, "size", 9, "value", "Generated by ACF"),
JSON("op", "text", "x", 50, "y", 24, "width", 495, "size", 9,
"align", "right", "value", "Page {page} of {pages}")
)
), "all");
pdf_setFont(pdf, JSON("name", "Arial", "embed", true));
int logoId = pdf_addImage(pdf, logo);
pdf_placeImage(pdf, logoId, 405, 96, 140, 60, JSON());
pdf_drawText(pdf,
"This text is drawn in the body flow area. If the y value is omitted, the current cursor is used.",
JSON("x", 50, "width", 330, "size", 11, "lineHeight", 15)
);
pdf_drawTable(pdf, JSON(
"x", 50,
"width", 495,
"paddingTop", 16,
"columns", JSONarray(
JSON("key", "description", "title", "Description", "width", 320, "resizeMode", "expand"),
JSON("key", "qty", "title", "Qty", "width", 55, "align", "right"),
JSON("key", "amount", "title", "Amount", "width", 120, "align", "right")
),
"values", JSONarray(
JSON("description", "Product A", "qty", "2", "amount", "10 000,00"),
JSON("description", "Product B", "qty", "1", "amount", "5 000,00")
),
"tableProperties", JSON(
"fontSize", 10,
"rowHeight", 24,
"alternateRows", true,
"headerFill", "#DCEAF7",
"alternateFill", "#EEF6FF",
"borderColor", "#A8B4C0"
),
"footer", JSON(
"cells", JSONarray(
JSON("text", "Total", "colSpan", 2, "align", "right"),
JSON("text", "15 000,00", "align", "right")
)
)
));
pdf_newPage(pdf);
pdf_drawText(pdf, "Manual page break created this page.", JSON("x", 50, "width", 495));
pdf_close(pdf);
return outPath;
end
2.12. Notes ↑
- PDF functions throw runtime exceptions if a command is invalid, if a handle is unknown, or if a PDF is already closed.
- Headers and footers use coordinates relative to the top of their own block.
- Body drawing commands use the current vertical cursor when
yis omitted. - Text and tables can flow automatically to the next page.
align,rotate,wrap,columns,gutter,balanceColumns, andparagraphSpacingare available for PDF text layout in version 1.8.0.4.- Streamed tables must be ended with
pdf_drawTableEndbefore closing the PDF. pdf_newPagecannot be used while a streamed table is open.
