use oxidize_pdf::{Color, Document, Font, Page, Result};
use std::env;
use std::time::Instant;
fn main() -> Result<()> {
let args: Vec<String> = env::args().collect();
let page_count = if args.len() > 1 {
args[1].parse().unwrap_or(50)
} else {
50
};
let start_time = Instant::now();
let mut doc = Document::new();
doc.set_title("Sales Report - Medium Complexity Benchmark");
doc.set_author("oxidize-pdf Performance Test");
let regions = [
"North America",
"Europe",
"Asia-Pacific",
"Latin America",
"Middle East",
"Africa",
"Oceania",
];
let products = [
"Product Alpha",
"Product Beta",
"Product Gamma",
"Product Delta",
"Product Epsilon",
"Product Zeta",
"Product Omega",
];
let sales_reps = [
"John Smith",
"Maria Garcia",
"Chen Wei",
"Ahmed Hassan",
"Anna Mueller",
"Sarah Johnson",
"David Brown",
"Lisa Wang",
"Carlos Rodriguez",
"Emma Thompson",
];
for page_num in 0..page_count {
let mut page = Page::a4();
let mut y_pos = 790.0;
page.graphics()
.set_fill_color(Color::rgb(0.0, 0.4, 0.8))
.rectangle(50.0, y_pos - 30.0, 100.0, 25.0)
.fill();
page.text()
.set_font(Font::HelveticaBold, 12.0)
.set_fill_color(Color::white())
.at(60.0, y_pos - 20.0)
.write("ACME CORP")?;
page.text()
.set_font(Font::HelveticaBold, 18.0)
.set_fill_color(Color::rgb(0.0, 0.4, 0.8))
.at(200.0, y_pos - 15.0)
.write("Q3 2025 Sales Report")?;
page.text()
.set_font(Font::Helvetica, 10.0)
.set_fill_color(Color::rgb(0.3, 0.3, 0.3))
.at(450.0, y_pos - 15.0)
.write(&format!("Report #{} - Sept 2025", page_num + 1))?;
y_pos -= 50.0;
page.graphics()
.set_stroke_color(Color::rgb(0.0, 0.4, 0.8))
.set_line_width(1.0)
.move_to(50.0, y_pos)
.line_to(545.0, y_pos)
.stroke();
y_pos -= 20.0;
page.text()
.set_font(Font::HelveticaBold, 14.0)
.at(50.0, y_pos)
.write(&format!("Page {} - Regional Sales Data", page_num + 1))?;
y_pos -= 25.0;
page.graphics()
.set_fill_color(Color::rgb(0.9, 0.9, 0.9))
.rectangle(50.0, y_pos - 15.0, 495.0, 20.0)
.fill();
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(55.0, y_pos - 5.0)
.write("Region")?;
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(150.0, y_pos - 5.0)
.write("Product")?;
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(250.0, y_pos - 5.0)
.write("Sales Rep")?;
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(350.0, y_pos - 5.0)
.write("Q3 Sales")?;
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(450.0, y_pos - 5.0)
.write("Growth %")?;
page.text()
.set_font(Font::HelveticaBold, 10.0)
.at(510.0, y_pos - 5.0)
.write("Status")?;
y_pos -= 25.0;
let row_count = 18 + (page_num % 7); for row in 0..row_count {
let region_idx = (page_num * 7 + row * 3) % regions.len();
let product_idx = (page_num * 11 + row * 5) % products.len();
let rep_idx = (page_num * 13 + row * 7) % sales_reps.len();
let region = regions[region_idx];
let product = products[product_idx];
let sales_rep = sales_reps[rep_idx];
let base_sales = 45000 + (page_num * 5000);
let sales = base_sales + (row * 3456) + ((page_num * row * 123) % 150000);
let growth = -20.0 + ((page_num as f32 * 3.7 + row as f32 * 1.9) % 45.0);
let status = if growth > 10.0 {
"🟢 Good"
} else if growth > 0.0 {
"🟡 Fair"
} else {
"🔴 Low"
};
if row % 2 == 0 {
page.graphics()
.set_fill_color(Color::rgb(0.98, 0.98, 0.98))
.rectangle(50.0, y_pos - 12.0, 495.0, 15.0)
.fill();
}
page.text()
.set_font(Font::Helvetica, 9.0)
.at(55.0, y_pos - 5.0)
.write(region)?;
page.text()
.set_font(Font::Helvetica, 9.0)
.at(150.0, y_pos - 5.0)
.write(product)?;
page.text()
.set_font(Font::Helvetica, 9.0)
.at(250.0, y_pos - 5.0)
.write(sales_rep)?;
page.text()
.set_font(Font::CourierBold, 9.0)
.at(350.0, y_pos - 5.0)
.write(&format!("${}", sales))?;
page.text()
.set_font(Font::Courier, 9.0)
.set_fill_color(if growth > 0.0 {
Color::rgb(0.0, 0.6, 0.0)
} else {
Color::rgb(0.8, 0.0, 0.0)
})
.at(430.0, y_pos - 5.0)
.write(&format!("{:+.1}%", growth))?;
page.text()
.set_font(Font::Helvetica, 8.0)
.at(480.0, y_pos - 5.0)
.write(status)?;
y_pos -= 15.0;
}
if (page_num + 1) % 3 == 0 {
y_pos -= 20.0;
let chart_type = (page_num / 3) % 3;
let chart_title = match chart_type {
0 => "Regional Performance Comparison",
1 => "Product Sales Distribution",
_ => "Quarterly Growth Trends",
};
page.text()
.set_font(Font::HelveticaBold, 12.0)
.set_fill_color(Color::rgb(0.1, 0.1, 0.1))
.at(50.0, y_pos)
.write(&format!("{} - Page {}", chart_title, page_num + 1))?;
y_pos -= 30.0;
page.graphics()
.set_fill_color(Color::rgb(0.97, 0.97, 0.98))
.rectangle(50.0, y_pos - 100.0, 495.0, 95.0)
.fill();
for i in 0..5 {
let grid_y = y_pos - (i as f64 * 20.0);
page.graphics()
.set_stroke_color(Color::rgb(0.85, 0.85, 0.85))
.set_line_width(0.5)
.move_to(70.0, grid_y)
.line_to(530.0, grid_y)
.stroke();
}
let chart_width = 400.0;
let num_bars = 6;
let bar_width = chart_width / num_bars as f64;
for i in 0..num_bars {
let base_performance = 25.0 + (page_num as f64 * 3.0);
let bar_height =
base_performance + (i as f64 * 7.0) + ((page_num * (i + 1) * 17) as f64 % 30.0);
let x = 70.0 + (i as f64 * bar_width);
for j in 0..5 {
let segment_height = bar_height / 5.0;
let segment_y = y_pos - bar_height + (j as f64 * segment_height);
let alpha = 0.4 + ((5 - j) as f64 * 0.12);
let color_shift = (page_num as f64 * 0.07 + i as f64 * 0.11) % 1.0;
page.graphics()
.set_fill_color(Color::rgb(
(0.2 + color_shift * 0.3) * alpha,
(0.5 + color_shift * 0.2) * alpha,
(0.9 - color_shift * 0.3) * alpha,
))
.rectangle(x + 10.0, segment_y, bar_width - 25.0, segment_height)
.fill();
}
page.graphics()
.set_stroke_color(Color::rgb(0.3, 0.3, 0.5))
.set_line_width(1.0)
.rectangle(x + 10.0, y_pos - bar_height, bar_width - 25.0, bar_height)
.stroke();
let value = (bar_height * 2.5 + page_num as f64 * 75.0 + i as f64 * 120.0) as u32;
page.text()
.set_font(Font::HelveticaBold, 8.0)
.set_fill_color(Color::rgb(0.1, 0.1, 0.3))
.at(x + bar_width / 2.0 - 12.0, y_pos - bar_height - 12.0)
.write(&format!("${}", value))?;
let sparkline_y = y_pos + 5.0;
let sparkline_width = bar_width - 30.0;
let num_points = 6;
let mut last_x = x + 12.0;
let mut last_y =
sparkline_y - ((page_num * (i + 1) * 7) % 15) as f64 - ((i * 2) as f64);
for p in 1..num_points {
let px = x + 12.0 + (p as f64 * (sparkline_width / num_points as f64));
let trend_val = ((page_num * (p + 1) * (i + 1) * 13) % 15) as f64;
let py = sparkline_y - trend_val - ((i * 2) as f64);
page.graphics()
.set_stroke_color(Color::rgb(0.4, 0.6, 0.8))
.set_line_width(1.5)
.move_to(last_x, last_y)
.line_to(px, py)
.stroke();
last_x = px;
last_y = py;
}
let label_text = match chart_type {
0 => {
let region_idx = (page_num * 3 + i) % regions.len();
regions[region_idx]
}
1 => {
let product_idx = (page_num * 5 + i) % products.len();
products[product_idx]
}
_ => &format!("Q{}", i + 1),
};
page.text()
.set_font(Font::Helvetica, 7.0)
.set_fill_color(Color::rgb(0.2, 0.2, 0.2))
.at(x + 5.0, y_pos + 20.0)
.write(label_text)?;
}
}
let report_id = format!("RPT-{:04}-{:03}", 2025, page_num + 1);
page.text()
.set_font(Font::Helvetica, 8.0)
.set_fill_color(Color::rgb(0.4, 0.4, 0.4))
.at(50.0, 30.0)
.write(&format!("CONFIDENTIAL - {} - ACME Corp", report_id))?;
page.text()
.set_font(Font::Helvetica, 8.0)
.set_fill_color(Color::rgb(0.4, 0.4, 0.4))
.at(450.0, 30.0)
.write(&format!("Page {} of {}", page_num + 1, page_count))?;
page.graphics()
.set_stroke_color(Color::rgb(0.8, 0.8, 0.8))
.set_line_width(0.5)
.rectangle(40.0, 40.0, 515.0, 760.0)
.stroke();
doc.add_page(page);
}
let generation_time = start_time.elapsed();
let write_start = Instant::now();
doc.save("examples/results/medium_complexity_benchmark.pdf")?;
let write_time = write_start.elapsed();
let total_time = start_time.elapsed();
println!("PAGES={}", page_count);
println!("GENERATION_MS={}", generation_time.as_millis());
println!("WRITE_MS={}", write_time.as_millis());
println!("TOTAL_MS={}", total_time.as_millis());
println!(
"PAGES_PER_SEC={:.2}",
page_count as f64 / total_time.as_secs_f64()
);
println!("COMPLEXITY=MEDIUM");
println!("\n📊 Medium Complexity Benchmark Results:");
println!(" 📄 Pages: {}", page_count);
println!(" ⚡ Generation: {}ms", generation_time.as_millis());
println!(" 💾 Write: {}ms", write_time.as_millis());
println!(" 🕐 Total: {}ms", total_time.as_millis());
println!(
" 📈 Performance: {:.1} pages/second",
page_count as f64 / total_time.as_secs_f64()
);
println!(" 📋 Content: Sales tables + charts + graphics per page");
Ok(())
}