1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use anyhow::bail;
use quick_xml::events::{BytesStart, Event};
use std::io::Read;
use crate::{
excel::XmlReader,
helper::{string_to_bool, string_to_int},
};
use super::{
extents::{XlsxChildExtent, XlsxExtents},
offset::{XlsxChildOffset, XlsxOffset},
};
/// https://learn.microsoft.com/en-us/dotnet/api/documentformat.openxml.drawing.transformgroup?view=openxml-3.0.1
///
/// This element is nearly identical to the representation of 2-D transforms for ordinary shapes (ยง20.1.7.6).
/// The only addition is a member to represent the Child offset and the Child extents.
///
/// Example
/// ```
/// <a:xfrm>
/// <a:off x="838200" y="990600"/>
/// <a:ext cx="2426208" cy="978408"/>
/// <a:chOff x="838200" y="990600"/>
/// <a:chExt cx="2426208" cy="978408"/>
/// </a:xfrm>
/// ```
///
/// tag: xfrm (2D Transform for Grouped Objects)
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxTransformGroup {
// Child Elements
// chExt (Child Extents)
pub child_extents: Option<XlsxChildExtent>,
// chOff (Child Offset)
pub child_offset: Option<XlsxChildOffset>,
// ext (Extents)
pub extents: Option<XlsxExtents>,
// off (Offset)
pub offset: Option<XlsxOffset>,
// Attributes
///Specifies a horizontal flip.
/// When true, this attribute defines that the shape is flipped horizontally about the center of its bounding box.
// flipH (Horizontal Flip)
pub horizontal_flip: Option<bool>,
/// Specifies a vertical flip.
/// When true, this attribute defines that the group is flipped vertically about the center of its bounding box.
// flipV (Vertical Flip)
pub vertical_flip: Option<bool>,
/// Specifies the rotation angle of the Graphic Frame.
// rot (Rotation)
pub rotation: Option<i64>,
}
impl XlsxTransformGroup {
pub(crate) fn load(reader: &mut XmlReader<impl Read>, e: &BytesStart) -> anyhow::Result<Self> {
let mut transform = Self {
child_extents: None,
child_offset: None,
extents: None,
offset: None,
horizontal_flip: None,
vertical_flip: None,
rotation: None,
};
let attributes = e.attributes();
for a in attributes {
match a {
Ok(a) => {
let string_value = String::from_utf8(a.value.to_vec())?;
match a.key.local_name().as_ref() {
b"flipH" => {
transform.horizontal_flip = string_to_bool(&string_value);
}
b"flipV" => {
transform.vertical_flip = string_to_bool(&string_value);
}
b"rot" => {
transform.rotation = string_to_int(&string_value);
}
_ => {}
}
}
Err(error) => {
bail!(error.to_string())
}
}
}
let mut buf = Vec::new();
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"ext" => {
transform.extents = Some(XlsxExtents::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"off" => {
transform.offset = Some(XlsxOffset::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"chExt" => {
transform.child_extents = Some(XlsxChildExtent::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"chOff" => {
transform.child_offset = Some(XlsxChildOffset::load(e)?);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"xfrm" => break,
Ok(Event::Eof) => bail!("unexpected end of file at `xfrm`."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(transform)
}
}