Skip to content

Commit 8646553

Browse files
authored
Support image align (#564)
* support image align right * add test case * add PicAlign Center * testcase update * change fmt importing * lint error update * align setting move to child
1 parent 51af3ac commit 8646553

File tree

6 files changed

+148
-7
lines changed

6 files changed

+148
-7
lines changed

docx-core/src/documents/elements/drawing.rs

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,15 @@ impl BuildXML for Box<Drawing> {
8989
)
9090
.open_position_h(&format!("{}", p.relative_from_h));
9191

92+
match p.position_h {
93+
DrawingPosition::Offset(x) => {
94+
let x = format!("{}", x as u32);
95+
b = b.pos_offset(&x).close();
96+
}
97+
DrawingPosition::Align(x) => {
98+
b = b.align(&x.to_string()).close();
99+
}
100+
}
92101
if let DrawingPosition::Offset(x) = p.position_h {
93102
let x = format!("{}", x as u32);
94103
b = b.pos_offset(&x).close();
@@ -108,8 +117,13 @@ impl BuildXML for Box<Drawing> {
108117
// Please see 20.4.2.7 extent (Drawing Object Size)
109118
// One inch equates to 914400 EMUs and a centimeter is 360000
110119
.wp_extent(&w, &h)
111-
.wp_effect_extent("0", "0", "0", "0")
112-
.wrap_none()
120+
.wp_effect_extent("0", "0", "0", "0");
121+
if p.allow_overlap {
122+
b = b.wrap_none();
123+
} else if p.position_type == DrawingPositionType::Anchor {
124+
b = b.wrap_square("bothSides");
125+
}
126+
b = b
113127
.wp_doc_pr("1", "Figure")
114128
.open_wp_c_nv_graphic_frame_pr()
115129
.a_graphic_frame_locks(
@@ -151,6 +165,55 @@ mod tests {
151165
assert_eq!(
152166
str::from_utf8(&d).unwrap(),
153167
r#"<w:drawing>
168+
<wp:inline distT="0" distB="0" distL="0" distR="0">
169+
<wp:extent cx="3048000" cy="2286000" />
170+
<wp:effectExtent b="0" l="0" r="0" t="0" />
171+
<wp:docPr id="1" name="Figure" />
172+
<wp:cNvGraphicFramePr>
173+
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
174+
</wp:cNvGraphicFramePr>
175+
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
176+
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
177+
<pic:nvPicPr>
178+
<pic:cNvPr id="0" name="" />
179+
<pic:cNvPicPr>
180+
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
181+
</pic:cNvPicPr>
182+
</pic:nvPicPr>
183+
<pic:blipFill>
184+
<a:blip r:embed="rIdImage123" />
185+
<a:srcRect />
186+
<a:stretch>
187+
<a:fillRect />
188+
</a:stretch>
189+
</pic:blipFill>
190+
<pic:spPr bwMode="auto">
191+
<a:xfrm rot="0">
192+
<a:off x="0" y="0" />
193+
<a:ext cx="3048000" cy="2286000" />
194+
</a:xfrm>
195+
<a:prstGeom prst="rect">
196+
<a:avLst />
197+
</a:prstGeom>
198+
</pic:spPr>
199+
</pic:pic></a:graphicData>
200+
</a:graphic>
201+
</wp:inline>
202+
</w:drawing>"#
203+
);
204+
}
205+
206+
#[test]
207+
fn test_drawing_build_with_pic_overlap() {
208+
use std::io::Read;
209+
210+
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
211+
let mut buf = Vec::new();
212+
let _ = img.read_to_end(&mut buf).unwrap();
213+
let d = Box::new(Drawing::new().pic(Pic::new(&buf).overlapping())).build();
214+
assert_eq!(
215+
str::from_utf8(&d).unwrap(),
216+
r#"<w:drawing>
154217
<wp:inline distT="0" distB="0" distL="0" distR="0">
155218
<wp:extent cx="3048000" cy="2286000" />
156219
<wp:effectExtent b="0" l="0" r="0" t="0" />
@@ -186,6 +249,67 @@ mod tests {
186249
</pic:pic></a:graphicData>
187250
</a:graphic>
188251
</wp:inline>
252+
</w:drawing>"#
253+
);
254+
}
255+
256+
#[test]
257+
fn test_drawing_build_with_pic_align_right() {
258+
use std::io::Read;
259+
260+
let mut img = std::fs::File::open("../images/cat_min.jpg").unwrap();
261+
let mut buf = Vec::new();
262+
let _ = img.read_to_end(&mut buf).unwrap();
263+
let mut pic = Pic::new(&buf).floating();
264+
pic = pic.relative_from_h(RelativeFromHType::Column);
265+
pic = pic.relative_from_v(RelativeFromVType::Paragraph);
266+
pic = pic.position_h(DrawingPosition::Align(PicAlign::Right));
267+
let d = Box::new(Drawing::new().pic(pic)).build();
268+
assert_eq!(
269+
str::from_utf8(&d).unwrap(),
270+
r#"<w:drawing>
271+
<wp:anchor distT="0" distB="0" distL="0" distR="0" simplePos="0" allowOverlap="0" behindDoc="0" locked="0" layoutInCell="0" relativeHeight="190500">
272+
<wp:simplePos x="0" y="0" />
273+
<wp:positionH relativeFrom="column">
274+
<wp:align>right</wp:align>
275+
</wp:positionH>
276+
<wp:positionV relativeFrom="paragraph">
277+
<wp:posOffset>0</wp:posOffset>
278+
</wp:positionV>
279+
<wp:extent cx="3048000" cy="2286000" />
280+
<wp:effectExtent b="0" l="0" r="0" t="0" />
281+
<wp:wrapSquare wrapText="bothSides" />
282+
<wp:docPr id="1" name="Figure" />
283+
<wp:cNvGraphicFramePr>
284+
<a:graphicFrameLocks xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" noChangeAspect="1" />
285+
</wp:cNvGraphicFramePr>
286+
<a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
287+
<a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
288+
<pic:nvPicPr>
289+
<pic:cNvPr id="0" name="" />
290+
<pic:cNvPicPr>
291+
<a:picLocks noChangeAspect="1" noChangeArrowheads="1" />
292+
</pic:cNvPicPr>
293+
</pic:nvPicPr>
294+
<pic:blipFill>
295+
<a:blip r:embed="rIdImage123" />
296+
<a:srcRect />
297+
<a:stretch>
298+
<a:fillRect />
299+
</a:stretch>
300+
</pic:blipFill>
301+
<pic:spPr bwMode="auto">
302+
<a:xfrm rot="0">
303+
<a:off x="0" y="0" />
304+
<a:ext cx="3048000" cy="2286000" />
305+
</a:xfrm>
306+
<a:prstGeom prst="rect">
307+
<a:avLst />
308+
</a:prstGeom>
309+
</pic:spPr>
310+
</pic:pic></a:graphicData>
311+
</a:graphic>
312+
</wp:anchor>
189313
</w:drawing>"#
190314
);
191315
}

docx-core/src/documents/elements/pic.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ impl Pic {
126126
self
127127
}
128128

129+
pub fn overlapping(mut self) -> Pic {
130+
self.allow_overlap = true;
131+
self
132+
}
133+
129134
pub fn offset_x(mut self, x: i32) -> Pic {
130135
self.position_h = DrawingPosition::Offset(x);
131136
self

docx-core/src/types/drawing_position.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use serde::Serialize;
2+
use std::fmt;
23

34
use wasm_bindgen::prelude::*;
45

@@ -18,10 +19,23 @@ pub enum DrawingPositionType {
1819
pub enum PicAlign {
1920
Left,
2021
Right,
22+
Center,
2123
Bottom,
2224
Top,
2325
}
2426

27+
impl fmt::Display for PicAlign {
28+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
29+
match *self {
30+
PicAlign::Left => write!(f, "left"),
31+
PicAlign::Right => write!(f, "right"),
32+
PicAlign::Center => write!(f, "center"),
33+
PicAlign::Bottom => write!(f, "bottom"),
34+
PicAlign::Top => write!(f, "top"),
35+
}
36+
}
37+
}
38+
2539
#[derive(Debug, Clone, Copy, Serialize, PartialEq, ts_rs::TS)]
2640
#[ts(export)]
2741
#[serde(rename_all = "camelCase")]

docx-core/src/xml_builder/drawing.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@ impl XMLBuilder {
4343
open!(open_position_h, "wp:positionH", "relativeFrom");
4444
open!(open_position_v, "wp:positionV", "relativeFrom");
4545
closed_with_child!(pos_offset, "wp:posOffset");
46+
closed_with_child!(align, "wp:align");
4647
closed!(wrap_none, "wp:wrapNone");
48+
closed!(wrap_square, "wp:wrapSquare", "wrapText");
4749
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11

2-
export type PicAlign = "left" | "right" | "bottom" | "top";
2+
export type PicAlign = "left" | "right" | "center" | "bottom" | "top";

docx-wasm/test/__snapshots__/index.test.js.snap

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152363,7 +152363,6 @@ exports[`writer should write inline image 2`] = `
152363152363
<wp:inline distT=\\"0\\" distB=\\"0\\" distL=\\"0\\" distR=\\"0\\">
152364152364
<wp:extent cx=\\"3048000\\" cy=\\"2286000\\" />
152365152365
<wp:effectExtent b=\\"0\\" l=\\"0\\" r=\\"0\\" t=\\"0\\" />
152366-
<wp:wrapNone />
152367152366
<wp:docPr id=\\"1\\" name=\\"Figure\\" />
152368152367
<wp:cNvGraphicFramePr>
152369152368
<a:graphicFrameLocks xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" noChangeAspect=\\"1\\" />
@@ -152417,7 +152416,6 @@ exports[`writer should write inline jpeg image 2`] = `
152417152416
<wp:inline distT=\\"0\\" distB=\\"0\\" distL=\\"0\\" distR=\\"0\\">
152418152417
<wp:extent cx=\\"3048000\\" cy=\\"2286000\\" />
152419152418
<wp:effectExtent b=\\"0\\" l=\\"0\\" r=\\"0\\" t=\\"0\\" />
152420-
<wp:wrapNone />
152421152419
<wp:docPr id=\\"1\\" name=\\"Figure\\" />
152422152420
<wp:cNvGraphicFramePr>
152423152421
<a:graphicFrameLocks xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" noChangeAspect=\\"1\\" />
@@ -152471,7 +152469,6 @@ exports[`writer should write jpeg image with del 2`] = `
152471152469
<wp:inline distT=\\"0\\" distB=\\"0\\" distL=\\"0\\" distR=\\"0\\">
152472152470
<wp:extent cx=\\"3048000\\" cy=\\"2286000\\" />
152473152471
<wp:effectExtent b=\\"0\\" l=\\"0\\" r=\\"0\\" t=\\"0\\" />
152474-
<wp:wrapNone />
152475152472
<wp:docPr id=\\"1\\" name=\\"Figure\\" />
152476152473
<wp:cNvGraphicFramePr>
152477152474
<a:graphicFrameLocks xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" noChangeAspect=\\"1\\" />
@@ -152525,7 +152522,6 @@ exports[`writer should write jpeg image with ins 2`] = `
152525152522
<wp:inline distT=\\"0\\" distB=\\"0\\" distL=\\"0\\" distR=\\"0\\">
152526152523
<wp:extent cx=\\"3048000\\" cy=\\"2286000\\" />
152527152524
<wp:effectExtent b=\\"0\\" l=\\"0\\" r=\\"0\\" t=\\"0\\" />
152528-
<wp:wrapNone />
152529152525
<wp:docPr id=\\"1\\" name=\\"Figure\\" />
152530152526
<wp:cNvGraphicFramePr>
152531152527
<a:graphicFrameLocks xmlns:a=\\"http://schemas.openxmlformats.org/drawingml/2006/main\\" noChangeAspect=\\"1\\" />

0 commit comments

Comments
 (0)