Skip to content

Commit c262333

Browse files
committed
xlsx images
1 parent 2e3a137 commit c262333

File tree

4 files changed

+99
-21
lines changed

4 files changed

+99
-21
lines changed

src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_document.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,16 @@ class ElementAdapter final : public abstract::ElementAdapter,
577577
[[nodiscard]] std::string
578578
image_href(const ElementIdentifier element_id) const override {
579579
const pugi::xml_node node = get_node(element_id);
580-
return node.attribute("xlink:href").value();
580+
if (const pugi::xml_attribute ref = node.attribute("r:embed"); ref) {
581+
if (const auto [relations, origin] = get_relations_and_origin(element_id);
582+
relations != nullptr) {
583+
if (const auto rel = relations->find(ref.value());
584+
rel != std::end(*relations)) {
585+
return origin.parent().join(RelPath(rel->second)).string();
586+
}
587+
}
588+
}
589+
return ""; // TODO
581590
}
582591

583592
private:
@@ -595,6 +604,21 @@ class ElementAdapter final : public abstract::ElementAdapter,
595604
return {};
596605
}
597606

607+
[[nodiscard]] std::pair<const Relations *, AbsPath>
608+
get_relations_and_origin(const ElementIdentifier element_id) const {
609+
if (const ElementRegistry::Element *element =
610+
m_registry->element(element_id);
611+
element == nullptr) {
612+
return {nullptr, {}};
613+
}
614+
if (const ElementRegistry::ElementRelations *element_relations =
615+
m_registry->element_relations(element_id);
616+
element_relations != nullptr) {
617+
return {element_relations->relations, element_relations->origin};
618+
}
619+
return get_relations_and_origin(element_parent(element_id));
620+
}
621+
598622
[[nodiscard]] static std::string get_text(const pugi::xml_node node) {
599623
if (const std::string name = node.name(); name == "t" || name == "v") {
600624
return node.text().get();

src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,21 @@ ElementRegistry::create_sheet_cell_element(const pugi::xml_node node,
5555
return {element_id, element, it->second};
5656
}
5757

58+
ElementRegistry::ElementRelations &
59+
ElementRegistry::attach_element_relations(const ElementIdentifier id,
60+
const Relations &relations,
61+
const AbsPath &origin) {
62+
check_element_id(id);
63+
if (m_element_relations.contains(id)) {
64+
throw std::runtime_error("DocumentElementRegistry::attach_element_"
65+
"relations: relations already attached");
66+
}
67+
ElementRelations &result = m_element_relations[id];
68+
result.relations = &relations;
69+
result.origin = origin;
70+
return result;
71+
}
72+
5873
ElementRegistry::Element &
5974
ElementRegistry::element_at(const ElementIdentifier id) {
6075
check_element_id(id);
@@ -102,6 +117,15 @@ ElementRegistry::element(const ElementIdentifier id) const {
102117
return &m_elements.at(id - 1);
103118
}
104119

120+
const ElementRegistry::ElementRelations *
121+
ElementRegistry::element_relations(const ElementIdentifier id) const {
122+
if (const auto it = m_element_relations.find(id);
123+
it != m_element_relations.end()) {
124+
return &it->second;
125+
}
126+
return nullptr;
127+
}
128+
105129
const ElementRegistry::Text *
106130
ElementRegistry::text_element(const ElementIdentifier id) const {
107131
if (const auto it = m_texts.find(id); it != m_texts.end()) {

src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_element_registry.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#pragma once
22

3+
#include <odr/internal/common/path.hpp>
4+
5+
#include <odr/internal/ooxml/ooxml_util.hpp>
6+
37
#include <odr/definitions.hpp>
48
#include <odr/document_element.hpp>
59
#include <odr/table_dimension.hpp>
@@ -26,6 +30,11 @@ class ElementRegistry final {
2630
bool is_editable{false};
2731
};
2832

33+
struct ElementRelations final {
34+
const Relations *relations{nullptr};
35+
AbsPath origin;
36+
};
37+
2938
struct Text final {
3039
pugi::xml_node last;
3140
};
@@ -87,6 +96,10 @@ class ElementRegistry final {
8796
std::tuple<ElementIdentifier, Element &, SheetCell &>
8897
create_sheet_cell_element(pugi::xml_node node, const TablePosition &position);
8998

99+
ElementRelations &attach_element_relations(ElementIdentifier id,
100+
const Relations &relations,
101+
const AbsPath &origin);
102+
90103
[[nodiscard]] Element &element_at(ElementIdentifier id);
91104
[[nodiscard]] Sheet &sheet_element_at(ElementIdentifier id);
92105

@@ -97,6 +110,8 @@ class ElementRegistry final {
97110
[[nodiscard]] Text *text_element(ElementIdentifier id);
98111

99112
[[nodiscard]] const Element *element(ElementIdentifier id) const;
113+
[[nodiscard]] const ElementRelations *
114+
element_relations(ElementIdentifier id) const;
100115
[[nodiscard]] const Text *text_element(ElementIdentifier id) const;
101116
[[nodiscard]] const Sheet *sheet_element(ElementIdentifier id) const;
102117
[[nodiscard]] const SheetCell *sheet_cell_element(ElementIdentifier id) const;
@@ -107,6 +122,7 @@ class ElementRegistry final {
107122

108123
private:
109124
std::vector<Element> m_elements;
125+
std::unordered_map<ElementIdentifier, ElementRelations> m_element_relations;
110126
std::unordered_map<ElementIdentifier, Text> m_texts;
111127
std::unordered_map<ElementIdentifier, Sheet> m_sheets;
112128
std::unordered_map<ElementIdentifier, SheetCell> m_sheet_cells;

src/odr/internal/ooxml/spreadsheet/ooxml_spreadsheet_parser.cpp

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,22 +90,6 @@ void parse_sheet_cell_children(ElementRegistry &registry,
9090
parse_any_element_children(registry, context, parent_id, node);
9191
}
9292

93-
void parse_frame_children(ElementRegistry &registry,
94-
const ParseContext &context,
95-
const ElementIdentifier parent_id,
96-
const pugi::xml_node node) {
97-
(void)registry;
98-
(void)context;
99-
(void)parent_id;
100-
if (const pugi::xml_node image_node =
101-
node.child("xdr:pic").child("xdr:blipFill").child("a:blip")) {
102-
(void)image_node;
103-
// TODO
104-
// auto [image, _] = parse_any_element_tree(registry, context, image_node);
105-
// registry.append_child(parent_id, image);
106-
}
107-
}
108-
10993
std::tuple<ElementIdentifier, pugi::xml_node>
11094
parse_sheet_element(ElementRegistry &registry, const ParseContext &context,
11195
const pugi::xml_node node) {
@@ -114,6 +98,9 @@ parse_sheet_element(ElementRegistry &registry, const ParseContext &context,
11498
}
11599

116100
const auto &[element_id, _, sheet] = registry.create_sheet_element(node);
101+
registry.attach_element_relations(element_id,
102+
context.get_document_relations(),
103+
context.get_document_path());
117104

118105
for (const pugi::xml_node col_node : node.child("cols").children("col")) {
119106
const std::uint32_t min = col_node.attribute("min").as_uint() - 1;
@@ -158,9 +145,14 @@ parse_sheet_element(ElementRegistry &registry, const ParseContext &context,
158145
const auto &[drawing_xml, drawing_relations] =
159146
context.get_documents_and_relations().at(drawing_path);
160147

148+
const ParseContext drawing_context(drawing_path, drawing_relations,
149+
context.get_documents_and_relations(),
150+
context.get_shared_strings());
151+
161152
for (const pugi::xml_node shape_node :
162153
drawing_xml.document_element().children()) {
163-
auto [shape, _] = parse_any_element_tree(registry, context, shape_node);
154+
const auto [shape, _] =
155+
parse_any_element_tree(registry, drawing_context, shape_node);
164156
if (shape == null_element_id) {
165157
continue;
166158
}
@@ -207,6 +199,30 @@ parse_text_element(ElementRegistry &registry, const ParseContext &context,
207199
return {element_id, last.next_sibling()};
208200
}
209201

202+
std::tuple<ElementIdentifier, pugi::xml_node>
203+
parse_frame_element(ElementRegistry &registry, const ParseContext &context,
204+
const pugi::xml_node node) {
205+
if (!node) {
206+
return {null_element_id, pugi::xml_node()};
207+
}
208+
209+
const auto &[element_id, _] =
210+
registry.create_element(ElementType::frame, node);
211+
registry.attach_element_relations(element_id,
212+
context.get_document_relations(),
213+
context.get_document_path());
214+
215+
if (const pugi::xml_node image_node =
216+
node.child("xdr:pic").child("xdr:blipFill").child("a:blip")) {
217+
auto [image, _] =
218+
parse_element_tree(registry, context, ElementType::image, image_node,
219+
parse_any_element_children);
220+
registry.append_child(element_id, image);
221+
}
222+
223+
return {element_id, node.next_sibling()};
224+
}
225+
210226
std::tuple<ElementIdentifier, pugi::xml_node>
211227
parse_any_element_tree(ElementRegistry &registry, const ParseContext &context,
212228
const pugi::xml_node node) {
@@ -229,9 +245,7 @@ parse_any_element_tree(ElementRegistry &registry, const ParseContext &context,
229245
{"r", create_default_tree_parser(ElementType::span)},
230246
{"t", parse_text_element},
231247
{"v", parse_text_element},
232-
{"xdr:twoCellAnchor",
233-
create_default_tree_parser(ElementType::frame, parse_frame_children)},
234-
};
248+
{"xdr:twoCellAnchor", parse_frame_element}};
235249

236250
if (const auto constructor_it = parser_table.find(node.name());
237251
constructor_it != std::end(parser_table)) {

0 commit comments

Comments
 (0)