fix: shape reader (#490)

Co-authored-by: bokuweb <bokuweb@bokuwebnombp.lan>
main
bokuweb 2022-06-08 00:44:51 +09:00 committed by GitHub
parent 961d53e678
commit 713c18fee2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 18615 additions and 5 deletions

View File

@ -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::*;

View File

@ -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),

View File

@ -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()
// }
// }

View File

@ -10,6 +10,7 @@ mod comments_extended;
mod custom_properties;
mod delete;
mod div;
mod shape;
mod doc_defaults;
mod doc_grid;
mod document;

View File

@ -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)));
}
}
_ => {}
}
}
_ => {}
};
}

View File

@ -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),
_ => {}
}
}
}
}

View File

@ -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),
}
}

View File

@ -0,0 +1,2 @@
export interface ImageData { id: string, }

View File

@ -0,0 +1,3 @@
import type { ImageData } from "./ImageData";
export interface Shape { style?: string, imageData?: ImageData, }

View File

@ -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;

View File

@ -0,0 +1,6 @@
import { Shape } from "./bindings/Shape";
export type ShapeJSON = {
type: "shape";
data: Shape;
};

View File

@ -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

View File

@ -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.