Attach any file (XML, CSV, XLSX, images) as an embedded file stream inside a PDF. The attachment travels with the document and can be extracted by any conforming viewer.
use pdfluent::{PdfDocument, FileAttachment};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut doc = PdfDocument::open("invoice.pdf")?;
doc.attach_file(
FileAttachment::from_file("invoice_data.xml")?
.description("Machine-readable invoice data (ZUGFeRD)")
.mime_type("application/xml"),
)?;
doc.save("invoice_with_attachment.pdf")?;
println!("File attached.");
Ok(())
}Add the pdfluent crate to Cargo.toml.
[dependencies]
pdfluent = "0.9"Load the document that will receive the attachment.
use pdfluent::PdfDocument;
let mut doc = PdfDocument::open("invoice.pdf")?;FileAttachment::from_file() reads the file bytes, determines a filename, and sets a creation date. All fields can be overridden.
use pdfluent::FileAttachment;
let attachment = FileAttachment::from_file("supporting_data.csv")?
.description("Raw data used to generate the figures in this report")
.mime_type("text/csv")
.filename("data.csv");If the file content is already in memory, use FileAttachment::from_bytes() instead.
let xml_bytes = generate_xml_data(); // your function
let attachment = FileAttachment::from_bytes(xml_bytes)
.filename("invoice.xml")
.mime_type("application/xml")
.description("ZUGFeRD structured invoice data");attach_file() embeds the file in the document-level EmbeddedFiles name tree. Save afterwards.
doc.attach_file(attachment)?;
// Verify
println!("Attached files: {}", doc.attachments().len());
doc.save("invoice_with_attachment.pdf")?;No JVM, no runtime, no DLL dependencies. Ships as a single native binary or WASM module.
Rust's ownership model prevents buffer overflows and use-after-free. No segfaults in PDF parsing.
Same code runs server-side, in Docker, on AWS Lambda, on Cloudflare Workers, or in the browser via WASM.