use std::path::Path;
use std::process::ExitCode;
use pdfrum::{Document, FindOptions};
fn main() -> ExitCode {
let args: Vec<String> = std::env::args().skip(1).collect();
let Some(input) = args.first() else {
eprintln!("usage: extract-text <input.pdf> [search-term]");
return ExitCode::FAILURE;
};
match run(Path::new(input), args.get(1).map(String::as_str)) {
Ok(()) => ExitCode::SUCCESS,
Err(err) => {
eprintln!("error: {err}");
ExitCode::FAILURE
}
}
}
fn run(input: &Path, needle: Option<&str>) -> Result<(), pdfrum::Error> {
let doc = Document::open(input)?;
let mut session = pdfrum::RenderSession::new();
for page in doc.pages() {
let text = page.text_on(&mut session);
match needle {
None => {
let label = doc
.page_label(page.index())
.unwrap_or_else(|| (page.index().get() + 1).to_string());
println!("=== page {label} ({} chars) ===", text.char_count());
println!("{text}");
}
Some(needle) => {
for range in text.find(needle, FindOptions::default()) {
let (Some(from), Some(to)) = (
text.runs.char_index(range.start),
text.runs.char_index(range.end),
) else {
continue;
};
let rects = text.rects(from..to);
println!(
"page {} chars {from}..{to} in {} box(es)",
page.index().get() + 1,
rects.len()
);
for rect in rects {
println!(
" x {:.1}..{:.1} y {:.1}..{:.1}",
rect.x0, rect.x1, rect.y0, rect.y1
);
}
}
}
}
for link in text.web_links() {
println!("link: {}", link.url);
}
}
Ok(())
}