| Crates.io | laser-pdf |
| lib.rs | laser-pdf |
| version | 0.1.1 |
| created_at | 2025-06-11 17:57:38.726333+00 |
| updated_at | 2025-06-11 18:26:45.046372+00 |
| description | A Rust library for programmatic PDF generation with precise, predictable layout control. |
| homepage | |
| repository | https://github.com/laser-pdf/laser-pdf |
| max_upload_size | |
| id | 1708895 |
| size | 893,122 |
A Rust library for programmatic PDF generation with precise, predictable layout control.
laser-pdf is designed for applications that need to reproduce layouts with pixel-perfect accuracy, providing fine-grained control over page breaking and element positioning. Built for Escola to generate complex PDFs with predictable behavior.
Titled, RepeatAfterBreak, and PinBelow for exact control over multi-page layoutsUnlike CSS, which can sometimes produce unexpected layouts, laser-pdf prioritizes predictability. Once you understand the relatively simple Element trait, you can easily predict how layouts will behave. Elements follow clear composition rules, and the collapse behavior is well-defined and consistent.
(These instructions might need some work. Don't fully trust them yet.)
(A simple function convenient multi-page generation is still missing.)
use laser_pdf::*;
use laser_pdf::elements::{text::Text, column::Column, padding::Padding};
use laser_pdf::fonts::builtin::BuiltinFont;
// Create a PDF document
let mut pdf = Pdf::new();
// Add a page
let location = pdf.add_page((210., 297.)); // A4 size in mm
// Create fonts
let font = BuiltinFont::helvetica(&mut pdf);
// Build elements
let title = Text::basic("Document Title", &font, 16.0);
let body = Text::basic("This is the document body content.", &font, 12.0);
// Compose layout
let content = Column {
gap: 10.0,
collapse: true,
content: |content| {
content
.add(&Padding::all(title, 5.0))?
.add(&body)?;
// Returns an option to support short-circuiting.
None
}
};
// Draw to PDF
let ctx = DrawCtx {
pdf: &mut pdf,
width: WidthConstraint { max: 200.0, expand: true },
location,
first_height: 280.0,
preferred_height: None,
breakable: None, // For single-page layout
};
content.draw(ctx);
// Save PDF
std::fs::write("output.pdf", pdf.finish())?;
echo '{
"title": "My Document",
"entries": [{
"size": [210, 297],
"fonts": {
"regular": "./fonts/regular.ttf"
},
"element": {
"type": "Column",
"gap": 10,
"content": [
{
"type": "Text",
"text": "Hello, World!",
"font": "regular",
"size": 16
}
]
}
}]
}' | cargo run > output.pdf
All layout components implement the Element trait with three key methods:
first_location_usage(): Determines if the element will use the first location on a pagemeasure(): Calculates dimensions given width constraintsdraw(): Renders the element to the PDFElements can intelligently break across pages using the breakable draw context. Advanced elements like Titled ensure titles stay with their content, while RepeatAfterBreak can repeat headers on each page.
Elements can collapse on each axis independently. When an element collapses in the direction of a container (like a Column), gaps around it are eliminated - similar to how display: none interacts with CSS Grid's gap property.
Column / Row: Vertical/horizontal stacking with gapsStack: Layered positioningPadding: Add space around elementsHAlign: Horizontal alignment controlText: Simple text rendering with built-in fontsRichText: Advanced text with TrueType fonts and text shapingImage: Raster image embeddingSVG: Vector graphics renderingRectangle / Circle: Basic shapesPage: Force page boundaryForceBreak: Insert page breaksBreakWhole: Keep element groups togetherTitled: Keep titles with contentRepeatAfterBreak: Repeat elements after page breaksPinBelow: Pin elements to page bottomShrinkToFit: Scale content to fit constraintsExpandToPreferredHeight: Grow to fill available spaceChangingTitle: Dynamic page titles⚠️ Pre-1.0: The library is under active development. While used in production at Escola, the API may change before the 1.0 release. Element names and some APIs are still being refined.
Roadmap to 1.0:
cargo build --verbose
# Run all tests
cargo test --verbose
# Run specific test
cargo test test_name
# Update snapshots
cargo insta review
The project uses insta for snapshot testing, including binary PDF snapshots for visual regression testing.
Licensed under the MIT License.
Built with ❤️ for precise, predictable PDF layouts