use rpdfium::{ArcDocument, ArcLibrary, Error, OpenOptions, Rect, RenderConfig, RgbaColor};
fn build_multi_page_pdf(page_count: usize) -> Vec<u8> {
let mut pdf = Vec::new();
pdf.extend_from_slice(b"%PDF-1.4\n");
let obj1_offset = pdf.len();
pdf.extend_from_slice(b"1 0 obj\n<< /Type /Catalog /Pages 2 0 R >>\nendobj\n");
let obj2_offset = pdf.len();
let kids: Vec<String> = (0..page_count).map(|i| format!("{} 0 R", i + 3)).collect();
let kids_str = kids.join(" ");
let pages_dict =
format!("2 0 obj\n<< /Type /Pages /Kids [{kids_str}] /Count {page_count} >>\nendobj\n");
pdf.extend_from_slice(pages_dict.as_bytes());
let mut page_offsets = Vec::new();
for i in 0..page_count {
let offset = pdf.len();
page_offsets.push(offset);
let obj_num = i + 3;
let page_obj = format!(
"{obj_num} 0 obj\n<< /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] >>\nendobj\n"
);
pdf.extend_from_slice(page_obj.as_bytes());
}
let xref_offset = pdf.len();
let total_objects = page_count + 3; pdf.extend_from_slice(b"xref\n");
pdf.extend_from_slice(format!("0 {total_objects}\n").as_bytes());
pdf.extend_from_slice(b"0000000000 65535 f \r\n");
pdf.extend_from_slice(format!("{:010} 00000 n \r\n", obj1_offset).as_bytes());
pdf.extend_from_slice(format!("{:010} 00000 n \r\n", obj2_offset).as_bytes());
for offset in &page_offsets {
pdf.extend_from_slice(format!("{:010} 00000 n \r\n", offset).as_bytes());
}
pdf.extend_from_slice(b"trailer\n");
pdf.extend_from_slice(format!("<< /Size {total_objects} /Root 1 0 R >>\n").as_bytes());
pdf.extend_from_slice(format!("startxref\n{xref_offset}\n%%EOF").as_bytes());
pdf
}
fn render_config() -> RenderConfig {
RenderConfig {
width: 100,
height: 100,
background: RgbaColor::WHITE,
media_box: Some(Rect::new(0.0, 0.0, 612.0, 792.0)),
rotation: 0,
tile_size: None,
progress: None,
grayscale: false,
antialiasing: true,
..RenderConfig::default()
}
}
#[test]
fn test_render_pages_parallel_basic() {
let lib = ArcLibrary::new();
let pdf = build_multi_page_pdf(3);
let opts = OpenOptions::default();
let doc = ArcDocument::open(&lib, pdf, &opts).unwrap();
let config = render_config();
let results = doc.render_pages_parallel(&[0, 1, 2], &config);
assert_eq!(results.len(), 3);
for result in &results {
let bitmap = result.as_ref().unwrap();
assert_eq!(bitmap.width, 100);
assert_eq!(bitmap.height, 100);
assert!(!bitmap.data.is_empty());
}
}
#[test]
fn test_render_all_pages_parallel() {
let lib = ArcLibrary::new();
let pdf = build_multi_page_pdf(5);
let opts = OpenOptions::default();
let doc = ArcDocument::open(&lib, pdf, &opts).unwrap();
let config = render_config();
let results = doc.render_all_pages_parallel(&config);
assert_eq!(results.len(), 5);
for result in &results {
assert!(result.is_ok());
}
}
#[test]
fn test_render_parallel_with_invalid_index() {
let lib = ArcLibrary::new();
let pdf = build_multi_page_pdf(3);
let opts = OpenOptions::default();
let doc = ArcDocument::open(&lib, pdf, &opts).unwrap();
let config = render_config();
let results = doc.render_pages_parallel(&[0, 99, 2], &config);
assert_eq!(results.len(), 3);
assert!(results[0].is_ok());
match &results[1] {
Err(Error::PageOutOfRange { index, count }) => {
assert_eq!(*index, 99);
assert_eq!(*count, 3);
}
other => panic!("expected PageOutOfRange, got {:?}", other),
}
assert!(results[2].is_ok());
}
#[test]
fn test_render_parallel_empty_indices() {
let lib = ArcLibrary::new();
let pdf = build_multi_page_pdf(3);
let opts = OpenOptions::default();
let doc = ArcDocument::open(&lib, pdf, &opts).unwrap();
let config = render_config();
let results = doc.render_pages_parallel(&[], &config);
assert!(results.is_empty());
}