use crate::document::convert::Page; use crate::error::Result; use base64::Engine; pub fn generate_preview_html(page: &Page, title: &str, output_path: &std::path::Path) -> Result<()> { let png_data = fax_page_to_png_bytes(page)?; let b64 = base64::engine::general_purpose::STANDARD.encode(&png_data); let data_uri = format!("data:image/png;base64,{}", b64); let w = page.width_pels; let h = page.rows; let html = build_viewer_html(&data_uri, w, h, title); std::fs::write(output_path, html)?; Ok(()) } fn fax_page_to_png_bytes(page: &Page) -> Result> { let width = page.width_pels as usize; let height = page.rows as usize; let bytes_per_row = (width + 7) / 8; let mut img_data = Vec::with_capacity(width * height); for y in 0..height { for x in 0..width { let byte_idx = y * bytes_per_row + x / 8; let bit = (page.pixels[byte_idx] >> (7 - (x % 8))) & 1; img_data.push(if bit == 1 { 0u8 } else { 255u8 }); } } let mut png_bytes = Vec::new(); { use image::ImageEncoder; let encoder = image::codecs::png::PngEncoder::new(&mut png_bytes); encoder .write_image(&img_data, page.width_pels, page.rows, image::ExtendedColorType::L8) .map_err(|e| crate::error::FaxError::Other(format!("PNG encode error: {}", e)))?; } Ok(png_bytes) } fn build_viewer_html(data_uri: &str, width: u32, height: u32, title: &str) -> String { let html = format!( r#" Fax Preview — {title}
{title} {width}×{height} px
"#, title = title, width = width, height = height, data_uri_str = serde_json::to_string(data_uri).unwrap(), ); html }