parent
961d53e678
commit
713c18fee2
|
@ -71,6 +71,7 @@ mod run_style;
|
||||||
mod section;
|
mod section;
|
||||||
mod section_property;
|
mod section_property;
|
||||||
mod shading;
|
mod shading;
|
||||||
|
mod shape;
|
||||||
mod start;
|
mod start;
|
||||||
mod strike;
|
mod strike;
|
||||||
mod structured_data_tag;
|
mod structured_data_tag;
|
||||||
|
@ -184,6 +185,7 @@ pub use run_style::*;
|
||||||
pub use section::*;
|
pub use section::*;
|
||||||
pub use section_property::*;
|
pub use section_property::*;
|
||||||
pub use shading::*;
|
pub use shading::*;
|
||||||
|
pub use shape::*;
|
||||||
pub use start::*;
|
pub use start::*;
|
||||||
pub use strike::*;
|
pub use strike::*;
|
||||||
pub use structured_data_tag::*;
|
pub use structured_data_tag::*;
|
||||||
|
|
|
@ -30,6 +30,7 @@ pub enum RunChild {
|
||||||
Tab(Tab),
|
Tab(Tab),
|
||||||
Break(Break),
|
Break(Break),
|
||||||
Drawing(Box<Drawing>),
|
Drawing(Box<Drawing>),
|
||||||
|
Shape(Box<Shape>),
|
||||||
CommentStart(Box<CommentRangeStart>),
|
CommentStart(Box<CommentRangeStart>),
|
||||||
CommentEnd(CommentRangeEnd),
|
CommentEnd(CommentRangeEnd),
|
||||||
FieldChar(FieldChar),
|
FieldChar(FieldChar),
|
||||||
|
@ -71,6 +72,12 @@ impl Serialize for RunChild {
|
||||||
t.serialize_field("data", s)?;
|
t.serialize_field("data", s)?;
|
||||||
t.end()
|
t.end()
|
||||||
}
|
}
|
||||||
|
RunChild::Shape(ref s) => {
|
||||||
|
let mut t = serializer.serialize_struct("Shape", 2)?;
|
||||||
|
t.serialize_field("type", "shape")?;
|
||||||
|
t.serialize_field("data", s)?;
|
||||||
|
t.end()
|
||||||
|
}
|
||||||
RunChild::CommentStart(ref r) => {
|
RunChild::CommentStart(ref r) => {
|
||||||
let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
|
let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
|
||||||
t.serialize_field("type", "commentRangeStart")?;
|
t.serialize_field("type", "commentRangeStart")?;
|
||||||
|
@ -149,6 +156,12 @@ impl Run {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For now reader only
|
||||||
|
// pub(crate) fn add_shape(mut self, d: Shape) -> Run {
|
||||||
|
// self.children.push(RunChild::Shape(Box::new(d)));
|
||||||
|
// self
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn add_break(mut self, break_type: BreakType) -> Run {
|
pub fn add_break(mut self, break_type: BreakType) -> Run {
|
||||||
self.children.push(RunChild::Break(Break::new(break_type)));
|
self.children.push(RunChild::Break(Break::new(break_type)));
|
||||||
self
|
self
|
||||||
|
@ -236,6 +249,9 @@ impl BuildXML for Run {
|
||||||
RunChild::Tab(t) => b = b.add_child(t),
|
RunChild::Tab(t) => b = b.add_child(t),
|
||||||
RunChild::Break(t) => b = b.add_child(t),
|
RunChild::Break(t) => b = b.add_child(t),
|
||||||
RunChild::Drawing(t) => b = b.add_child(t),
|
RunChild::Drawing(t) => b = b.add_child(t),
|
||||||
|
RunChild::Shape(_t) => {
|
||||||
|
todo!("Support shape writer.")
|
||||||
|
}
|
||||||
RunChild::CommentStart(c) => b = b.add_child(c),
|
RunChild::CommentStart(c) => b = b.add_child(c),
|
||||||
RunChild::CommentEnd(c) => b = b.add_child(c),
|
RunChild::CommentEnd(c) => b = b.add_child(c),
|
||||||
RunChild::FieldChar(c) => b = b.add_child(c),
|
RunChild::FieldChar(c) => b = b.add_child(c),
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Clone, PartialEq, Default, ts_rs::TS)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct Shape {
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub style: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub image_data: Option<ImageData>,
|
||||||
|
}
|
||||||
|
// Experimental, For now reader only.
|
||||||
|
|
||||||
|
#[derive(Serialize, Debug, Clone, PartialEq, Default, ts_rs::TS)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ImageData {
|
||||||
|
pub id: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Shape {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Default::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn style(mut self, style: impl Into<String>) -> Self {
|
||||||
|
self.style = Some(style.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn image_data(mut self, id: impl Into<String>) -> Self {
|
||||||
|
self.image_data = Some(ImageData { id: id.into() });
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl BuildXML for Shape {
|
||||||
|
// fn build(&self) -> Vec<u8> {
|
||||||
|
// let b = XMLBuilder::new();
|
||||||
|
// let mut b = b.open_pict();
|
||||||
|
// b = b.add_child(t),
|
||||||
|
// b.close().build()
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -10,6 +10,7 @@ mod comments_extended;
|
||||||
mod custom_properties;
|
mod custom_properties;
|
||||||
mod delete;
|
mod delete;
|
||||||
mod div;
|
mod div;
|
||||||
|
mod shape;
|
||||||
mod doc_defaults;
|
mod doc_defaults;
|
||||||
mod doc_grid;
|
mod doc_grid;
|
||||||
mod document;
|
mod document;
|
||||||
|
|
|
@ -87,10 +87,6 @@ impl ElementReader for Run {
|
||||||
if let Ok(drawing) = Drawing::read(r, &attributes) {
|
if let Ok(drawing) = Drawing::read(r, &attributes) {
|
||||||
run = run.add_drawing(drawing);
|
run = run.add_drawing(drawing);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// For now, we treat pict ad drawing
|
|
||||||
XMLElement::Pict => {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
XMLElement::FieldChar => {
|
XMLElement::FieldChar => {
|
||||||
if let Ok(f) = read_field_char(&attributes) {
|
if let Ok(f) = read_field_char(&attributes) {
|
||||||
|
@ -114,6 +110,18 @@ impl ElementReader for Run {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some("v") => {
|
||||||
|
let e = VXMLElement::from_str(&name.local_name).unwrap();
|
||||||
|
match e {
|
||||||
|
// Experimental For now support only imageData in shape
|
||||||
|
VXMLElement::Shape => {
|
||||||
|
if let Ok(shape) = Shape::read(r, &attributes) {
|
||||||
|
run.children.push(RunChild::Shape(Box::new(shape)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
#![allow(clippy::single_match)]
|
||||||
|
|
||||||
|
use std::io::Read;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use xml::attribute::OwnedAttribute;
|
||||||
|
use xml::reader::{EventReader, XmlEvent};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl ElementReader for Shape {
|
||||||
|
fn read<R: Read>(
|
||||||
|
r: &mut EventReader<R>,
|
||||||
|
attrs: &[OwnedAttribute],
|
||||||
|
) -> Result<Self, ReaderError> {
|
||||||
|
let mut shape = Shape::new();
|
||||||
|
if let Some(style) = read(attrs, "style") {
|
||||||
|
shape = shape.style(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let e = r.next();
|
||||||
|
match e {
|
||||||
|
Ok(XmlEvent::StartElement {
|
||||||
|
name, attributes, ..
|
||||||
|
}) => {
|
||||||
|
if let Ok(VXMLElement::ImageData) = VXMLElement::from_str(&name.local_name) {
|
||||||
|
if let Some(id) = read(&attributes, "id") {
|
||||||
|
shape = shape.image_data(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { name, .. }) => {
|
||||||
|
let e = VXMLElement::from_str(&name.local_name).unwrap();
|
||||||
|
if e == VXMLElement::Shape {
|
||||||
|
return Ok(shape);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => return Err(ReaderError::XMLReadError),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -211,6 +211,7 @@ pub enum VXMLElement {
|
||||||
Fill,
|
Fill,
|
||||||
TextBox,
|
TextBox,
|
||||||
Shape,
|
Shape,
|
||||||
|
ImageData,
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,6 +453,7 @@ impl FromStr for VXMLElement {
|
||||||
"fill" => Ok(VXMLElement::Fill),
|
"fill" => Ok(VXMLElement::Fill),
|
||||||
"textbox" => Ok(VXMLElement::TextBox),
|
"textbox" => Ok(VXMLElement::TextBox),
|
||||||
"shape" => Ok(VXMLElement::Shape),
|
"shape" => Ok(VXMLElement::Shape),
|
||||||
|
"imagedata" => Ok(VXMLElement::ImageData),
|
||||||
_ => Ok(VXMLElement::Unsupported),
|
_ => Ok(VXMLElement::Unsupported),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
|
||||||
|
export interface ImageData { id: string, }
|
|
@ -0,0 +1,3 @@
|
||||||
|
import type { ImageData } from "./ImageData";
|
||||||
|
|
||||||
|
export interface Shape { style?: string, imageData?: ImageData, }
|
|
@ -1,4 +1,5 @@
|
||||||
import { DrawingJSON } from "./drawing";
|
import { DrawingJSON } from "./drawing";
|
||||||
|
import { ShapeJSON } from "./shape";
|
||||||
import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
|
import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
|
||||||
import { BorderType } from "../border";
|
import { BorderType } from "../border";
|
||||||
import { InsertJSON, DeleteJSON } from "./paragraph";
|
import { InsertJSON, DeleteJSON } from "./paragraph";
|
||||||
|
@ -50,6 +51,7 @@ export type RunChildJSON =
|
||||||
| TabJSON
|
| TabJSON
|
||||||
| BreakJSON
|
| BreakJSON
|
||||||
| DrawingJSON
|
| DrawingJSON
|
||||||
|
| ShapeJSON
|
||||||
| CommentRangeStartJSON
|
| CommentRangeStartJSON
|
||||||
| CommentRangeEndJSON;
|
| CommentRangeEndJSON;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { Shape } from "./bindings/Shape";
|
||||||
|
|
||||||
|
export type ShapeJSON = {
|
||||||
|
type: "shape";
|
||||||
|
data: Shape;
|
||||||
|
};
|
|
@ -18,7 +18,7 @@
|
||||||
"serve": "webpack-dev-server --open --config webpack.dev.js",
|
"serve": "webpack-dev-server --open --config webpack.dev.js",
|
||||||
"copy": "cpy 'dist/node/pkg/package.json' 'dist/web/pkg'",
|
"copy": "cpy 'dist/node/pkg/package.json' 'dist/web/pkg'",
|
||||||
"tsrs": "cd ../ && make test",
|
"tsrs": "cd ../ && make test",
|
||||||
"copy:bindings": "cpy '../docx-core/bindings' './js/json/bindings'",
|
"copy:bindings": "cpy '../docx-core/bindings' './js/json'",
|
||||||
"prepublishOnly": "npm run build"
|
"prepublishOnly": "npm run build"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -147,6 +147,12 @@ describe("reader", () => {
|
||||||
const json = w.readDocx(buffer);
|
const json = w.readDocx(buffer);
|
||||||
expect(json).toMatchSnapshot();
|
expect(json).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should read imagedata in shape", () => {
|
||||||
|
const buffer = readFileSync("../fixtures/shape/shape.docx");
|
||||||
|
const json = w.readDocx(buffer);
|
||||||
|
expect(json).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("writer", () => {
|
describe("writer", () => {
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue