Skip to main content
Version: 4.2 (beta)

PDF Document API

The com.hsyco.pdf API creates PDF documents from plugins and drivers: flowing text, lists, tables with repeated header rows, images, Java2D drawings, headers and footers with page numbers. It is built on Apache PDFBox 3.0.8, embedded in hsyco.jar (see Office and PDF Libraries), and gives access to PDFBox for everything it doesn't cover.

import com.hsyco.pdf.*;
import java.awt.Color;
import java.io.File;

try (Document doc = new Document(PageSize.A4, 40, 40, 60, 50)) { // margins: left, right, top, bottom, in points
doc.addTitle("Energy report");
doc.setFooter("Building A", "", "Page {page} of {pages}", new Font(Font.SANS, 8));

Paragraph title = new Paragraph("Energy report - October 2026", new Font(Font.SANS, 16, Font.BOLD));
title.setSpacingAfter(12);
title.setKeepWithNext(true);
doc.add(title);

Table table = new Table(new float[] {3, 1, 1}); // relative widths
table.setWidthPercentage(100);
table.setHeaderRows(1); // repeated on each page
table.setAlternateRowColor(new Color(0xF2F4F7));
table.getDefaultCell().setPadding(4); // also for the Cells below
Font bold = new Font(Font.SANS, 9, Font.BOLD);
table.addCell(new Cell(new Phrase("Meter", bold)));
table.addCell(new Cell(new Phrase("kWh", bold)));
table.addCell(new Cell(new Phrase("Cost", bold)));
for (Reading r : readings) {
table.addCell(r.name);
Cell kwh = new Cell(String.format("%.1f", r.kwh));
kwh.setHorizontalAlignment(Element.ALIGN_RIGHT);
table.addCell(kwh);
table.addCell(String.format("%.2f €", r.cost));
}
doc.add(table);

// a bar chart in Java2D: points, origin at the top left of the block
doc.add(Drawing.graphics2D(150, (g, width, height) -> {
g.setColor(new Color(0x3366CC));
for (int i = 0; i < daily.length; i++) {
int h = (int) (daily[i] / maxDaily * (height - 15));
g.fillRect(i * 16, (int) height - h, 12, h);
}
g.setColor(Color.BLACK);
g.setFont(new java.awt.Font("SansSerif", java.awt.Font.PLAIN, 8));
g.drawString("kWh per day", 0, 10);
}));

doc.save(new File("reports/energy-2026-10.pdf")); // creates reports/ if needed
}

Layout rules​

  • Elements are placed top to bottom in the content area of the page, in the order they are added. What doesn't fit moves to a new page, with the same size and margins, or the ones set with setPageSize() and setMargins() for the following pages. All lengths are in points (1/72 inch); Units.mm() converts millimeters.
  • Lines break at spaces, measured with the font metrics. A word longer than the line is broken between characters. There is no hyphenation.
  • Text is normalized to composed characters. A tab is drawn as four spaces; \r\n and \r are line breaks like \n; a no-break space (U+00A0) looks like a space but never breaks; a soft hyphen and other control characters are removed.
  • Justified text widens the real spaces, so text extraction, search and copy and paste see one space between words. The last line of a paragraph and a line ended by \n are not justified.
  • A paragraph splits between lines across pages unless setKeepTogether(true). setKeepWithNext(true) moves a heading to the next page together with the first line of the following element.
  • A table row is not split if it fits on an empty page: it moves to the next page, and the header rows are repeated first. Header rows are never left alone at the bottom of a page. A row taller than a full page is split between text lines of its cells; an image in a cell is scaled down to fit. Column widths are computed once per table. The alternate row color counts body rows from the first one, across pages.
  • A character that the font doesn't have is drawn as ? and logged once per document in the HSYCO error log. With TIMES and COURIER this applies to everything outside Western European text.
  • Right-to-left text and scripts that need glyph shaping (Arabic, Indic) are not supported. Chinese, Japanese and Korean work with a TrueType font registered with Font.registerFamily() or loaded with Font.load(), with line breaks between characters.
  • Page content is kept in temporary files under .tmp/pdf in the HSYCO folder, not in memory, so long reports fit on a Raspberry Pi. close() deletes them; use try-with-resources. On a Raspberry Pi, a 50-page report takes about 10 seconds: build reports in a separate thread, not in callbacks that must return quickly.

Fonts​

SANS is the default family: Liberation Sans, embedded, for all the Latin, Greek and Cyrillic text it covers, and metrically compatible with Helvetica and Arial. HELVETICA is the same font. TIMES (also TIMES_ROMAN) and COURIER are PDF standard fonts, not embedded, for Western European text only. Only the characters used are embedded. Other TrueType fonts are added with Font.registerFamily() or Font.load().

Names shared with other packages​

Cell also exists in Apache POI (org.apache.poi.ss.usermodel), Font and Image in java.awt, Document and Element in org.w3c.dom. With wildcard imports of both packages the compiler reports the ambiguity: next to import com.hsyco.pdf.*;, import other classes by their single name (import java.awt.Color;), and write a clashing one fully qualified, such as java.awt.Font in a Java2D drawing.

Document​

A PDF document laid out from elements added in order. Headers, footers and page decorators are drawn at save(), when the page count is known.

Document(PageSize size)
Document(PageSize size, float left, float right, float top, float bottom)

Creates a document. The margins are in points; without them, 36 points on every side.

add​

void add(Element element) throws IOException

Lays out an element after the previous ones: a Paragraph, Phrase, ItemList, Table, Image, Drawing, LineSeparator, Spacer or PageBreak. An element with setKeepWithNext(true) waits for the next one. Throws IllegalStateException after save().

newPage​

void newPage() throws IOException

Starts a new page for the content that follows. Has no effect on a page without content, and a break that no content follows adds no page.

setPageSize​

void setPageSize(PageSize size)

The page size of the following pages.

setMargins​

void setMargins(float left, float right, float top, float bottom)

The margins of the following pages, in points.

addTitle​

void addTitle(String title)
void addAuthor(String author)
void addSubject(String subject)
void addKeywords(String keywords)
void addCreator(String creator)

Document properties.

setHeader​

void setHeader(String text, int alignment, Font font)
void setHeader(String left, String center, String right, Font font)

A header in the top margin, with its baseline at half the top margin: one text aligned Element.ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT, or three texts. {page} and {pages} are replaced by the page number and count.

setFooter​

void setFooter(String text, int alignment, Font font)
void setFooter(String left, String center, String right, Font font)

A footer in the bottom margin, with its baseline at half the bottom margin, like setHeader.

setPageDecorator​

void setPageDecorator(PageDecorator decorator)

Draws on every page at save(), after the header and footer: logos, watermarks, custom headers.

getPDDocument​

PDDocument getPDDocument()

The PDFBox document being built, for everything this API doesn't cover.

save​

void save(File file) throws IOException
void save(OutputStream out) throws IOException

Writes the document. save(File) creates missing folders. The first save draws headers, footers and decorators; no element can be added after it.

close​

void close() throws IOException

Deletes the temporary files. A document with content that was closed without save() writes nothing, and logs HSYCO PDF: document closed without save(), nothing written.

PageSize​

A page size in points. rotate() gives the landscape size.

PageSize(float width, float height)

A custom size in points.

PageSize constants​

PageSize A3, A4, A5, LETTER, LEGAL

A3 841.89 × 1190.55, A4 595.28 × 841.89, A5 419.53 × 595.28, LETTER 612 × 792, LEGAL 612 × 1008.

rotate​

PageSize rotate()

The same size, landscape.

getWidth​

float getWidth()
float getHeight()

Units​

mm​

static float mm(float mm)

Converts millimeters to points.

Font​

A font: family, size in points, style and color (java.awt.Color, black by default).

Font(String family, float size)
Font(String family, float size, int style)
Font(String family, float size, int style, Color color)

Font constants​

String SANS, HELVETICA, TIMES, TIMES_ROMAN, COURIER
int NORMAL, BOLD, ITALIC, BOLDITALIC, UNDERLINE

