Support image in header footer (#680)
* wip * wip * wip * fix: image in header/footer * fix: Changelogmain
parent
8224ff0663
commit
72adfa699f
|
@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## @0.4.8 (19. Feb, 2024)
|
||||
|
||||
- Fixed a bug, image in header/footer is not stored in media when read.
|
||||
- Fixed a bug, image in header/footer is broken.
|
||||
|
||||
## docx-wasm@0.0.278-rc27 (17. Jan, 2024)
|
||||
|
||||
- Support part of `pPrDefault`.
|
||||
|
|
|
@ -143,7 +143,7 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
|||
|
||||
[[package]]
|
||||
name = "docx-rs"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"image",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "docx-rs"
|
||||
version = "0.4.7"
|
||||
version = "0.4.8"
|
||||
authors = ["bokuweb <bokuweb12@gmail.com>"]
|
||||
repository = "https://github.com/bokuweb/docx-rs"
|
||||
edition = "2018"
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
use docx_rs::{Docx, Header, Paragraph, Pic, Run};
|
||||
use std::{error::Error, io::Cursor};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let cat = Pic::new(include_bytes!("../../images/cat_min.jpg"));
|
||||
let header =
|
||||
Header::new().add_paragraph(Paragraph::new().add_run(Run::new().add_image(cat.clone())));
|
||||
let mut out = Vec::new();
|
||||
let docx = Docx::new()
|
||||
.header(header)
|
||||
.add_paragraph(Paragraph::new().add_run(Run::new().add_image(cat)));
|
||||
docx.build().pack(Cursor::new(&mut out))?;
|
||||
|
||||
std::fs::write("/tmp/out.docx", &out)?;
|
||||
Ok(())
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
use crate::documents::BuildXML;
|
||||
use crate::{xml_builder::*, ImageIdAndPath};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct FooterRels {
|
||||
pub images: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl FooterRels {
|
||||
pub fn new() -> FooterRels {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_image(mut self, id: impl Into<String>, path: impl Into<String>) -> Self {
|
||||
self.images.push((id.into(), path.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_images(&mut self, images: Vec<ImageIdAndPath>) {
|
||||
self.images = images;
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for FooterRels {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let mut b = XMLBuilder::new();
|
||||
b = b
|
||||
.declaration(None)
|
||||
.open_relationships("http://schemas.openxmlformats.org/package/2006/relationships");
|
||||
|
||||
for (id, path) in self.images.iter() {
|
||||
b = b.relationship(
|
||||
id,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
path,
|
||||
)
|
||||
}
|
||||
|
||||
b.close().build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
use crate::documents::BuildXML;
|
||||
use crate::{xml_builder::*, ImageIdAndPath};
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct HeaderRels {
|
||||
pub images: Vec<(String, String)>,
|
||||
}
|
||||
|
||||
impl HeaderRels {
|
||||
pub fn new() -> HeaderRels {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn add_image(mut self, id: impl Into<String>, path: impl Into<String>) -> Self {
|
||||
self.images.push((id.into(), path.into()));
|
||||
self
|
||||
}
|
||||
|
||||
pub(crate) fn set_images(&mut self, images: Vec<ImageIdAndPath>) {
|
||||
self.images = images;
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildXML for HeaderRels {
|
||||
fn build(&self) -> Vec<u8> {
|
||||
let mut b = XMLBuilder::new();
|
||||
b = b
|
||||
.declaration(None)
|
||||
.open_relationships("http://schemas.openxmlformats.org/package/2006/relationships");
|
||||
|
||||
for (id, path) in self.images.iter() {
|
||||
b = b.relationship(
|
||||
id,
|
||||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
||||
path,
|
||||
)
|
||||
}
|
||||
|
||||
b.close().build()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
use crate::{
|
||||
DeleteChild, DrawingData, InsertChild, Paragraph, ParagraphChild, RunChild,
|
||||
StructuredDataTagChild, Table, TableCellContent, TableChild, TableRowChild, TocContent,
|
||||
};
|
||||
|
||||
pub(crate) fn collect_images_from_paragraph(
|
||||
paragraph: &mut Paragraph,
|
||||
images: &mut Vec<(String, String)>,
|
||||
image_bufs: &mut Vec<(String, Vec<u8>)>,
|
||||
id_prefix: Option<&str>,
|
||||
) {
|
||||
for child in &mut paragraph.children {
|
||||
if let ParagraphChild::Run(run) = child {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
let buf = image_bufs.iter().find(|x| x.0 == pic.id || x.1 == b);
|
||||
let pic_id = if let Some(prefix) = id_prefix {
|
||||
format!("{}{}", prefix, pic.id)
|
||||
} else {
|
||||
pic.id.clone()
|
||||
};
|
||||
if buf.as_ref().is_none() {
|
||||
images.push((
|
||||
pic_id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic_id),
|
||||
));
|
||||
image_bufs.push((pic_id.clone(), b));
|
||||
pic.id = pic_id;
|
||||
} else {
|
||||
pic.id = buf.unwrap().0.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let ParagraphChild::Insert(ins) = child {
|
||||
for child in &mut ins.children {
|
||||
match child {
|
||||
InsertChild::Run(run) => {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
InsertChild::Delete(del) => {
|
||||
for d in &mut del.children {
|
||||
if let DeleteChild::Run(run) = d {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else if let ParagraphChild::Delete(del) = child {
|
||||
for d in &mut del.children {
|
||||
if let DeleteChild::Run(run) = d {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn collect_images_from_table(
|
||||
table: &mut Table,
|
||||
images: &mut Vec<(String, String)>,
|
||||
image_bufs: &mut Vec<(String, Vec<u8>)>,
|
||||
id_prefix: Option<&str>,
|
||||
) {
|
||||
for TableChild::TableRow(row) in &mut table.rows {
|
||||
for TableRowChild::TableCell(cell) in &mut row.cells {
|
||||
for content in &mut cell.children {
|
||||
match content {
|
||||
TableCellContent::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(paragraph, images, image_bufs, id_prefix);
|
||||
}
|
||||
TableCellContent::Table(table) => {
|
||||
collect_images_from_table(table, images, image_bufs, id_prefix)
|
||||
}
|
||||
TableCellContent::StructuredDataTag(tag) => {
|
||||
for child in &mut tag.children {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(
|
||||
paragraph, images, image_bufs, id_prefix,
|
||||
);
|
||||
}
|
||||
if let StructuredDataTagChild::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs, id_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
TableCellContent::TableOfContents(t) => {
|
||||
for child in &mut t.before_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(
|
||||
paragraph, images, image_bufs, id_prefix,
|
||||
);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs, id_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
for child in &mut t.after_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(
|
||||
paragraph, images, image_bufs, id_prefix,
|
||||
);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs, id_prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,10 +15,13 @@ mod elements;
|
|||
mod font_table;
|
||||
mod footer;
|
||||
mod footer_id;
|
||||
mod footer_rels;
|
||||
mod header;
|
||||
mod header_id;
|
||||
mod header_rels;
|
||||
mod history_id;
|
||||
mod hyperlink_id;
|
||||
mod image_collector;
|
||||
mod numberings;
|
||||
mod paragraph_id;
|
||||
mod paragraph_property_change_id;
|
||||
|
@ -57,8 +60,10 @@ pub use elements::*;
|
|||
pub use font_table::*;
|
||||
pub use footer::*;
|
||||
pub use footer_id::*;
|
||||
pub use footer_rels::*;
|
||||
pub use header::*;
|
||||
pub use header_id::*;
|
||||
pub use header_rels::*;
|
||||
pub use numberings::*;
|
||||
pub use rels::*;
|
||||
pub use settings::*;
|
||||
|
@ -73,6 +78,8 @@ pub use xml_docx::*;
|
|||
|
||||
use serde::{ser, Serialize};
|
||||
|
||||
use self::image_collector::{collect_images_from_paragraph, collect_images_from_table};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Image(pub Vec<u8>);
|
||||
|
||||
|
@ -533,7 +540,26 @@ impl Docx {
|
|||
}
|
||||
}
|
||||
|
||||
let (images, images_bufs) = self.create_images();
|
||||
let (images, mut images_bufs) = self.images_in_doc();
|
||||
let (header_images, header_images_bufs) = self.images_in_header();
|
||||
let (footer_images, footer_images_bufs) = self.images_in_footer();
|
||||
|
||||
images_bufs.extend(header_images_bufs);
|
||||
images_bufs.extend(footer_images_bufs);
|
||||
|
||||
let mut header_rels = vec![HeaderRels::new(); 3];
|
||||
for (i, images) in header_images.iter().enumerate() {
|
||||
if let Some(h) = header_rels.get_mut(i) {
|
||||
h.set_images(images.to_owned());
|
||||
}
|
||||
}
|
||||
let mut footer_rels = vec![FooterRels::new(); 3];
|
||||
for (i, images) in footer_images.iter().enumerate() {
|
||||
if let Some(f) = footer_rels.get_mut(i) {
|
||||
f.set_images(images.to_owned());
|
||||
}
|
||||
}
|
||||
|
||||
let web_extensions = self.web_extensions.iter().map(|ext| ext.build()).collect();
|
||||
let custom_items = self.custom_items.iter().map(|xml| xml.build()).collect();
|
||||
let custom_item_props = self.custom_item_props.iter().map(|p| p.build()).collect();
|
||||
|
@ -569,6 +595,8 @@ impl Docx {
|
|||
document: self.document.build(),
|
||||
comments: self.comments.build(),
|
||||
document_rels: self.document_rels.build(),
|
||||
header_rels: header_rels.into_iter().map(|r| r.build()).collect(),
|
||||
footer_rels: footer_rels.into_iter().map(|r| r.build()).collect(),
|
||||
settings: self.settings.build(),
|
||||
font_table: self.font_table.build(),
|
||||
numberings: self.numberings.build(),
|
||||
|
@ -850,99 +878,186 @@ impl Docx {
|
|||
}
|
||||
|
||||
// Traverse and collect images from document.
|
||||
fn create_images(&mut self) -> (Vec<ImageIdAndPath>, Vec<ImageIdAndBuf>) {
|
||||
fn images_in_doc(&mut self) -> (Vec<ImageIdAndPath>, Vec<ImageIdAndBuf>) {
|
||||
let mut images: Vec<(String, String)> = vec![];
|
||||
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
||||
|
||||
for child in &mut self.document.children {
|
||||
match child {
|
||||
DocumentChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(paragraph, &mut images, &mut image_bufs);
|
||||
collect_images_from_paragraph(paragraph, &mut images, &mut image_bufs, None);
|
||||
}
|
||||
DocumentChild::Table(table) => {
|
||||
for TableChild::TableRow(row) in &mut table.rows {
|
||||
for TableRowChild::TableCell(cell) in &mut row.cells {
|
||||
for content in &mut cell.children {
|
||||
match content {
|
||||
TableCellContent::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
TableCellContent::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
TableCellContent::StructuredDataTag(tag) => {
|
||||
for child in &mut tag.children {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) =
|
||||
child
|
||||
{
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
if let StructuredDataTagChild::Table(table) = child {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
TableCellContent::TableOfContents(t) => {
|
||||
for child in &mut t.before_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for child in &mut t.after_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
collect_images_from_table(table, &mut images, &mut image_bufs, None);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
(images, image_bufs)
|
||||
}
|
||||
|
||||
fn images_in_header(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
|
||||
let mut header_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
|
||||
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
||||
|
||||
if let Some(header) = &mut self.document.section_property.header.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in header.children.iter_mut() {
|
||||
match child {
|
||||
HeaderChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
header_images[0] = images;
|
||||
}
|
||||
|
||||
if let Some(header) = &mut self.document.section_property.even_header.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in header.children.iter_mut() {
|
||||
match child {
|
||||
HeaderChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
header_images[1] = images;
|
||||
}
|
||||
|
||||
if let Some(header) = &mut self.document.section_property.first_header.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in header.children.iter_mut() {
|
||||
match child {
|
||||
HeaderChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
HeaderChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("header"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
header_images[2] = images;
|
||||
}
|
||||
(header_images, image_bufs)
|
||||
}
|
||||
|
||||
// Traverse and collect images from header.
|
||||
fn images_in_footer(&mut self) -> (Vec<Vec<ImageIdAndPath>>, Vec<ImageIdAndBuf>) {
|
||||
let mut footer_images: Vec<Vec<ImageIdAndPath>> = vec![vec![]; 3];
|
||||
let mut image_bufs: Vec<(String, Vec<u8>)> = vec![];
|
||||
|
||||
if let Some(footer) = &mut self.document.section_property.footer.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in footer.children.iter_mut() {
|
||||
match child {
|
||||
FooterChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
footer_images[0] = images;
|
||||
}
|
||||
|
||||
if let Some(footer) = &mut self.document.section_property.even_footer.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in footer.children.iter_mut() {
|
||||
match child {
|
||||
FooterChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
footer_images[1] = images;
|
||||
}
|
||||
|
||||
if let Some(footer) = &mut self.document.section_property.first_footer.as_mut() {
|
||||
let mut images: Vec<ImageIdAndPath> = vec![];
|
||||
for child in footer.children.iter_mut() {
|
||||
match child {
|
||||
FooterChild::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(
|
||||
paragraph,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
FooterChild::Table(table) => {
|
||||
collect_images_from_table(
|
||||
table,
|
||||
&mut images,
|
||||
&mut image_bufs,
|
||||
Some("footer"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
footer_images[2] = images;
|
||||
}
|
||||
(footer_images, image_bufs)
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_dependencies_in_paragraph(
|
||||
|
@ -1147,95 +1262,6 @@ fn store_comments_in_table(table: &mut Table, comments: &[Comment]) {
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_images_from_paragraph(
|
||||
paragraph: &mut Paragraph,
|
||||
images: &mut Vec<(String, String)>,
|
||||
image_bufs: &mut Vec<(String, Vec<u8>)>,
|
||||
) {
|
||||
for child in &mut paragraph.children {
|
||||
if let ParagraphChild::Run(run) = child {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
let buf = image_bufs
|
||||
.iter()
|
||||
.find(|x| x.0 == pic.id.clone() || x.1 == b.clone());
|
||||
if buf.as_ref().is_none() {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
} else {
|
||||
pic.id = buf.unwrap().0.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let ParagraphChild::Insert(ins) = child {
|
||||
for child in &mut ins.children {
|
||||
match child {
|
||||
InsertChild::Run(run) => {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
InsertChild::Delete(del) => {
|
||||
for d in &mut del.children {
|
||||
if let DeleteChild::Run(run) = d {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
} else if let ParagraphChild::Delete(del) = child {
|
||||
for d in &mut del.children {
|
||||
if let DeleteChild::Run(run) = d {
|
||||
for child in &mut run.children {
|
||||
if let RunChild::Drawing(d) = child {
|
||||
if let Some(DrawingData::Pic(pic)) = &mut d.data {
|
||||
images.push((
|
||||
pic.id.clone(),
|
||||
// For now only png supported
|
||||
format!("media/{}.png", pic.id),
|
||||
));
|
||||
let b = std::mem::take(&mut pic.image);
|
||||
image_bufs.push((pic.id.clone(), b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn push_comment_and_comment_extended(
|
||||
comments: &mut Vec<Comment>,
|
||||
comments_extended: &mut Vec<CommentExtended>,
|
||||
|
@ -1261,56 +1287,6 @@ fn push_comment_and_comment_extended(
|
|||
}
|
||||
}
|
||||
|
||||
fn collect_images_from_table(
|
||||
table: &mut Table,
|
||||
images: &mut Vec<(String, String)>,
|
||||
image_bufs: &mut Vec<(String, Vec<u8>)>,
|
||||
) {
|
||||
for TableChild::TableRow(row) in &mut table.rows {
|
||||
for TableRowChild::TableCell(cell) in &mut row.cells {
|
||||
for content in &mut cell.children {
|
||||
match content {
|
||||
TableCellContent::Paragraph(paragraph) => {
|
||||
collect_images_from_paragraph(paragraph, images, image_bufs);
|
||||
}
|
||||
TableCellContent::Table(table) => {
|
||||
collect_images_from_table(table, images, image_bufs)
|
||||
}
|
||||
TableCellContent::StructuredDataTag(tag) => {
|
||||
for child in &mut tag.children {
|
||||
if let StructuredDataTagChild::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(paragraph, images, image_bufs);
|
||||
}
|
||||
if let StructuredDataTagChild::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs);
|
||||
}
|
||||
}
|
||||
}
|
||||
TableCellContent::TableOfContents(t) => {
|
||||
for child in &mut t.before_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(paragraph, images, image_bufs);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs);
|
||||
}
|
||||
}
|
||||
|
||||
for child in &mut t.after_contents {
|
||||
if let TocContent::Paragraph(paragraph) = child {
|
||||
collect_images_from_paragraph(paragraph, images, image_bufs);
|
||||
}
|
||||
if let TocContent::Table(table) = child {
|
||||
collect_images_from_table(table, images, image_bufs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update_document_by_toc(
|
||||
document_children: Vec<DocumentChild>,
|
||||
styles: &Styles,
|
||||
|
|
|
@ -18,7 +18,9 @@ pub struct XMLDocx {
|
|||
pub numberings: Vec<u8>,
|
||||
pub media: Vec<(String, Vec<u8>)>,
|
||||
pub headers: Vec<Vec<u8>>,
|
||||
pub header_rels: Vec<Vec<u8>>,
|
||||
pub footers: Vec<Vec<u8>>,
|
||||
pub footer_rels: Vec<Vec<u8>>,
|
||||
pub comments_extended: Vec<u8>,
|
||||
pub taskpanes: Option<Vec<u8>>,
|
||||
pub taskpanes_rels: Vec<u8>,
|
||||
|
|
|
@ -49,11 +49,21 @@ where
|
|||
for (i, h) in xml.headers.iter().enumerate() {
|
||||
zip.start_file(format!("word/header{}.xml", i + 1), options)?;
|
||||
zip.write_all(h)?;
|
||||
|
||||
if let Some(rels) = xml.header_rels.get(i) {
|
||||
zip.start_file(format!("word/_rels/header{}.xml.rels", i + 1), options)?;
|
||||
zip.write_all(rels)?;
|
||||
}
|
||||
}
|
||||
|
||||
for (i, h) in xml.footers.iter().enumerate() {
|
||||
zip.start_file(format!("word/footer{}.xml", i + 1), options)?;
|
||||
zip.write_all(h)?;
|
||||
|
||||
if let Some(rels) = xml.footer_rels.get(i) {
|
||||
zip.start_file(format!("word/_rels/footer{}.xml.rels", i + 1), options)?;
|
||||
zip.write_all(rels)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !xml.media.is_empty() {
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Bold = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BoldCs = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BorderType = "nil" | "none" | "single" | "thick" | "double" | "dotted" | "dashed" | "dotdash" | "dotdotdash" | "triple" | "thinthicksmallgap" | "thickthinsmallgap" | "thinthickthinsmallgap" | "thinthickmediumgap" | "thickthinmediumgap" | "thinthickthinmediumgap" | "thinthicklargegap" | "thickthinlargegap" | "thinthickthinlargegap" | "wave" | "doublewave" | "dashsmallgap" | "dashdotstroked" | "threedemboss" | "threedengrave" | "outset" | "inset" | "apples" | "archedscallops" | "babypacifier" | "babyrattle";
|
|
@ -0,0 +1,4 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { BreakType } from "./BreakType";
|
||||
|
||||
export interface Break { break_type: BreakType, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type BreakType = "Page" | "Column" | "TextWrapping" | "Unsupported";
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Caps = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type CharacterSpacing = number;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Color = string;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface Comment { id: number, author: string, date: string, children: any[], parentCommentId: number | null, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface CommentRangeEnd { id: number, }
|
|
@ -0,0 +1,4 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Comment } from "./Comment";
|
||||
|
||||
export interface CommentRangeStart { id: number, comment: Comment, }
|
|
@ -0,0 +1,4 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { DeleteChild } from "./DeleteChild";
|
||||
|
||||
export interface Delete { author: string, date: string, children: Array<DeleteChild>, }
|
|
@ -0,0 +1,6 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CommentRangeEnd } from "./CommentRangeEnd";
|
||||
import type { CommentRangeStart } from "./CommentRangeStart";
|
||||
import type { Run } from "./Run";
|
||||
|
||||
export type DeleteChild = { "Run": Run } | { "CommentStart": CommentRangeStart } | { "CommentEnd": CommentRangeEnd };
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface DeleteText { text: string, preserveSpace: boolean, }
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export interface FooterReference { footerType: string, id: string, }
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
export interface HeaderReference { headerType: string, id: string, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Highlight = string;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface Insert { children: any[], author: string, date: string, }
|
|
@ -0,0 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { CommentRangeEnd } from "./CommentRangeEnd";
|
||||
import type { CommentRangeStart } from "./CommentRangeStart";
|
||||
import type { Delete } from "./Delete";
|
||||
import type { Run } from "./Run";
|
||||
|
||||
export type InsertChild = { "Run": Run } | { "Delete": Delete } | { "CommentStart": CommentRangeStart } | { "CommentEnd": CommentRangeEnd };
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface InstrPAGEREF { pageRef: string, hyperlink: boolean, relativePosition: boolean, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface InstrTC { text: string, omitsPageNumber: boolean, level: number | null, itemTypeIdentifier: string | null, }
|
|
@ -0,0 +1,7 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { InstrHyperlink } from "./InstrHyperlink";
|
||||
import type { InstrPAGEREF } from "./InstrPAGEREF";
|
||||
import type { InstrTC } from "./InstrTC";
|
||||
import type { InstrToC } from "./InstrToC";
|
||||
|
||||
export type InstrText = { "TOC": InstrToC } | { "TC": InstrTC } | { "PAGEREF": InstrPAGEREF } | { "HYPERLINK": InstrHyperlink } | { "Unsupported": string };
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Italic = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type ItalicCs = boolean;
|
|
@ -0,0 +1,4 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { RunProperty } from "./RunProperty";
|
||||
|
||||
export interface Run { runProperty: RunProperty, children: any[], }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface RunFonts { ascii?: string, hiAnsi?: string, eastAsia?: string, cs?: string, asciiTheme?: string, hiAnsiTheme?: string, eastAsiaTheme?: string, csTheme?: string, hint?: string, }
|
|
@ -0,0 +1,23 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Bold } from "./Bold";
|
||||
import type { BoldCs } from "./BoldCs";
|
||||
import type { Caps } from "./Caps";
|
||||
import type { CharacterSpacing } from "./CharacterSpacing";
|
||||
import type { Color } from "./Color";
|
||||
import type { Delete } from "./Delete";
|
||||
import type { Highlight } from "./Highlight";
|
||||
import type { Insert } from "./Insert";
|
||||
import type { Italic } from "./Italic";
|
||||
import type { ItalicCs } from "./ItalicCs";
|
||||
import type { RunFonts } from "./RunFonts";
|
||||
import type { RunStyle } from "./RunStyle";
|
||||
import type { SpecVanish } from "./SpecVanish";
|
||||
import type { Strike } from "./Strike";
|
||||
import type { Sz } from "./Sz";
|
||||
import type { SzCs } from "./SzCs";
|
||||
import type { TextBorder } from "./TextBorder";
|
||||
import type { Underline } from "./Underline";
|
||||
import type { Vanish } from "./Vanish";
|
||||
import type { VertAlign } from "./VertAlign";
|
||||
|
||||
export interface RunProperty { style?: RunStyle, sz?: Sz, szCs?: SzCs, color?: Color, highlight?: Highlight, vertAlign?: VertAlign, underline?: Underline, bold?: Bold, boldCs?: BoldCs, caps?: Caps, italic?: Italic, italicCs?: ItalicCs, vanish?: Vanish, specVanish?: SpecVanish, characterSpacing?: CharacterSpacing, fonts?: RunFonts, textBorder?: TextBorder, del?: Delete, ins?: Insert, strike?: Strike, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type RunStyle = string;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SpecVanish = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Strike = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface Sym { font: string, char: string, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Sz = number;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type SzCs = number;
|
|
@ -0,0 +1,5 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { TabLeaderType } from "./TabLeaderType";
|
||||
import type { TabValueType } from "./TabValueType";
|
||||
|
||||
export interface Tab { val: TabValueType | null, leader: TabLeaderType | null, pos: number | null, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type TabLeaderType = "dot" | "heavy" | "hyphen" | "middledot" | "none" | "underscore";
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type TabValueType = "bar" | "center" | "clear" | "decimal" | "end" | "right" | "num" | "start" | "left";
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export interface Text { text: string, preserveSpace: boolean, }
|
|
@ -0,0 +1,4 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { BorderType } from "./BorderType";
|
||||
|
||||
export interface TextBorder { borderType: BorderType, size: number, color: string, space: number, }
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Underline = string;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type Vanish = boolean;
|
|
@ -0,0 +1,3 @@
|
|||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
|
||||
export type VertAlign = string;
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "docx-wasm",
|
||||
"version": "0.0.278-rc27",
|
||||
"version": "0.4.8",
|
||||
"main": "dist/node/index.js",
|
||||
"browser": "dist/web/index.js",
|
||||
"author": "bokuweb <bokuweb12@gmail.com>",
|
||||
|
|
|
@ -162826,6 +162826,11 @@ exports[`writer should write evenFooter with table for default section 3`] = `
|
|||
</w:tblCellMar><w:tblInd w:w=\\"0\\" w:type=\\"dxa\\" /></w:tblPr><w:tblGrid /><w:tr><w:trPr /><w:tc><w:tcPr><w:tcBorders><w:top w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:left w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:bottom w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:right w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideH w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideV w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /></w:tcBorders></w:tcPr><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello Footer!!</w:t></w:r></w:p></w:tc></w:tr></w:tbl></w:ftr>"
|
||||
`;
|
||||
|
||||
exports[`writer should write evenFooter with table for default section 4`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\" />"
|
||||
`;
|
||||
|
||||
exports[`writer should write external hyperlink 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
@ -162874,6 +162879,11 @@ exports[`writer should write firstHeader with table for default section 3`] = `
|
|||
</w:tblCellMar><w:tblInd w:w=\\"0\\" w:type=\\"dxa\\" /></w:tblPr><w:tblGrid /><w:tr><w:trPr /><w:tc><w:tcPr><w:tcBorders><w:top w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:left w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:bottom w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:right w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideH w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /><w:insideV w:val=\\"single\\" w:sz=\\"2\\" w:space=\\"0\\" w:color=\\"000000\\" /></w:tcBorders></w:tcPr><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello Header!!</w:t></w:r></w:p></w:tc></w:tr></w:tbl></w:hdr>"
|
||||
`;
|
||||
|
||||
exports[`writer should write firstHeader with table for default section 4`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\" />"
|
||||
`;
|
||||
|
||||
exports[`writer should write footer for default section 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
@ -162897,6 +162907,11 @@ exports[`writer should write footer for default section 3`] = `
|
|||
<w:ftr xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:o=\\"urn:schemas-microsoft-com:office:office\\" xmlns:v=\\"urn:schemas-microsoft-com:vml\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w10=\\"urn:schemas-microsoft-com:office:word\\" xmlns:wp=\\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\\" xmlns:wps=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\\" xmlns:wpg=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\\" xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:wp14=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" mc:Ignorable=\\"w14 wp14\\"><w:p w14:paraId=\\"00000002\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello Footer</w:t></w:r></w:p></w:ftr>"
|
||||
`;
|
||||
|
||||
exports[`writer should write footer for default section 4`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\" />"
|
||||
`;
|
||||
|
||||
exports[`writer should write header for default section 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
@ -162940,6 +162955,60 @@ exports[`writer should write hello 3`] = `
|
|||
</w:num></w:numbering>"
|
||||
`;
|
||||
|
||||
exports[`writer should write image in header 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
<Relationship Id=\\"rId1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\\" Target=\\"styles.xml\\" />
|
||||
<Relationship Id=\\"rId2\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable\\" Target=\\"fontTable.xml\\" />
|
||||
<Relationship Id=\\"rId3\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings\\" Target=\\"settings.xml\\" />
|
||||
<Relationship Id=\\"rId5\\" Type=\\"http://schemas.microsoft.com/office/2011/relationships/commentsExtended\\" Target=\\"commentsExtended.xml\\" />
|
||||
<Relationship Id=\\"rIdHeader1\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header\\" Target=\\"header1.xml\\" />
|
||||
<Relationship Id=\\"rIdImage5\\" Type=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image\\" Target=\\"media/rIdImage5.png\\" />
|
||||
</Relationships>"
|
||||
`;
|
||||
|
||||
exports[`writer should write image in header 2`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" standalone=\\"yes\\"?>
|
||||
<w:document xmlns:o=\\"urn:schemas-microsoft-com:office:office\\" xmlns:r=\\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\\" xmlns:v=\\"urn:schemas-microsoft-com:vml\\" xmlns:w=\\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\\" xmlns:w10=\\"urn:schemas-microsoft-com:office:word\\" xmlns:wp=\\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\\" xmlns:wps=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingShape\\" xmlns:wpg=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingGroup\\" xmlns:mc=\\"http://schemas.openxmlformats.org/markup-compatibility/2006\\" xmlns:wp14=\\"http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing\\" xmlns:w14=\\"http://schemas.microsoft.com/office/word/2010/wordml\\" xmlns:w15=\\"http://schemas.microsoft.com/office/word/2012/wordml\\" mc:Ignorable=\\"w14 wp14\\">
|
||||
<w:body><w:p w14:paraId=\\"00000001\\"><w:pPr><w:rPr /></w:pPr><w:r><w:rPr /><w:t xml:space=\\"preserve\\">Hello world!!</w:t><w:drawing>
|
||||
<wp:inline distT=\\"0\\" distB=\\"0\\" distL=\\"0\\" distR=\\"0\\">
|
||||
<wp:extent cx=\\"3048000\\" cy=\\"2286000\\" />
|
||||
<wp:effectExtent b=\\"0\\" l=\\"0\\" r=\\"0\\" t=\\"0\\" />
|
||||
<wp:docPr id=\\"1\\" name=\\"Figure\\" />
|
||||
<wp:cNvGraphicFramePr>
|
||||
<a:graphicFrameLocks xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" noChangeAspect=\\"1\\" />
|
||||
</wp:cNvGraphicFramePr>
|
||||
<a:graphic xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\">
|
||||
<a:graphicData uri=\\"http://schemas.openxmlformats.org/drawingml/2006/picture\\"><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=\\"rIdImage5\\" />
|
||||
<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></a:graphicData>
|
||||
</a:graphic>
|
||||
</wp:inline>
|
||||
</w:drawing></w:r></w:p><w:sectPr><w:pgSz w:w=\\"11906\\" w:h=\\"16838\\" /><w:pgMar w:top=\\"1985\\" w:right=\\"1701\\" w:bottom=\\"1701\\" w:left=\\"1701\\" w:header=\\"851\\" w:footer=\\"992\\" w:gutter=\\"0\\" /><w:cols w:space=\\"425\\" w:num=\\"1\\" /><w:headerReference w:type=\\"default\\" r:id=\\"rIdHeader1\\" /></w:sectPr></w:body>
|
||||
</w:document>"
|
||||
`;
|
||||
|
||||
exports[`writer should write inline image 1`] = `
|
||||
"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
|
||||
<Relationships xmlns=\\"http://schemas.openxmlformats.org/package/2006/relationships\\">
|
||||
|
|
|
@ -192,7 +192,9 @@ describe("reader", () => {
|
|||
});
|
||||
|
||||
test("should read default line spacing", () => {
|
||||
const buffer = readFileSync("../fixtures/default_line_spacing/default_line_spacing.docx");
|
||||
const buffer = readFileSync(
|
||||
"../fixtures/default_line_spacing/default_line_spacing.docx"
|
||||
);
|
||||
const json = w.readDocx(buffer);
|
||||
expect(json).toMatchSnapshot();
|
||||
});
|
||||
|
@ -1006,4 +1008,23 @@ describe("writer", () => {
|
|||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("should write image in header", () => {
|
||||
const buf = Buffer.from(encodedCat, "base64");
|
||||
const image = new w.Image(buf).size(320 * 9525, 240 * 9525);
|
||||
const p = new w.Paragraph().addRun(
|
||||
new w.Run().addText("Hello world!!").addImage(image)
|
||||
);
|
||||
const header = new w.Header().addParagraph(p);
|
||||
const buffer = new w.Docx().header(header).addParagraph(p).build();
|
||||
|
||||
writeFileSync("../output/js/header_in_image.docx", buffer);
|
||||
|
||||
const z = new Zip(Buffer.from(buffer));
|
||||
for (const e of z.getEntries()) {
|
||||
if (e.entryName.match(/document.xml/)) {
|
||||
expect(z.readAsText(e)).toMatchSnapshot();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue