parent
961d53e678
commit
713c18fee2
|
@ -71,6 +71,7 @@ mod run_style;
|
|||
mod section;
|
||||
mod section_property;
|
||||
mod shading;
|
||||
mod shape;
|
||||
mod start;
|
||||
mod strike;
|
||||
mod structured_data_tag;
|
||||
|
@ -184,6 +185,7 @@ pub use run_style::*;
|
|||
pub use section::*;
|
||||
pub use section_property::*;
|
||||
pub use shading::*;
|
||||
pub use shape::*;
|
||||
pub use start::*;
|
||||
pub use strike::*;
|
||||
pub use structured_data_tag::*;
|
||||
|
|
|
@ -30,6 +30,7 @@ pub enum RunChild {
|
|||
Tab(Tab),
|
||||
Break(Break),
|
||||
Drawing(Box<Drawing>),
|
||||
Shape(Box<Shape>),
|
||||
CommentStart(Box<CommentRangeStart>),
|
||||
CommentEnd(CommentRangeEnd),
|
||||
FieldChar(FieldChar),
|
||||
|
@ -71,6 +72,12 @@ impl Serialize for RunChild {
|
|||
t.serialize_field("data", s)?;
|
||||
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) => {
|
||||
let mut t = serializer.serialize_struct("CommentRangeStart", 2)?;
|
||||
t.serialize_field("type", "commentRangeStart")?;
|
||||
|
@ -149,6 +156,12 @@ impl Run {
|
|||
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 {
|
||||
self.children.push(RunChild::Break(Break::new(break_type)));
|
||||
self
|
||||
|
@ -236,6 +249,9 @@ impl BuildXML for Run {
|
|||
RunChild::Tab(t) => b = b.add_child(t),
|
||||
RunChild::Break(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::CommentEnd(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 delete;
|
||||
mod div;
|
||||
mod shape;
|
||||
mod doc_defaults;
|
||||
mod doc_grid;
|
||||
mod document;
|
||||
|
|
|
@ -87,10 +87,6 @@ impl ElementReader for Run {
|
|||
if let Ok(drawing) = Drawing::read(r, &attributes) {
|
||||
run = run.add_drawing(drawing);
|
||||
}
|
||||
}
|
||||
// For now, we treat pict ad drawing
|
||||
XMLElement::Pict => {
|
||||
|
||||
}
|
||||
XMLElement::FieldChar => {
|
||||
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,
|
||||
TextBox,
|
||||
Shape,
|
||||
ImageData,
|
||||
Unsupported,
|
||||
}
|
||||
|
||||
|
@ -452,6 +453,7 @@ impl FromStr for VXMLElement {
|
|||
"fill" => Ok(VXMLElement::Fill),
|
||||
"textbox" => Ok(VXMLElement::TextBox),
|
||||
"shape" => Ok(VXMLElement::Shape),
|
||||
"imagedata" => Ok(VXMLElement::ImageData),
|
||||
_ => 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 { ShapeJSON } from "./shape";
|
||||
import { CommentRangeStartJSON, CommentRangeEndJSON } from "..";
|
||||
import { BorderType } from "../border";
|
||||
import { InsertJSON, DeleteJSON } from "./paragraph";
|
||||
|
@ -50,6 +51,7 @@ export type RunChildJSON =
|
|||
| TabJSON
|
||||
| BreakJSON
|
||||
| DrawingJSON
|
||||
| ShapeJSON
|
||||
| CommentRangeStartJSON
|
||||
| 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",
|
||||
"copy": "cpy 'dist/node/pkg/package.json' 'dist/web/pkg'",
|
||||
"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"
|
||||
},
|
||||
"resolutions": {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -147,6 +147,12 @@ describe("reader", () => {
|
|||
const json = w.readDocx(buffer);
|
||||
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", () => {
|
||||
|
|
Binary file not shown.
Loading…
Reference in New Issue