Skip to content

Commit

Permalink
Merge pull request fschutt#141 from nubis/master
Browse files Browse the repository at this point in the history
Adds escape hatch for pages to add annotations
  • Loading branch information
fschutt authored Sep 13, 2023
2 parents e764df4 + b4151f4 commit b30ac08
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 0 deletions.
29 changes: 29 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ required-features = []
name = "svg"
required-features = ["svg"]

[[example]]
name = "annotations"
required-features = []

[[example]]
name = "hyperlink"
required-features = ["annotations"]
46 changes: 46 additions & 0 deletions examples/annotations.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//! Uses the extend_with feature to add a link to the page.
extern crate printpdf;

use printpdf::*;
use std::fs::File;
use std::io::BufWriter;
use lopdf::{
StringFormat::Literal,
Dictionary,
Object
};

fn main() {
let (doc, page1, layer1) =
PdfDocument::new("printpdf graphics test", Mm(210.0), Mm(297.0), "Layer 1");
let page = doc.get_page(page1);
let current_layer = page.get_layer(layer1);

let action = Dictionary::from_iter(vec![
("Type", "Action".into()),
("S", Object::Name(b"URI".to_vec())),
("URI", Object::String(b"https://github.com/fschutt/printpdf".to_vec(), Literal)),
]);

let annotation = Dictionary::from_iter(vec![
("Type", "Annot".into()),
("Subtype", Object::Name(b"Link".to_vec())),
("Rect", vec![20.into(), 580.into(), 300.into(), 560.into()].into()),
("C", vec![].into()),
("Contents", Object::String("Hello World".into(), Literal)),
("A", action.into()),
]);

let annotations = Dictionary::from_iter(vec![
("Annots", Object::Array(vec![annotation.into()]))
]);

page.extend_with(annotations);

let text = "There's an invisible annotation with a link covering this text.";
let font = doc.add_builtin_font(BuiltinFont::Helvetica).unwrap();
current_layer.use_text(text, 10.0, Mm(10.0), Mm(200.0), &font);

doc.save(&mut BufWriter::new(File::create("test_annotations.pdf").unwrap()))
.unwrap();
}
6 changes: 6 additions & 0 deletions src/pdf_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,6 +664,12 @@ impl PdfDocumentReference {
("Parent", Reference(pages_id)),
]);

if let Some(extension) = &page.extend_with {
for (key, value) in extension.iter() {
p.set(key.to_vec(), value.clone())
}
}

// this will collect the resources needed for rendering this page
let layers_temp = ocg_list.iter().find(|e| e.0 == idx).unwrap();
let (mut resources_page, layer_streams) =
Expand Down
13 changes: 13 additions & 0 deletions src/pdf_page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub struct PdfPage {
pub layers: Vec<PdfLayer>,
/// Resources used in this page
pub(crate) resources: PdfResources,
/// Extend the page with custom ad-hoc attributes, as an escape hatch to the low level lopdf library.
/// Can be used to add annotations to a page.
/// If your dictionary is wrong it will produce a broken PDF without warning or useful messages.
pub(crate) extend_with: Option<lopdf::Dictionary>,
}

/// A "reference" to the current page, allows for inner mutability
Expand All @@ -48,6 +52,7 @@ impl PdfPage {
height: height.into(),
layers: Vec::new(),
resources: PdfResources::new(),
extend_with: None
};

let initial_layer = PdfLayer::new(layer_name);
Expand Down Expand Up @@ -189,4 +194,12 @@ impl PdfPageReference {
layer,
}
}

#[inline]
pub fn extend_with(&self, dict: lopdf::Dictionary) {
let doc = self.document.upgrade().unwrap();
let mut doc = doc.borrow_mut();
let page = &mut doc.pages[self.page.0];
page.extend_with = Some(dict);
}
}

0 comments on commit b30ac08

Please sign in to comment.