Families and styles; styles combine, such as Font.BOLD | Font.UNDERLINE.

registerFamily​

static void registerFamily(String name, File regular, File bold, File italic, File boldItalic)

Adds a TrueType family. A style without a file (null) uses the regular file; no bold or italic is synthesized. Throws IllegalArgumentException when a file can't be read.

load​

static Font load(File ttf, float size, int style, Color color)

A shortcut for a family of one TrueType file.

getFamily​

String getFamily()
float getSize()
int getStyle()
Color getColor()

Chunk​

A run of text in one font. A chunk without its own font takes the font of its phrase.

Chunk(String text)
Chunk(String text, Font font)

NEWLINE​

static Chunk NEWLINE

A forced line break.

setBackground​

Chunk setBackground(Color color)

Phrase​

A sequence of chunks with no paragraph spacing, used in cells and as the base of Paragraph. The default font is SANS 12.

Phrase()
Phrase(String text)
Phrase(String text, Font font)

add​

Phrase add(Chunk chunk)

Paragraph​

A phrase laid out as a block. \n in the text is a line break.

Paragraph()
Paragraph(String text)
Paragraph(String text, Font font)
Paragraph(Phrase phrase)

setAlignment​

void setAlignment(int alignment)

Element.ALIGN_LEFT (default), ALIGN_CENTER, ALIGN_RIGHT or ALIGN_JUSTIFIED.

setLeading​

void setLeading(float points)

A fixed line height.

setMultipliedLeading​

void setMultipliedLeading(float factor)

A line height of factor times the largest font size of each line; 1.25 by default.

setSpacingBefore​

void setSpacingBefore(float points)
void setSpacingAfter(float points)

Space before (dropped at the top of a page) and after.

setIndentationLeft​

void setIndentationLeft(float points)
void setIndentationRight(float points)
void setFirstLineIndent(float points)

setKeepTogether​

void setKeepTogether(boolean keep)

Moves the whole paragraph to the next page when it doesn't fit the rest of the page and fits on an empty one.

setKeepWithNext​

void setKeepWithNext(boolean keep)

Keeps the paragraph on the same page as the first line of the following element.

ItemList​

A bulleted or numbered list. Not called List, to avoid the clash with java.util.List.

ItemList(boolean numbered)

add​

ItemList add(String text)
ItemList add(Paragraph item)

setSymbol​

void setSymbol(String symbol)

The bullet, • by default. Numbered lists use 1., 2., …

setIndentation​

void setIndentation(float points)

Distance of the item text from the symbol, 20 points by default.

Table​

A table of cells, filled row by row. Cells added as String, Phrase or Cell all take the values they don't set from the default cell, as it is when they are added.

Table(int columns)
Table(float[] relativeWidths)

setWidthPercentage​

void setWidthPercentage(float percent)

Percentage of the content width, 80 by default.

setTotalWidth​

void setTotalWidth(float points)

An absolute width, which wins over the percentage.

setHorizontalAlignment​

void setHorizontalAlignment(int alignment)

Placement of the table, Element.ALIGN_CENTER by default.

setHeaderRows​

void setHeaderRows(int rows)

The first rows, repeated at the top of each page.

getDefaultCell​

Cell getDefaultCell()

The default values of the cells added after: padding 2, a 0.5-point black box border, left and top aligned, colspan 1. Changing it affects only the cells added afterwards, so a header can be added with one default and the body with another.

addCell​

void addCell(String text)
void addCell(Phrase phrase)
void addCell(Cell cell)
void addCell(Image image)

Adds a copy of the cell: changing a Cell after adding it has no effect.

setSpacingBefore​

void setSpacingBefore(float points)
void setSpacingAfter(float points)

setAlternateRowColor​

void setAlternateRowColor(Color color)

The background of every second body row, counted from the first body row across pages.

completeRow​

void completeRow()

Fills the current row with empty cells. An incomplete last row is completed automatically.

Cell​

