1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
extern crate pdf;
use std::env::args;
use std::fmt;
use std::collections::HashMap;
use pdf::file::{FileOptions};
use pdf::object::*;
use pdf::primitive::{Primitive, PdfString};
struct Indent(usize);
impl fmt::Display for Indent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for _ in 0 .. self.0 {
write!(f, " ")?;
}
Ok(())
}
}
fn walk_outline(r: &impl Resolve, mut node: RcRef<OutlineItem>, name_map: &impl Fn(&str) -> usize, page_map: &impl Fn(PlainRef) -> usize, depth: usize) {
let indent = Indent(depth);
loop {
if let Some(ref title) = node.title {
println!("{}title: {:?}", indent, title.to_string_lossy());
}
if let Some(ref dest) = node.dest {
match dest {
Primitive::String(ref s) => {
let name = s.to_string_lossy();
let page_nr = name_map(&name);
println!("{}dest: {:?} -> page nr. {:?}", indent, name, page_nr);
}
Primitive::Array(ref a) => match a[0] {
Primitive::Reference(r) => {
let page_nr = page_map(r);
println!("{}dest: {:?} -> page nr. {:?}", indent, a, page_nr);
}
_ => unimplemented!("invalid reference in array"),
}
_ => unimplemented!("invalid dest"),
}
}
if let Some(Action::Goto(MaybeNamedDest::Direct(Dest { page: Some(page), ..}))) = node.action {
let page_nr = page_map(page.get_inner());
println!("{}action -> page nr. {:?}", indent, page_nr);
}
if let Some(ref a) = node.se {
println!("{} -> {:?}", indent, a);
}
if let Some(entry_ref) = node.first {
let entry = r.get(entry_ref).unwrap();
walk_outline(r, entry, name_map, page_map, depth + 1);
}
if let Some(entry_ref) = node.next {
node = r.get(entry_ref).unwrap();
continue;
}
break;
}
}
#[cfg(feature="cache")]
fn main() {
let path = args().nth(1).expect("no file given");
println!("read: {}", path);
let file = FileOptions::cached().open(&path).unwrap();
let resolver = file.resolver();
let catalog = file.get_root();
let mut pages_map: HashMap<String, PlainRef> = HashMap::new();
let mut count = 0;
let mut dests_cb = |key: &PdfString, val: &Option<Dest>| {
//println!("{:?} {:?}", key, val);
if let Some(Dest { page: Some(page), ..}) = val {
pages_map.insert(key.to_string_lossy(), page.get_inner());
}
count += 1;
};
if let Some(ref names) = catalog.names {
if let Some(ref dests) = names.dests {
dests.walk(&resolver, &mut dests_cb).unwrap();
}
}
let mut pages = HashMap::new();
fn add_tree(r: &impl Resolve, pages: &mut HashMap<PlainRef, usize>, tree: &PageTree, current_page: &mut usize) {
for &node_ref in &tree.kids {
let node = r.get(node_ref).unwrap();
match *node {
PagesNode::Tree(ref tree) => {
add_tree(r, pages, tree, current_page);
}
PagesNode::Leaf(ref _page) => {
pages.insert(node_ref.get_inner(), *current_page);
*current_page += 1;
}
}
}
}
add_tree(&resolver, &mut pages, &catalog.pages, &mut 0);
let get_page_nr = |name: &str| -> usize {
let page = pages_map[name];
pages[&page]
};
let page_nr = |r: PlainRef| -> usize {
pages[&r]
};
if let Some(ref outlines) = catalog.outlines {
if let Some(entry_ref) = outlines.first {
let entry = resolver.get(entry_ref).unwrap();
walk_outline(&resolver, entry, &get_page_nr, &page_nr, 0);
}
}
println!("{} items", count);
}
|