use crate::data_structure::Document;
use crate::render::tessellation::{document_bbox, entity_fills, entity_polylines};
pub fn export(doc: &Document) -> Result<Vec<u8>, String> {
if doc.entity_count() == 0 {
return Err("Canvas is empty, nothing to export".to_string());
}
let Some((min, max)) = document_bbox(doc) else {
return Err("Canvas is empty, nothing to export".to_string());
};
let mut polys: Vec<(Vec<(f64, f64)>, bool)> = Vec::new();
let mut fills: Vec<(Vec<(f64, f64)>, (u8, u8, u8))> = Vec::new();
for entity in doc.entities().values() {
for (pts, color) in entity_fills(entity) {
if pts.len() >= 3 {
fills.push((pts.iter().map(|p| (p.x, p.y)).collect(), color));
}
}
for (pts, closed) in entity_polylines(entity) {
if pts.len() >= 2 {
polys.push((pts.iter().map(|p| (p.x, p.y)).collect(), closed));
}
}
}
if polys.is_empty() && fills.is_empty() {
return Err("Nothing to draw".to_string());
}
let m = 10.0;
let w = (max.x - min.x) + 2.0 * m;
let h = (max.y - min.y) + 2.0 * m;
let tx = |x: f64| x - min.x + m;
let ty = |y: f64| y - min.y + m;
let mut c = String::new();
c += "1 w\n";
for (pts, color) in &fills {
c += &format!(
"{:.3} {:.3} {:.3} rg\n",
color.0 as f64 / 255.0,
color.1 as f64 / 255.0,
color.2 as f64 / 255.0
);
c += &format!("{:.2} {:.2} m\n", tx(pts[0].0), ty(pts[0].1));
for p in pts.iter().skip(1) {
c += &format!("{:.2} {:.2} l\n", tx(p.0), ty(p.1));
}
c += "h f\n";
}
c += "0 0 0 RG\n";
for (pts, closed) in &polys {
let n = pts.len();
c += &format!("{:.2} {:.2} m\n", tx(pts[0].0), ty(pts[0].1));
for p in pts.iter().take(n).skip(1) {
c += &format!("{:.2} {:.2} l\n", tx(p.0), ty(p.1));
}
if *closed {
c += &format!("{:.2} {:.2} l\n", tx(pts[0].0), ty(pts[0].1));
}
c += "S\n";
}
let obj3 = format!(
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {w:.2} {h:.2}] /Contents 4 0 R /Resources << >> >>"
);
let obj4 = format!("<< /Length {} >>\nstream\n{c}endstream", c.len());
let bodies = [
"<< /Type /Catalog /Pages 2 0 R >>".to_string(),
"<< /Type /Pages /Kids [3 0 R] /Count 1 >>".to_string(),
obj3,
obj4,
];
let mut out: Vec<u8> = b"%PDF-1.4\n".to_vec();
let mut offsets = [0usize; 4];
for (i, body) in bodies.iter().enumerate() {
offsets[i] = out.len();
out.extend_from_slice(format!("{} 0 obj\n{}\nendobj\n", i + 1, body).as_bytes());
}
let xref_off = out.len();
out.extend_from_slice(b"xref\n0 5\n");
out.extend_from_slice(b"0000000000 65535 f \n");
for off in offsets {
out.extend_from_slice(format!("{off:010} 00000 n \n").as_bytes());
}
out.extend_from_slice(
format!("trailer\n<< /Size 5 /Root 1 0 R >>\nstartxref\n{xref_off}\n%%EOF").as_bytes(),
);
Ok(out)
}