//! Windows metafiles: hand-written EMF and WMF writers and readers. //! //! [`export`] writes the visible art over one region of a document (an artboard) as a metafile: //! //! - **EMF**: paths keep their Bézier curves, fills are solid brushes, strokes geometric pens with //! their width, caps, joins, miter limit and dashes; strokes a pen can't draw (aligned inside or //! outside, width profiles, arrowheads) are their filled outlines and brush strokes their brush //! art. Clipping masks clip, type is written as glyph outlines, images keep their pixels (with //! their transparency), gradients become images clipped to what they paint and pattern fills //! their tiles clipped to the shape. The header's frame is the region in 0.01 mm. //! - **WMF**: the same art with curves flattened into polygons and 16-bit coordinates, behind a //! placeable header that gives the size; WMF has no clipping paths, transparency, dashes on wide //! lines or gradients, so clipped art is written whole, images over white, dashes as separate //! lines and gradients and patterns as one colour (each loss comes back as a warning). //! //! [`import`] reads either format back into a document of one artboard (the picture's frame) and //! one layer: paths with fills and strokes, clipping, images and text. Records it doesn't read are //! skipped, with one warning. //! //! - `bytes`: little-endian writing and bounds-checked reading. //! - `dib`: device-independent bitmaps, both ways. //! - `scene`: the document walk both writers share. //! - `emf`, `wmf`: the writers. //! - `import`: the reader. mod bytes; mod dib; mod emf; mod import; mod scene; mod wmf; use vectorcraft_doc::Document; use vectorcraft_geom::Rect; /// A Windows metafile format. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Kind { /// Enhanced Metafile (32-bit coordinates, Bézier curves, paths and clipping). Emf, /// Windows Metafile with a placeable header (16-bit coordinates, polygons). Wmf, } impl Kind { /// The format id (`emf`, `wmf`). pub fn id(self) -> &'static str { match self { Self::Emf => "emf", Self::Wmf => "wmf", } } } /// The metafile format `bytes` start like, if any. pub fn sniff(bytes: &[u8]) -> Option { if emf::is_emf(bytes) { Some(Kind::Emf) } else if wmf::is_wmf(bytes) { Some(Kind::Wmf) } else { None } } /// A written metafile. #[derive(Clone, Debug, Default)] pub struct Output { pub bytes: Vec, /// What was approximated or left out. pub warnings: Vec, } /// Write the visible art of `doc` over `region` (document space: its top-left corner is the /// picture's origin, its size the picture's) as `kind`. Live geometry effects are applied first; /// template layers, hidden objects and guides are left out. Raster effects should be turned into /// images before (the engine does); the ones left are reported and left out. pub fn export(doc: &Document, region: Rect, kind: Kind) -> Result { let r = region.abs(); if ![r.x0, r.y0, r.x1, r.y1].iter().all(|v| v.is_finite()) || r.width() <= 0.0 || r.height() <= 0.0 { return Err("the export region is empty".into()); } let baked = vectorcraft_effects::bake_document(doc); let doc = baked.as_ref().unwrap_or(doc); let (ops, mut warnings) = scene::Scene::new(doc, r, kind == Kind::Emf).run(); let bytes = match kind { Kind::Emf => emf::write(&ops, r, &doc.title), Kind::Wmf => wmf::write(&ops, r, &mut warnings), }; Ok(Output { bytes, warnings }) } /// A metafile read into a document. #[derive(Clone, Debug)] pub struct Imported { pub document: Document, pub kind: Kind, /// What was approximated or skipped. pub warnings: Vec, } /// Read an EMF or WMF file (with or without a placeable header) into a document whose one /// artboard is the picture's frame. pub fn import(bytes: &[u8]) -> Result { import::import(bytes) } #[cfg(test)] mod tests; #[cfg(test)] mod tests_import;