A Rust library for PDF document manipulation.
Clone or download
Latest commit d5d1087 Dec 12, 2018
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode Disable auto format markdown Feb 4, 2018
assets insert image on page Sep 20, 2018
benches Format code with rustfmt Oct 8, 2018
examples Format code with rustfmt Oct 8, 2018
pdfutil Add extract_stream subcommand Sep 17, 2018
src Use pom 3.0 Dec 12, 2018
tests Format code with rustfmt Oct 8, 2018
.editorconfig Release 0.8.0 Mar 16, 2017
.gitignore impl Document add_object method Dec 20, 2016
.travis.yml Make chrono crate optional Sep 19, 2018
Cargo.toml Use pom 3.0 Dec 12, 2018
LICENSE Initial commit Dec 13, 2016
README.md Update example code Apr 16, 2018
rustfmt.toml compress page content after change Sep 18, 2018



Crates.io Build Status

A Rust library for PDF document manipulation.

Example Code

  • Create PDF document
extern crate lopdf;
use lopdf::{Document, Object, Stream};
use lopdf::content::{Content, Operation};

let mut doc = Document::with_version("1.5");
let pages_id = doc.new_object_id();
let font_id = doc.add_object(dictionary! {
	"Type" => "Font",
	"Subtype" => "Type1",
	"BaseFont" => "Courier",
let resources_id = doc.add_object(dictionary! {
	"Font" => dictionary! {
		"F1" => font_id,
let content = Content {
	operations: vec![
		Operation::new("BT", vec![]),
		Operation::new("Tf", vec!["F1".into(), 48.into()]),
		Operation::new("Td", vec![100.into(), 600.into()]),
		Operation::new("Tj", vec![Object::string_literal("Hello World!")]),
		Operation::new("ET", vec![]),
let content_id = doc.add_object(Stream::new(dictionary! {}, content.encode().unwrap()));
let page_id = doc.add_object(dictionary! {
	"Type" => "Page",
	"Parent" => pages_id,
	"Contents" => content_id,
let pages = dictionary! {
	"Type" => "Pages",
	"Kids" => vec![page_id.into()],
	"Count" => 1,
	"Resources" => resources_id,
	"MediaBox" => vec![0.into(), 0.into(), 595.into(), 842.into()],
doc.objects.insert(pages_id, Object::Dictionary(pages));
let catalog_id = doc.add_object(dictionary! {
	"Type" => "Catalog",
	"Pages" => pages_id,
doc.trailer.set("Root", catalog_id);
  • Modify PDF document
let mut doc = Document::load("example.pdf")?;
doc.version = "1.4".to_string();
doc.replace_text(1, "Hello World!", "Modified text!");


  • Why keeping everything in memory as high-level objects until finallay serializing the entire document?

    Normally a PDF document won't be very large, ranging form tens of KB to hundreds of MB. Memory size is not a bottle neck for today's computer. By keep the whole document in memory, stream length can be pre-calculated, no need to use a reference object for the Length entry, the resulting PDF file is smaller for distribution and faster for PDF consumers to process.

    Producing is a one-time effort, while consuming is many more.