1use std::str::FromStr;
2
3mod content_types;
4mod custom_item_property;
5mod custom_item_rels;
6mod doc_props;
7mod document;
8mod document_rels;
9mod elements;
10mod font_table;
11mod footer;
12mod footer_id;
13mod header;
14mod header_id;
15mod hyperlink_id;
16mod numberings;
17mod paragraph_id;
18mod pic_id;
19mod rels;
20mod settings;
21mod styles;
22mod taskpanes;
23mod taskpanes_rels;
24mod theme;
25mod toc_key;
26mod web_settings;
27mod webextension;
28
29pub(crate) use hyperlink_id::*;
30use image::ImageFormat;
31pub(crate) use paragraph_id::*;
32pub(crate) use pic_id::*;
33
34pub use content_types::*;
35pub use custom_item_property::*;
36pub use custom_item_rels::*;
37pub use doc_props::*;
38pub use document::*;
39pub use document_rels::*;
40pub use elements::*;
41pub use font_table::*;
42pub use footer::*;
43pub use footer_id::*;
44pub use header::*;
45pub use header_id::*;
46pub use numberings::*;
47pub use rels::*;
48pub use settings::*;
49pub use styles::*;
50pub use taskpanes::*;
51pub use taskpanes_rels::*;
52pub use theme::*;
53pub use toc_key::*;
54pub use web_settings::*;
55pub use webextension::*;
56
57use serde::{ser, Serialize};
58
59#[derive(Debug, Clone)]
60pub struct Image(pub Vec<u8>);
61
62#[derive(Debug, Clone)]
63pub struct Png(pub Vec<u8>);
64
65pub type ImageIdAndPath = (String, String);
66pub type ImageIdAndBuf = (String, Vec<u8>);
67
68impl ser::Serialize for Image {
69 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
70 where
71 S: ser::Serializer,
72 {
73 let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
74 serializer.collect_str(&base64)
75 }
76}
77
78impl ser::Serialize for Png {
79 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80 where
81 S: ser::Serializer,
82 {
83 let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
84 serializer.collect_str(&base64)
85 }
86}
87
88#[derive(Debug, Clone, Serialize)]
89#[serde(rename_all = "camelCase")]
90pub struct Docx {
91 pub content_type: ContentTypes,
92 pub rels: Rels,
93 pub document_rels: DocumentRels,
94 pub doc_props: DocProps,
95 pub styles: Styles,
96 pub document: Document,
97 pub numberings: Numberings,
98 pub settings: Settings,
99 pub font_table: FontTable,
100 pub media: Vec<(String, Vec<u8>)>,
101 pub web_settings: WebSettings,
102 pub taskpanes: Option<Taskpanes>,
103 pub taskpanes_rels: TaskpanesRels,
104 pub web_extensions: Vec<WebExtension>,
105 pub custom_item_props: Vec<CustomItemProperty>,
106 pub custom_item_rels: Vec<CustomItemRels>,
107 pub themes: Vec<Theme>,
108 pub images: Vec<(String, String, Image, Png)>,
109 pub hyperlinks: Vec<(String, String, String)>,
110}
111
112impl Default for Docx {
113 fn default() -> Self {
114 let content_type = ContentTypes::new().set_default();
115 let rels = Rels::new().set_default();
116 let doc_props = DocProps::new(CorePropsConfig::new());
117 let styles = Styles::new();
118 let document = Document::new();
119 let document_rels = DocumentRels::new();
120 let settings = Settings::new();
121 let font_table = FontTable::new();
122 let numberings = Numberings::new();
123 let media = vec![];
124 let web_settings = WebSettings::new();
125
126 Docx {
127 content_type,
128 rels,
129 document_rels,
130 doc_props,
131 styles,
132 document,
133 numberings,
134 settings,
135 font_table,
136 media,
137 web_settings,
138 taskpanes: None,
139 taskpanes_rels: TaskpanesRels::new(),
140 web_extensions: vec![],
141 custom_item_props: vec![],
142 custom_item_rels: vec![],
143 themes: vec![],
144 images: vec![],
145 hyperlinks: vec![],
146 }
147 }
148}
149
150impl Docx {
151 pub fn new() -> Docx {
152 Default::default()
153 }
154
155 pub fn document(mut self, d: Document) -> Docx {
156 for child in &self.document.children {
157 match child {
158 DocumentChild::Paragraph(paragraph) => {
159 if paragraph.has_numbering {
160 self.document_rels.has_numberings = true;
161 }
162 }
163 DocumentChild::Table(table) => {
164 if table.has_numbering {
165 self.document_rels.has_numberings = true;
166 }
167 }
168 _ => {}
169 }
170 }
171 self.document = d;
172 self
173 }
174
175 pub fn styles(mut self, s: Styles) -> Self {
176 self.styles = s;
177 self
178 }
179
180 pub fn add_style(mut self, s: Style) -> Self {
181 self.styles = self.styles.add_style(s);
182 self
183 }
184
185 pub fn numberings(mut self, n: Numberings) -> Self {
186 self.numberings = n;
187 self
188 }
189
190 pub fn settings(mut self, s: Settings) -> Self {
191 self.settings = s;
192 self
193 }
194
195 pub(crate) fn web_settings(mut self, s: WebSettings) -> Self {
197 self.web_settings = s;
198 self
199 }
200
201 pub(crate) fn add_image(
203 mut self,
204 id: impl Into<String>,
205 path: impl Into<String>,
206 buf: Vec<u8>,
207 ) -> Self {
208 if let Ok(dimg) = image::load_from_memory(&buf) {
209 let mut png = std::io::Cursor::new(vec![]);
210 dimg.write_to(&mut png, ImageFormat::Png)
212 .expect("Unable to write dynamic image");
213
214 self.images
215 .push((id.into(), path.into(), Image(buf), Png(png.into_inner())));
216 }
217 self
218 }
219
220 pub(crate) fn add_hyperlink(
222 mut self,
223 id: impl Into<String>,
224 path: impl Into<String>,
225 r#type: impl Into<String>,
226 ) -> Self {
227 self.hyperlinks
228 .push((id.into(), path.into(), r#type.into()));
229 self
230 }
231
232 pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
233 if p.has_numbering {
234 self.document_rels.has_numberings = true;
237 }
238 self.document = self.document.add_paragraph(p);
239 self
240 }
241
242 pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Docx {
243 if t.has_numbering {
244 self.document_rels.has_numberings = true;
247 }
248 self.document = self.document.add_structured_data_tag(t);
249 self
250 }
251
252 pub fn add_table_of_contents(mut self, t: TableOfContents) -> Docx {
253 self.document = self.document.add_table_of_contents(t);
254 self
255 }
256
257 pub fn add_table(mut self, t: Table) -> Docx {
258 if t.has_numbering {
259 self.document_rels.has_numberings = true;
262 }
263 self.document = self.document.add_table(t);
264 self
265 }
266
267 pub fn header(mut self, header: Header) -> Self {
268 if header.has_numbering {
269 self.document_rels.has_numberings = true;
270 }
271 let count = self.document_rels.header_count + 1;
272 self.document.section_property = self
273 .document
274 .section_property
275 .header(header, &create_header_rid(count));
276 self.document_rels.header_count = count;
277 self.content_type = self.content_type.add_header();
278 self
279 }
280
281 pub fn first_header(mut self, header: Header) -> Self {
282 if header.has_numbering {
283 self.document_rels.has_numberings = true;
284 }
285 let count = self.document_rels.header_count + 1;
286 self.document.section_property = self
287 .document
288 .section_property
289 .first_header(header, &create_header_rid(count));
290 self.document_rels.header_count = count;
291 self.content_type = self.content_type.add_header();
292 self
293 }
294
295 pub fn even_header(mut self, header: Header) -> Self {
296 if header.has_numbering {
297 self.document_rels.has_numberings = true;
298 }
299 let count = self.document_rels.header_count + 1;
300 self.document.section_property = self
301 .document
302 .section_property
303 .even_header(header, &create_header_rid(count));
304 self.document_rels.header_count = count;
305 self.content_type = self.content_type.add_header();
306 self.settings = self.settings.even_and_odd_headers();
307 self
308 }
309
310 pub fn footer(mut self, footer: Footer) -> Self {
311 if footer.has_numbering {
312 self.document_rels.has_numberings = true;
313 }
314 let count = self.document_rels.footer_count + 1;
315 self.document.section_property = self
316 .document
317 .section_property
318 .footer(footer, &create_footer_rid(count));
319 self.document_rels.footer_count = count;
320 self.content_type = self.content_type.add_footer();
321 self
322 }
323
324 pub fn first_footer(mut self, footer: Footer) -> Self {
325 if footer.has_numbering {
326 self.document_rels.has_numberings = true;
327 }
328 let count = self.document_rels.footer_count + 1;
329 self.document.section_property = self
330 .document
331 .section_property
332 .first_footer(footer, &create_footer_rid(count));
333 self.document_rels.footer_count = count;
334 self.content_type = self.content_type.add_footer();
335 self
336 }
337
338 pub fn even_footer(mut self, footer: Footer) -> Self {
339 if footer.has_numbering {
340 self.document_rels.has_numberings = true;
341 }
342 let count = self.document_rels.footer_count + 1;
343 self.document.section_property = self
344 .document
345 .section_property
346 .even_footer(footer, &create_footer_rid(count));
347 self.document_rels.footer_count = count;
348 self.content_type = self.content_type.add_footer();
349 self.settings = self.settings.even_and_odd_headers();
350 self
351 }
352
353 pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
354 self.numberings = self.numberings.add_abstract_numbering(num);
355 self
356 }
357
358 pub fn add_numbering(mut self, num: Numbering) -> Docx {
359 self.numberings = self.numberings.add_numbering(num);
360 self
361 }
362
363 pub fn created_at(mut self, date: &str) -> Self {
364 self.doc_props = self.doc_props.created_at(date);
365 self
366 }
367
368 pub fn updated_at(mut self, date: &str) -> Self {
369 self.doc_props = self.doc_props.updated_at(date);
370 self
371 }
372
373 pub fn custom_property(mut self, name: impl Into<String>, item: impl Into<String>) -> Self {
374 self.doc_props = self.doc_props.custom_property(name, item);
375 self
376 }
377
378 pub fn doc_id(mut self, id: &str) -> Self {
379 self.settings = self.settings.doc_id(id);
380 self
381 }
382
383 pub fn default_tab_stop(mut self, stop: usize) -> Self {
384 self.settings = self.settings.default_tab_stop(stop);
385 self
386 }
387
388 pub fn add_doc_var(mut self, name: &str, val: &str) -> Self {
389 self.settings = self.settings.add_doc_var(name, val);
390 self
391 }
392
393 pub fn page_size(mut self, w: u32, h: u32) -> Self {
394 self.document = self.document.page_size(PageSize::new().size(w, h));
395 self
396 }
397
398 pub fn page_margin(mut self, margin: crate::types::PageMargin) -> Self {
399 self.document = self.document.page_margin(margin);
400 self
401 }
402
403 pub fn page_orient(mut self, o: crate::types::PageOrientationType) -> Self {
404 self.document = self.document.page_orient(o);
405 self
406 }
407
408 pub fn default_size(mut self, size: usize) -> Self {
409 self.styles = self.styles.default_size(size);
410 self
411 }
412
413 pub fn default_spacing(mut self, spacing: i32) -> Self {
414 self.styles = self.styles.default_spacing(spacing);
415 self
416 }
417
418 pub fn default_fonts(mut self, font: RunFonts) -> Self {
419 self.styles = self.styles.default_fonts(font);
420 self
421 }
422
423 pub fn taskpanes(mut self) -> Self {
424 self.taskpanes = Some(Taskpanes::new());
425 self.rels = self.rels.add_taskpanes_rel();
426 self.content_type = self.content_type.add_taskpanes();
427 self
428 }
429
430 pub fn web_extension(mut self, ext: WebExtension) -> Self {
431 self.web_extensions.push(ext);
432 self.taskpanes_rels = self.taskpanes_rels.add_rel();
433 self.content_type = self.content_type.add_web_extensions();
434 self
435 }
436}