docx_rs/documents/elements/
pic.rs1use serde::Serialize;
2use std::io::Write;
3
4use crate::documents::*;
5use crate::types::*;
6use crate::xml_builder::*;
7
8#[derive(Debug, Clone, Serialize, PartialEq)]
9#[cfg_attr(feature = "wasm", derive(ts_rs::TS))]
10#[cfg_attr(feature = "wasm", ts(export))]
11#[serde(rename_all = "camelCase")]
12pub struct Pic {
13 pub id: String,
14 #[serde(skip_serializing_if = "Vec::is_empty")]
16 pub image: Vec<u8>,
17 pub size: (u32, u32),
19 pub position_type: DrawingPositionType,
20 pub simple_pos: bool,
25 pub simple_pos_x: i32,
27 pub simple_pos_y: i32,
28 pub layout_in_cell: bool,
32 pub relative_height: u32,
37 pub allow_overlap: bool,
38 pub position_h: DrawingPosition,
39 pub position_v: DrawingPosition,
40 pub relative_from_h: RelativeFromHType,
41 pub relative_from_v: RelativeFromVType,
42 pub dist_t: i32,
45 pub dist_b: i32,
46 pub dist_l: i32,
47 pub dist_r: i32,
48 pub rot: u16,
50}
51
52impl Pic {
53 #[cfg(feature = "image")]
54 pub fn new(buf: &[u8]) -> Pic {
58 let img = ::image::load_from_memory(buf).expect("Should load image from memory.");
59 let (w, h) = ::image::GenericImageView::dimensions(&img);
60 let mut buf = std::io::Cursor::new(vec![]);
61 img.write_to(&mut buf, ::image::ImageFormat::Png)
62 .expect("Unable to write dynamic image");
63 Self::new_with_dimensions(buf.into_inner(), w, h)
64 }
65
66 pub fn new_with_dimensions(buffer: Vec<u8>, width_px: u32, height_px: u32) -> Pic {
70 let id = create_pic_rid(generate_pic_id());
71 Self {
72 id,
73 image: buffer,
74 size: (from_px(width_px), from_px(height_px)),
75 position_type: DrawingPositionType::Inline,
76 simple_pos: false,
77 simple_pos_x: 0,
78 simple_pos_y: 0,
79 layout_in_cell: false,
80 relative_height: 190500,
81 allow_overlap: false,
82 position_v: DrawingPosition::Offset(0),
83 position_h: DrawingPosition::Offset(0),
84 relative_from_h: RelativeFromHType::default(),
85 relative_from_v: RelativeFromVType::default(),
86 dist_t: 0,
87 dist_b: 0,
88 dist_l: 0,
89 dist_r: 0,
90 rot: 0,
91 }
92 }
93
94 pub(crate) fn with_empty() -> Pic {
95 Self {
96 id: "".to_string(),
97 image: vec![],
98 size: (0, 0),
99 position_type: DrawingPositionType::Inline,
100 simple_pos: false,
101 simple_pos_x: 0,
102 simple_pos_y: 0,
103 layout_in_cell: false,
104 relative_height: 190500,
105 allow_overlap: false,
106 position_v: DrawingPosition::Offset(0),
107 position_h: DrawingPosition::Offset(0),
108 relative_from_h: RelativeFromHType::default(),
109 relative_from_v: RelativeFromVType::default(),
110 dist_t: 0,
111 dist_b: 0,
112 dist_l: 0,
113 dist_r: 0,
114 rot: 0,
115 }
116 }
117
118 pub fn id(mut self, id: impl Into<String>) -> Pic {
119 self.id = id.into();
120 self
121 }
122
123 pub fn size(mut self, w_emu: u32, h_emu: u32) -> Pic {
125 self.size = (w_emu, h_emu);
126 self
127 }
128
129 pub fn rotate(mut self, deg: u16) -> Pic {
131 self.rot = deg;
132 self
133 }
134
135 pub fn floating(mut self) -> Pic {
136 self.position_type = DrawingPositionType::Anchor;
137 self
138 }
139
140 pub fn overlapping(mut self) -> Pic {
141 self.allow_overlap = true;
142 self
143 }
144
145 pub fn offset_x(mut self, x: i32) -> Pic {
146 self.position_h = DrawingPosition::Offset(x);
147 self
148 }
149
150 pub fn offset_y(mut self, y: i32) -> Pic {
151 self.position_v = DrawingPosition::Offset(y);
152 self
153 }
154
155 pub fn position_h(mut self, pos: DrawingPosition) -> Self {
156 self.position_h = pos;
157 self
158 }
159
160 pub fn position_v(mut self, pos: DrawingPosition) -> Self {
161 self.position_v = pos;
162 self
163 }
164
165 pub fn relative_from_h(mut self, t: RelativeFromHType) -> Self {
166 self.relative_from_h = t;
167 self
168 }
169
170 pub fn relative_from_v(mut self, t: RelativeFromVType) -> Self {
171 self.relative_from_v = t;
172 self
173 }
174
175 pub fn dist_t(mut self, v: i32) -> Self {
176 self.dist_t = v;
177 self
178 }
179
180 pub fn dist_b(mut self, v: i32) -> Self {
181 self.dist_b = v;
182 self
183 }
184
185 pub fn dist_l(mut self, v: i32) -> Self {
186 self.dist_l = v;
187 self
188 }
189
190 pub fn dist_r(mut self, v: i32) -> Self {
191 self.dist_r = v;
192 self
193 }
194
195 pub fn simple_pos(mut self, v: bool) -> Self {
196 self.simple_pos = v;
197 self
198 }
199
200 pub fn relative_height(mut self, v: u32) -> Self {
201 self.relative_height = v;
202 self
203 }
204}
205
206impl BuildXML for Pic {
207 fn build_to<W: Write>(
208 &self,
209 stream: xml::writer::EventWriter<W>,
210 ) -> xml::writer::Result<xml::writer::EventWriter<W>> {
211 XMLBuilder::from(stream)
212 .open_pic("http://schemas.openxmlformats.org/drawingml/2006/picture")?
213 .open_pic_nv_pic_pr()?
214 .pic_c_nv_pr("0", "")?
215 .open_pic_c_nv_pic_pr()?
216 .a_pic_locks("1", "1")?
217 .close()?
218 .close()?
219 .open_blip_fill()?
220 .a_blip(&self.id)?
221 .a_src_rect()?
222 .open_a_stretch()?
223 .a_fill_rect()?
224 .close()?
225 .close()?
226 .open_pic_sp_pr("auto")?
227 .open_a_xfrm_with_rot(&format!("{}", (self.rot as u32) * 60 * 1000))?
228 .a_off("0", "0")?
229 .a_ext(&format!("{}", self.size.0), &format!("{}", self.size.1))?
230 .close()?
231 .open_a_prst_geom("rect")?
232 .a_av_lst()?
233 .close()?
234 .close()?
235 .close()?
236 .into_inner()
237 }
238}
239
240#[cfg(test)]
241mod tests {
242
243 use super::*;
244 #[cfg(test)]
245 use pretty_assertions::assert_eq;
246 use std::str;
247
248 #[test]
249 fn test_pic_build() {
250 let b = Pic::new_with_dimensions(Vec::new(), 320, 240).build();
251 assert_eq!(
252 str::from_utf8(&b).unwrap(),
253 r#"<pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="0" name="" /><pic:cNvPicPr><a:picLocks noChangeAspect="1" noChangeArrowheads="1" /></pic:cNvPicPr></pic:nvPicPr><pic:blipFill><a:blip r:embed="rIdImage123" /><a:srcRect /><a:stretch><a:fillRect /></a:stretch></pic:blipFill><pic:spPr bwMode="auto"><a:xfrm rot="0"><a:off x="0" y="0" /><a:ext cx="3048000" cy="2286000" /></a:xfrm><a:prstGeom prst="rect"><a:avLst /></a:prstGeom></pic:spPr></pic:pic>"#
254 );
255 }
256}