A table cell. Every property not set takes the value the table's default cell has when the cell is added.

Cell(String text)
Cell(Phrase phrase)
Cell(Paragraph paragraph)
Cell(Image image)

An image is scaled down to the cell's width.

Cell constants​

int NO_BORDER, TOP, BOTTOM, LEFT, RIGHT, BOX

Border sides, combined in a mask.

setColspan​

void setColspan(int columns)

setHorizontalAlignment​

void setHorizontalAlignment(int alignment)
void setVerticalAlignment(int alignment)

ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFIED; vertically ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM.

setPadding​

void setPadding(float points)
void setPaddingLeft(float points)
void setPaddingRight(float points)
void setPaddingTop(float points)
void setPaddingBottom(float points)

setBackgroundColor​

void setBackgroundColor(Color color)

setBorder​

void setBorder(int mask)
void setBorderWidth(float points)
void setBorderColor(Color color)

setMinimumHeight​

void setMinimumHeight(float points)

setNoWrap​

void setNoWrap(boolean noWrap)

Keeps each line of text on one line, clipped to the cell.

Image​

An image, as a block or in a cell. JPEG files are embedded as they are; other files, and a BufferedImage without a quality, are converted losslessly. Unscaled, 1 pixel is 1 point; an image larger than the content area is scaled down to fit.

getInstance​

static Image getInstance(File file) throws IOException
static Image getInstance(String path) throws IOException
static Image getInstance(byte[] data) throws IOException
static Image getInstance(BufferedImage image)
static Image getInstance(BufferedImage image, float jpegQuality)

A path is a local file; URLs aren't fetched. With a JPEG quality (0.8 for photos and camera frames), a BufferedImage is embedded as JPEG; without it, losslessly, which suits charts and screenshots but makes a photo several MB per page.

scaleToFit​

void scaleToFit(float width, float height)
void scalePercent(float percent)
void scaleAbsolute(float width, float height)

setAlignment​

void setAlignment(int alignment)
void setSpacingBefore(float points)
void setSpacingAfter(float points)

LineSeparator​

LineSeparator(float widthPercent, float thickness, Color color)

A horizontal rule, centered.

Spacer​

Spacer(float points)

Vertical space.

PageBreak​

PageBreak()

A forced page break, like newPage(): a break at the end of the document adds no page.

Drawing​

A block of the given height in the flow, as wide as the content area, drawn by a callback. It moves to the next page if it doesn't fit; the engine saves and restores the graphics state around the callback.

Drawing(float height, ContentStreamPainter painter)
interface ContentStreamPainter { void paint(PDPageContentStream cs, PDRectangle box) throws IOException; }

PDFBox drawing in PDF coordinates (origin at the bottom left); box is the block's rectangle.

graphics2D​

static Drawing graphics2D(float height, Graphics2DPainter painter)
interface Graphics2DPainter { void paint(Graphics2D g, float width, float height) throws IOException; }

Java2D drawing, with the origin at the top left of the block, in points. The output is vector graphics. Text in the SansSerif, Dialog, Arial or Helvetica fonts is written as real text in Liberation Sans; other fonts become outlines. Text metrics come from AWT. A drawing taller than the content area is scaled down to fit.

PageDecorator​

decorate​

void decorate(PageContext context) throws IOException

Called at save() for each page. An exception stops save().

PageContext​

The page a PageDecorator draws on, in PDF points from the page's bottom-left corner.

getPageNumber​

int getPageNumber()
int getPageCount()

getContentStream​

PDPageContentStream getContentStream()

PDFBox drawing over the page.

getPageRectangle​

PDRectangle getPageRectangle()
PDRectangle getContentRectangle()

The whole page, and the area inside its margins.

showText​

void showText(String text, float x, float y, Font font, int alignment) throws IOException

One line of text with its baseline at y, its left end, center or right end at x for ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT.

Element​

The interface of everything Document.add() accepts.

Element constants​

int ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, ALIGN_JUSTIFIED, ALIGN_TOP, ALIGN_MIDDLE, ALIGN_BOTTOM