use std::str::FromStr;
mod content_types;
mod custom_item_property;
mod custom_item_rels;
mod doc_props;
mod document;
mod document_rels;
mod elements;
mod font_table;
mod footer;
mod footer_id;
mod header;
mod header_id;
mod hyperlink_id;
mod numberings;
mod paragraph_id;
mod pic_id;
mod rels;
mod settings;
mod styles;
mod taskpanes;
mod taskpanes_rels;
mod theme;
mod toc_key;
mod web_settings;
mod webextension;
pub(crate) use hyperlink_id::*;
use image::ImageFormat;
pub(crate) use paragraph_id::*;
pub(crate) use pic_id::*;
pub use content_types::*;
pub use custom_item_property::*;
pub use custom_item_rels::*;
pub use doc_props::*;
pub use document::*;
pub use document_rels::*;
pub use elements::*;
pub use font_table::*;
pub use footer::*;
pub use footer_id::*;
pub use header::*;
pub use header_id::*;
pub use numberings::*;
pub use rels::*;
pub use settings::*;
pub use styles::*;
pub use taskpanes::*;
pub use taskpanes_rels::*;
pub use theme::*;
pub use toc_key::*;
pub use web_settings::*;
pub use webextension::*;
use serde::{ser, Serialize};
#[derive(Debug, Clone)]
pub struct Image(pub Vec<u8>);
#[derive(Debug, Clone)]
pub struct Png(pub Vec<u8>);
pub type ImageIdAndPath = (String, String);
pub type ImageIdAndBuf = (String, Vec<u8>);
impl ser::Serialize for Image {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
serializer.collect_str(&base64)
}
}
impl ser::Serialize for Png {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let base64 = base64::display::Base64Display::with_config(&*self.0, base64::STANDARD);
serializer.collect_str(&base64)
}
}
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Docx {
pub content_type: ContentTypes,
pub rels: Rels,
pub document_rels: DocumentRels,
pub doc_props: DocProps,
pub styles: Styles,
pub document: Document,
pub numberings: Numberings,
pub settings: Settings,
pub font_table: FontTable,
pub media: Vec<(String, Vec<u8>)>,
pub web_settings: WebSettings,
pub taskpanes: Option<Taskpanes>,
pub taskpanes_rels: TaskpanesRels,
pub web_extensions: Vec<WebExtension>,
pub custom_item_props: Vec<CustomItemProperty>,
pub custom_item_rels: Vec<CustomItemRels>,
pub themes: Vec<Theme>,
pub images: Vec<(String, String, Image, Png)>,
pub hyperlinks: Vec<(String, String, String)>,
}
impl Default for Docx {
fn default() -> Self {
let content_type = ContentTypes::new().set_default();
let rels = Rels::new().set_default();
let doc_props = DocProps::new(CorePropsConfig::new());
let styles = Styles::new();
let document = Document::new();
let document_rels = DocumentRels::new();
let settings = Settings::new();
let font_table = FontTable::new();
let numberings = Numberings::new();
let media = vec![];
let web_settings = WebSettings::new();
Docx {
content_type,
rels,
document_rels,
doc_props,
styles,
document,
numberings,
settings,
font_table,
media,
web_settings,
taskpanes: None,
taskpanes_rels: TaskpanesRels::new(),
web_extensions: vec![],
custom_item_props: vec![],
custom_item_rels: vec![],
themes: vec![],
images: vec![],
hyperlinks: vec![],
}
}
}
impl Docx {
pub fn new() -> Docx {
Default::default()
}
pub fn document(mut self, d: Document) -> Docx {
for child in &self.document.children {
match child {
DocumentChild::Paragraph(paragraph) => {
if paragraph.has_numbering {
self.document_rels.has_numberings = true;
}
}
DocumentChild::Table(table) => {
if table.has_numbering {
self.document_rels.has_numberings = true;
}
}
_ => {}
}
}
self.document = d;
self
}
pub fn styles(mut self, s: Styles) -> Self {
self.styles = s;
self
}
pub fn add_style(mut self, s: Style) -> Self {
self.styles = self.styles.add_style(s);
self
}
pub fn numberings(mut self, n: Numberings) -> Self {
self.numberings = n;
self
}
pub fn settings(mut self, s: Settings) -> Self {
self.settings = s;
self
}
pub(crate) fn web_settings(mut self, s: WebSettings) -> Self {
self.web_settings = s;
self
}
pub(crate) fn add_image(
mut self,
id: impl Into<String>,
path: impl Into<String>,
buf: Vec<u8>,
) -> Self {
if let Ok(dimg) = image::load_from_memory(&buf) {
let mut png = std::io::Cursor::new(vec![]);
dimg.write_to(&mut png, ImageFormat::Png)
.expect("Unable to write dynamic image");
self.images
.push((id.into(), path.into(), Image(buf), Png(png.into_inner())));
}
self
}
pub(crate) fn add_hyperlink(
mut self,
id: impl Into<String>,
path: impl Into<String>,
r#type: impl Into<String>,
) -> Self {
self.hyperlinks
.push((id.into(), path.into(), r#type.into()));
self
}
pub fn add_paragraph(mut self, p: Paragraph) -> Docx {
if p.has_numbering {
self.document_rels.has_numberings = true;
}
self.document = self.document.add_paragraph(p);
self
}
pub fn add_structured_data_tag(mut self, t: StructuredDataTag) -> Docx {
if t.has_numbering {
self.document_rels.has_numberings = true;
}
self.document = self.document.add_structured_data_tag(t);
self
}
pub fn add_table_of_contents(mut self, t: TableOfContents) -> Docx {
self.document = self.document.add_table_of_contents(t);
self
}
pub fn add_table(mut self, t: Table) -> Docx {
if t.has_numbering {
self.document_rels.has_numberings = true;
}
self.document = self.document.add_table(t);
self
}
pub fn header(mut self, header: Header) -> Self {
if header.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.header_count + 1;
self.document.section_property = self
.document
.section_property
.header(header, &create_header_rid(count));
self.document_rels.header_count = count;
self.content_type = self.content_type.add_header();
self
}
pub fn first_header(mut self, header: Header) -> Self {
if header.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.header_count + 1;
self.document.section_property = self
.document
.section_property
.first_header(header, &create_header_rid(count));
self.document_rels.header_count = count;
self.content_type = self.content_type.add_header();
self
}
pub fn even_header(mut self, header: Header) -> Self {
if header.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.header_count + 1;
self.document.section_property = self
.document
.section_property
.even_header(header, &create_header_rid(count));
self.document_rels.header_count = count;
self.content_type = self.content_type.add_header();
self.settings = self.settings.even_and_odd_headers();
self
}
pub fn footer(mut self, footer: Footer) -> Self {
if footer.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.footer_count + 1;
self.document.section_property = self
.document
.section_property
.footer(footer, &create_footer_rid(count));
self.document_rels.footer_count = count;
self.content_type = self.content_type.add_footer();
self
}
pub fn first_footer(mut self, footer: Footer) -> Self {
if footer.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.footer_count + 1;
self.document.section_property = self
.document
.section_property
.first_footer(footer, &create_footer_rid(count));
self.document_rels.footer_count = count;
self.content_type = self.content_type.add_footer();
self
}
pub fn even_footer(mut self, footer: Footer) -> Self {
if footer.has_numbering {
self.document_rels.has_numberings = true;
}
let count = self.document_rels.footer_count + 1;
self.document.section_property = self
.document
.section_property
.even_footer(footer, &create_footer_rid(count));
self.document_rels.footer_count = count;
self.content_type = self.content_type.add_footer();
self.settings = self.settings.even_and_odd_headers();
self
}
pub fn add_abstract_numbering(mut self, num: AbstractNumbering) -> Docx {
self.numberings = self.numberings.add_abstract_numbering(num);
self
}
pub fn add_numbering(mut self, num: Numbering) -> Docx {
self.numberings = self.numberings.add_numbering(num);
self
}
pub fn created_at(mut self, date: &str) -> Self {
self.doc_props = self.doc_props.created_at(date);
self
}
pub fn updated_at(mut self, date: &str) -> Self {
self.doc_props = self.doc_props.updated_at(date);
self
}
pub fn custom_property(mut self, name: impl Into<String>, item: impl Into<String>) -> Self {
self.doc_props = self.doc_props.custom_property(name, item);
self
}
pub fn doc_id(mut self, id: &str) -> Self {
self.settings = self.settings.doc_id(id);
self
}
pub fn default_tab_stop(mut self, stop: usize) -> Self {
self.settings = self.settings.default_tab_stop(stop);
self
}
pub fn add_doc_var(mut self, name: &str, val: &str) -> Self {
self.settings = self.settings.add_doc_var(name, val);
self
}
pub fn page_size(mut self, w: u32, h: u32) -> Self {
self.document = self.document.page_size(PageSize::new().size(w, h));
self
}
pub fn page_margin(mut self, margin: crate::types::PageMargin) -> Self {
self.document = self.document.page_margin(margin);
self
}
pub fn page_orient(mut self, o: crate::types::PageOrientationType) -> Self {
self.document = self.document.page_orient(o);
self
}
pub fn default_size(mut self, size: usize) -> Self {
self.styles = self.styles.default_size(size);
self
}
pub fn default_spacing(mut self, spacing: i32) -> Self {
self.styles = self.styles.default_spacing(spacing);
self
}
pub fn default_fonts(mut self, font: RunFonts) -> Self {
self.styles = self.styles.default_fonts(font);
self
}
pub fn taskpanes(mut self) -> Self {
self.taskpanes = Some(Taskpanes::new());
self.rels = self.rels.add_taskpanes_rel();
self.content_type = self.content_type.add_taskpanes();
self
}
pub fn web_extension(mut self, ext: WebExtension) -> Self {
self.web_extensions.push(ext);
self.taskpanes_rels = self.taskpanes_rels.add_rel();
self.content_type = self.content_type.add_web_extensions();
self
}
}