use super::*; use serde::ser::{SerializeStruct, Serializer}; use serde::Serialize; use crate::documents::BuildXML; use crate::xml_builder::*; #[derive(Debug, Clone, Serialize, PartialEq)] pub struct Drawing { pub position_type: DrawingPositionType, pub data: Option, // TODO: Old definition, remove later pub children: Vec, } #[derive(Debug, Clone, Serialize, PartialEq)] pub enum DrawingData { Pic(Pic), } // TODO: Old definition, remove later #[derive(Debug, Clone, PartialEq)] pub enum DrawingChild { WpAnchor(WpAnchor), } #[derive(Debug, Clone, Serialize, PartialEq)] pub enum DrawingPositionType { Anchor, Inline { dist_t: usize, dist_b: usize, dist_l: usize, dist_r: usize, }, } impl Serialize for DrawingChild { fn serialize(&self, serializer: S) -> Result where S: Serializer, { match *self { DrawingChild::WpAnchor(ref s) => { let mut t = serializer.serialize_struct("WpAnchor", 2)?; t.serialize_field("type", "anchor")?; t.serialize_field("data", s)?; t.end() } } } } impl Drawing { pub fn new() -> Drawing { Default::default() } pub fn add_anchor(mut self, a: WpAnchor) -> Drawing { self.children.push(DrawingChild::WpAnchor(a)); self } pub fn pic(mut self, pic: Pic) -> Drawing { self.data = Some(DrawingData::Pic(pic)); self } } impl Default for Drawing { fn default() -> Self { Drawing { position_type: DrawingPositionType::Inline { dist_t: 0, dist_b: 0, dist_l: 0, dist_r: 0, }, data: None, children: vec![], } } } impl BuildXML for Drawing { fn build(&self) -> Vec { let b = XMLBuilder::new(); let mut b = b.open_drawing(); if let DrawingPositionType::Inline { .. } = self.position_type { b = b.open_wp_inline("0", "0", "0", "0") } else { b = b.open_wp_anchor("0", "0", "0", "0"); } match &self.data { Some(DrawingData::Pic(p)) => { let w = format!("{}", crate::types::emu::from_px(p.size.0)); let h = format!("{}", crate::types::emu::from_px(p.size.1)); b = b // Please see 20.4.2.7 extent (Drawing Object Size) // One inch equates to 914400 EMUs and a centimeter is 360000 .wp_extent(&w, &h) .wp_effect_extent("0", "0", "0", "0") .wp_doc_pr("1", "Figure") .open_wp_c_nv_graphic_frame_pr() .a_graphic_frame_locks( "http://schemas.openxmlformats.org/drawingml/2006/main", "1", ) .close() .open_a_graphic("http://schemas.openxmlformats.org/drawingml/2006/main") .open_a_graphic_data("http://schemas.openxmlformats.org/drawingml/2006/picture") .add_child(&p.clone()) .close() .close(); } None => {} } b.close().close().build() } } #[cfg(test)] mod tests { use super::*; #[cfg(test)] use pretty_assertions::assert_eq; use std::str; #[test] fn test_drawing_build_with_pic() { use std::io::Read; let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap(); let mut buf = Vec::new(); let _ = img.read_to_end(&mut buf).unwrap(); let d = Drawing::new().pic(Pic::new(buf)).build(); assert_eq!( str::from_utf8(&d).unwrap(), r#" "# ); } }