| Crates.io | carbonpdf |
| lib.rs | carbonpdf |
| version | 0.2.0 |
| created_at | 2026-01-02 21:21:30.5616+00 |
| updated_at | 2026-01-08 17:17:15.003431+00 |
| description | Production-ready HTML to PDF conversion using Headless Chrome |
| homepage | |
| repository | https://github.com/RockyCott/carbonpdf |
| max_upload_size | |
| id | 2019219 |
| size | 152,728 |
Production-ready HTML to PDF conversion in Rust using Headless Chrome.
Chrome or Chromium must be installed and accessible. CarbonPDF will automatically detect Chrome in standard locations, or you can specify a custom path.
On Ubuntu/Debian:
sudo apt-get install chromium-browser
On Arch Linux:
sudo pacman -S chromium
On macOS:
brew install --cask google-chrome
On Windows: Download from google.com/chrome
Add to your Cargo.toml:
[dependencies]
carbonpdf = "0.1"
tokio = { version = "1", features = ["full"] }
use carbonpdf::{PdfBuilder, PageSize, Result};
#[tokio::main]
async fn main() -> Result<()> {
// Convert HTML string to PDF
let pdf = PdfBuilder::new()
.html("<h1>Hello, CarbonPDF!</h1><p>Easy PDF generation.</p>")
.page_size(PageSize::A4)
.margin_all(1.0)
.build()
.await?;
std::fs::write("output.pdf", pdf)?;
Ok(())
}
let pdf = PdfBuilder::new()
.file("invoice.html")
.page_size(PageSize::Letter)
.build()
.await?;
let pdf = PdfBuilder::new()
.url("https://example.com")
.build()
.await?;
CarbonPDF includes optional Handlebars templating support for custom templates with variables.
Add the templates feature to your Cargo.toml:
[dependencies]
carbonpdf = { version = "0.2", features = ["templates"] }
Use your own Handlebars templates:
use carbonpdf::{PdfBuilder, Result};
use serde_json::json;
#[tokio::main]
async fn main() -> Result<()> {
let template = r#"
<h1>{{title}}</h1>
<p>Hello {{name}}, your order #{{order_id}} is confirmed!</p>
<ul>
{{#each items}}
<li>{{this}}</li>
{{/each}}
</ul>
"#;
let data = json!({
"title": "Order Confirmation",
"name": "Sevani",
"order_id": "12345",
"items": ["Product A", "Product B", "Product C"]
});
let pdf = PdfBuilder::new()
.template(template, data)?
.build()
.await?;
std::fs::write("output.pdf", pdf)?;
Ok(())
}
CarbonPDF includes custom Handlebars helpers:
{{format_currency value symbol}} - Format currency values{{format_date date_string}} - Format datesExample:
<p>Total: {{format_currency 1234.56 "$"}}</p>
<!-- Outputs: Total: $1234.56 -->
use carbonpdf::{PdfBuilder, PageSize, Orientation};
let pdf = PdfBuilder::new()
.html(html_content)
.page_size(PageSize::A4)
.orientation(Orientation::Landscape)
.margins(0.5, 0.75, 0.5, 0.75) // top, right, bottom, left (inches)
.scale(0.9)
.print_background(true)
.header("<div style='font-size: 10px;'>Page <span class='pageNumber'></span></div>")
.footer("<div style='text-align: center;'>© 2024 Your Company</div>")
.timeout(60) // seconds
.build()
.await?;
let pdf = PdfBuilder::new()
.html(content)
.custom_page_size(8.5, 14.0) // width, height in inches
.build()
.await?;
let pdf = PdfBuilder::new()
.html(content)
.no_sandbox() // Required in Docker
.chrome_args(["--disable-dev-shm-usage"])
.build()
.await?;
Install the CLI:
cargo install carbonpdf --features cli
Usage:
# Convert HTML file
carbonpdf input.html -o output.pdf
# Convert from URL
carbonpdf https://example.com -o example.pdf
# With options
carbonpdf input.html -o output.pdf \
--page-size A4 \
--landscape \
--margin 1.0 \
--scale 0.9
CarbonPDF uses a layered architecture:
PdfRenderer trait for backend implementationsSee ARCHITECTURE.md for detailed design documentation.
CarbonPDF provides detailed error types:
use carbonpdf::Error;
match pdf_result {
Ok(pdf) => println!("Success!"),
Err(Error::ChromeProcess(msg)) => eprintln!("Chrome error: {}", msg),
Err(Error::Timeout(secs)) => eprintln!("Timed out after {}s", secs),
Err(Error::InvalidConfig(msg)) => eprintln!("Config error: {}", msg),
Err(e) => eprintln!("Error: {}", e),
}
// Reuse renderer instance across requests
lazy_static! {
static ref RENDERER: ChromeRenderer = {
ChromeRenderer::new(ChromeConfig::default())
.await
.expect("Failed to initialize Chrome")
};
}
async fn generate_invoice(html: String) -> Result<Vec<u8>> {
RENDERER.render(
InputSource::html(html),
PdfConfig::default()
).await
}
# Dockerfile
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y \
chromium \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/myapp /usr/local/bin/
CMD ["myapp"]
// In your code
let pdf = PdfBuilder::new()
.html(content)
.no_sandbox() // Required in Docker
.chrome_args(["--disable-dev-shm-usage"])
.build()
.await?;
Contributions welcome! Please see CONTRIBUTING.md.
Licensed under either of:
at your option.
Built on the shoulders of giants: