Render to PDF and Images

Axyra Sheets includes a full rendering pipeline that lays out pages much like a spreadsheet application, honoring page setup, print areas, scaling, fonts, borders, charts, and images, and exports the result to PDF or image formats.

A PDF in one line

try (Workbook wb = Workbook.open(Path.of("report.xlsx"))) {
    wb.renderPdf(Path.of("report.pdf"));
}

Controlling the output

PdfOptions is a builder. Everything is optional.

import io.keikai.axyra.sheets.io.PdfOptions;

PdfOptions options = PdfOptions.builder()
        .title("Q3 Report")
        .author("Finance")
        .sheetNames("Summary", "Detail")   // only these sheets
        .pageRange("1-4")                  // only these pages
        .watermark("CONFIDENTIAL")
        .bookmarks(true)                   // one outline entry per sheet
        .build();

wb.renderPdf(Path.of("report.pdf"), options);

To render into memory instead of onto disk:

byte[] pdf = wb.renderPdf(options);

Encryption and permissions

PdfOptions locked = PdfOptions.builder()
        .userPassword("open-me")     // required to open the document
        .ownerPassword("owner")      // required to change permissions
        .allowPrint(true)
        .allowCopy(false)
        .allowModify(false)
        .build();

Archival output

.pdfA(true) produces PDF/A output — fonts fully embedded, no encryption, no transparency. It cannot be combined with the password options above.

Fonts

Rendering needs the fonts the workbook asks for. Point the engine at your font directories when the defaults are not enough:

PdfOptions.builder().fontDirs(List.of("/usr/share/fonts", "/opt/corp-fonts")).build();

The renderer scans the usual macOS and Linux font directories, but not C:\Windows\Fonts; on Windows, pass that folder (or your application’s font folder) in fontDirs. Metric-compatible substitutes are bundled for Calibri (Carlito), Cambria (Caladea), and Arial (Liberation Sans). Other missing fonts fall back to a different font, which changes line breaks, and CJK text needs CJK fonts (such as Noto) installed. If output must be pixel-stable across machines, ship the fonts.

Images

Per sheet, to any of six raster or vector formats:

import io.keikai.axyra.sheets.io.ImageOptions;
import io.keikai.axyra.sheets.io.Renderer;

ImageOptions image = ImageOptions.builder()
        .scale(2.0)          // 2× the nominal size
        .gridLines(true)     // draw grid lines even if the sheet hides them
        .page(1)             // one page of a multi-page sheet
        .build();

int summary = wb.sheet("Summary").index();   // look the sheet up by name

byte[] png = wb.renderSheetPng(summary, image);
byte[] svg = wb.renderSheetSvg(summary, image);

// The Renderer facade covers the rest
byte[] jpg  = Renderer.toJpeg(wb, summary, image);
byte[] tiff = Renderer.toTiff(wb, summary, image);

The methods take a sheet index. Resolve it from the sheet name: a file saved in Evaluation Mode starts with an extra Axyra Evaluation Copy sheet, so index 0 is not necessarily your first sheet.

Use scale(...) for a multiple of the nominal size, or targetWidthPx(...) to pin the output to an exact pixel width and let the engine derive the scale.

Page count

Useful for progress reporting, or for splitting a large render into chunks:

int pages = wb.sheetPageCount(wb.sheet("Summary").index());

HTML

Not a render, strictly — HTML export reproduces the sheet as a styled table rather than as paginated output. It is the right choice for previewing a sheet in a browser.

import io.keikai.axyra.sheets.io.HtmlOptions;

// The package shape Excel's "Save as Web Page" writes — report.html plus a
// report_files/ sidecar holding each sheet, the stylesheet and the images.
wb.saveHtml(Path.of("report.html"), HtmlOptions.create());

// Or one self-contained file: every sheet in it, every image inlined.
wb.saveHtml(Path.of("report.html"), HtmlOptions.create().singleFile(true));

The package is the default for a path, and the shape a multi-sheet workbook needs for its sheet tabs to work. Pick the single document when the file has to travel on its own.

Next

Get code at GitHub