ferrisume_core/export/
pdf.rs

1use std::fmt::Debug;
2use std::io;
3use std::io::Write;
4
5use anyhow::Result;
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8use wkhtmltopdf::{Orientation, PageSize, PdfApplication, Size};
9
10#[derive(Error, Debug)]
11pub enum PdfExportError {
12    #[error("Invalid paper size {0}")]
13    InvalidPaperSize(String),
14    #[error("Invalid margin definition '{0}'")]
15    InvalidMarginDefinition(String),
16    #[error("Invalid margin value: {0}")]
17    InvalidMarginValue(std::num::ParseFloatError),
18    #[error("Headless chrome error: {0}")]
19    HeadlessChromeError(#[from] anyhow::Error),
20    #[error("IO error: {0}")]
21    IoError(#[from] io::Error),
22    #[error("wkhtmltopdf error: {0}")]
23    WkHtmlToPdfError(#[from] wkhtmltopdf::Error),
24}
25
26#[derive(Serialize, Deserialize)]
27pub struct PdfExportOptions {
28    pub paper_size: String,
29    pub margins: Vec<String>,
30}
31
32pub fn export_to_pdf(
33    html_content: &str,
34    output_path: &str,
35    options: &PdfExportOptions,
36) -> Result<(), PdfExportError> {
37    let pdf_app = PdfApplication::new()?;
38
39    let mut pdf = &mut pdf_app.builder();
40
41    pdf = pdf
42        .orientation(Orientation::Portrait)
43        .margin(Size::Inches(options.margins[0].parse().unwrap_or(10)))
44        .title("Resume");
45
46    match options.paper_size.to_lowercase().as_str() {
47        "a4" => pdf = pdf.page_size(PageSize::A4),
48        "letter" => pdf = pdf.page_size(PageSize::Letter),
49        _ => return Err(PdfExportError::InvalidPaperSize(options.paper_size.clone())),
50    }
51
52    pdf.build_from_html(html_content)?.save(&output_path)?;
53
54    Ok(())
55}