use crate::data_structure::Document;
use crate::render::tessellation::{document_bbox, entity_fills, entity_polylines};
pub fn export(doc: &Document) -> Result<String, 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 minx = min.x - m;
let miny = min.y - m;
let maxx = max.x + m;
let maxy = max.y + m;
let mut ps = String::new();
ps += "%!PS-Adobe-3.0 EPSF-3.0\n";
ps += &format!(
"%%BoundingBox: {} {} {} {}\n",
minx.floor() as i64,
miny.floor() as i64,
maxx.ceil() as i64,
maxy.ceil() as i64
);
ps += "%%Pages: 0\n";
ps += "%%EndComments\n";
ps += "1 setlinewidth\n";
for (pts, color) in &fills {
ps += &format!(
"{:.3} {:.3} {:.3} setrgbcolor\n",
color.0 as f64 / 255.0,
color.1 as f64 / 255.0,
color.2 as f64 / 255.0
);
ps += &format!("newpath\n{:.3} {:.3} moveto\n", pts[0].0, pts[0].1);
for p in pts.iter().skip(1) {
ps += &format!("{:.3} {:.3} lineto\n", p.0, p.1);
}
ps += "closepath\nfill\n";
}
ps += "0 0 0 setrgbcolor\n";
for (pts, closed) in &polys {
let n = pts.len();
ps += &format!("{:.3} {:.3} moveto\n", pts[0].0, pts[0].1);
for p in pts.iter().take(n).skip(1) {
ps += &format!("{:.3} {:.3} lineto\n", p.0, p.1);
}
if *closed {
ps += &format!("{:.3} {:.3} lineto\n", pts[0].0, pts[0].1);
}
ps += "stroke\n";
}
ps += "%%EOF\n";
Ok(ps)
}