Skip to content

Commit 2cd6406

Browse files
authored
fix: pptx rendering (#161)
1 parent 65d7d1b commit 2cd6406

File tree

6 files changed

+111
-12
lines changed

6 files changed

+111
-12
lines changed

docs/DeveloperTroubleshooting.md

+57
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,62 @@ Problem: The zip entry paths mut not contain a `../` part.
8080
+-----------------+
8181
| word/styles.xml | > shared across all
8282
+-----------------+
83+
```
84+
85+
## OOXML Presentation Model
86+
87+
- Entry point is the same `.rels` file and main document is usually `ppt/_rels/presentation.xml`
88+
- Main document references both `slide` and `slideMaster` and `theme` and `notesMaster`
89+
- SlideMaster references `slideLayout` (and `theme`) pages
90+
- Slide references `slideLayout` pages and `notesSlide`
91+
- Theme page has no references
92+
- SlideLayout references `slideMaster` pages. Note, there is a circular reference there!
93+
- NotesSlide references `NotesMaster`
94+
- NotesMaster references back to Theme.
95+
96+
### SlideMaster
97+
98+
> The master slide is the template upon which presentation slides are built. It specifies the shapes and objects as placeholders for content on presentation slides, as well as the formatting of the content within the placeholders. Of course the content and formatting specified on a master slide can be altered by layout slides and the presentation slides themselves, but absent such overrides, the master slide establishes the overall look and feel of the presentation. [Source](http://officeopenxml.com/prSlideMaster.php)
8399
100+
### SlideLayout
101+
102+
> A slide layout is essentially a template design which can be applied to one or more slides, defining the default appearance and positioning of objects on the slide. It "sits" on top of the master slide, acting as an override to alter or supplement information provided on the master slide. When applied to a slide, all corresponding content within objects on the slide is mapped to the slide layout placeholders. [Source](http://officeopenxml.com/prSlideLayout.php)
103+
104+
105+
```
106+
┌─────────────┐
107+
│ _rels/.rels │
108+
└──────┬──────┘
109+
110+
111+
┌─────────────────────┐
112+
┌───────────────────────────────┤/ppt/presentation.xml├───────────────────────────┐
113+
│ └─────────┬───────────┘ │
114+
│ │ │
115+
│ ▼ │
116+
│ ┌────────────────────────┐ │
117+
│ │/ppt/slides/slide{N}.xml│ │
118+
│ └─────┬──────────────────┘ │
119+
│ │ ▲ │
120+
│ │ │ │
121+
│ ▼ ▼ │
122+
│ ┌────────────────────────────────────┐ ┌─────────────────┐ │
123+
│ │/ppt/slideLayouts/slideLayout{N}.xml│ │notesSlide{N}.xml│ │
124+
│ └────────────────────────────────────┘ └─────┬───────────┘ │
125+
│ ▲ │ │
126+
│ │ │ │
127+
│ ▼ ▼ │
128+
│ ┌────────────────────────────────────┐ ┌──────────────────────────────────┐ │
129+
└─►│/ppt/slideMasters/slideMaster{N}.xml│ │/ppt/notesMasters/notesMaster1.xml│◄─┤
130+
└───────────────────────────────┬────┘ └─────┬────────────────────────────┘ │
131+
│ │ │
132+
│ ▼ │
133+
│ ┌────────────┐ │
134+
└──────►│theme{N}.xml│◄────────────────────────┤
135+
└────────────┘ │
136+
▲ │
137+
│ │
138+
┌───────┴────────────────────────────┐ │
139+
│/handoutMasters/handoutMaster{N}.xml│◄─┘
140+
└────────────────────────────────────┘
84141
```

src/stencil/model.clj

+21-8
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,21 @@
2424
(cleanup/process)
2525
(select-keys [:variables :dynamic? :executable :fragments]))))
2626

27+
(defn- ->submodel [dir f]
28+
{::path (fs/unix-path (fs/unroll f))
29+
:source-file (file dir f)
30+
:executable (->exec (file dir f))
31+
:relations (relations/->rels dir f)})
32+
33+
(defn- assoc-slide-layouts-notes [main-document dir]
34+
(->> (for [hf (:headers+footers main-document)
35+
:when (:relations hf)
36+
target (relations/targets-by-type (:relations hf)
37+
#{relations/rel-type-slide-layout relations/rel-type-notes-slide})]
38+
(->submodel dir (file (fs/parent-file (file (::path hf))) target)))
39+
(doall)
40+
(assoc main-document ::slide-layouts)))
41+
2742
(defn load-template-model [dir, options-map]
2843
(assert (fs/exists? dir))
2944
(assert (fs/directory? dir))
@@ -41,12 +56,9 @@
4156
:executable (->exec (file dir main-document))
4257
:relations main-document-rels
4358
:headers+footers (doall
44-
(for [t (relations/targets-by-type main-document-rels relations/extra-relations)
45-
:let [f (file (fs/parent-file (file main-document)) t)]]
46-
{::path (fs/unix-path f)
47-
:source-file (file dir f)
48-
:executable (->exec (file dir f))
49-
:relations (relations/->rels dir f)}))}
59+
(for [t (relations/targets-by-type main-document-rels relations/extra-relations)]
60+
(->submodel dir (fs/unroll (file (fs/parent-file (file main-document)) t)))))}
61+
(assoc-slide-layouts-notes dir)
5062
(style/assoc-style dir)
5163
(numbering/assoc-numbering dir))}))
5264

@@ -93,10 +105,11 @@
93105
(assoc :result result)))))]
94106
(-> template-model
95107
(update-in [:main :headers+footers] (partial mapv evaluate))
108+
(update-in [:main ::slide-layouts] (partial mapv evaluate))
96109
(update :main evaluate))))))))
97110

98111
(defn- model-seq [model]
99-
(let [model-keys [:relations :headers+footers :main :style :content-types :fragments ::numbering :result]]
112+
(let [model-keys [:relations :headers+footers :main :style :content-types :fragments ::numbering :result ::slide-layouts]]
100113
(tree-seq map? (fn [node] (flatten (keep node model-keys))) model)))
101114

102115

@@ -161,7 +174,7 @@
161174
;; TODO: we could speed this up!
162175
(if-let [f (attr-mappers (:tag xml-tree))]
163176
(update-in xml-tree [:attrs ooxml/val] f)
164-
(assoc xml-tree :content (mapv (partial xml-map-attrs attr-mappers) (:content xml-tree))))
177+
(assoc xml-tree :content (mapv (partial xml-map-attrs attr-mappers) (:content xml-tree))))
165178
xml-tree))
166179

167180
; And therefore:

src/stencil/model/relations.clj

+19-3
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,28 @@
3131
(def rel-type-header
3232
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header")
3333

34+
;; PPTX
35+
3436
(def rel-type-slide
3537
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
3638

37-
(def extra-relations
38-
#{rel-type-footer rel-type-header rel-type-slide})
39+
(def rel-type-slide-master
40+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster")
41+
42+
(def rel-type-slide-layout
43+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout")
44+
45+
(def rel-type-theme
46+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")
3947

48+
(def rel-type-notes-slide
49+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide")
50+
51+
(def rel-type-notes-master
52+
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
53+
54+
(def extra-relations
55+
#{rel-type-footer rel-type-header rel-type-slide rel-type-slide-master rel-type-notes-master})
4056

4157
(defn- parse [rel-file]
4258
(with-open [reader (io/input-stream (file rel-file))]
@@ -53,7 +69,7 @@
5369

5470
(defn ->rels [^java.io.File dir f]
5571
(let [rels-path (if f
56-
(unix-path (file (fs/parent-file (file f)) "_rels" (str (.getName (file f)) ".rels")))
72+
(unix-path (fs/unroll (file (fs/parent-file (file f)) "_rels" (str (.getName (file f)) ".rels"))))
5773
(unix-path (file "_rels" ".rels")))
5874
rels-file (file dir rels-path)]
5975
(when (fs/exists? rels-file)

src/stencil/ooxml.clj

+7-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@
118118
"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" "xr2"
119119
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" "xr3"
120120
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" "xr6"
121-
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" "xr10"})
121+
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" "xr10"
122+
;additional aliases from PowerPoint
123+
"http://schemas.openxmlformats.org/drawingml/2006/main" "a"
124+
"http://schemas.openxmlformats.org/presentationml/2006/main" "p"
125+
"http://schemas.microsoft.com/office/powerpoint/2010/main" "p14"
126+
"http://schemas.microsoft.com/office/powerpoint/2012/main" "p15"
127+
})
122128

123129
;; drawing, binary large image or picture
124130
(def blip :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fdrawingml%2F2006%2Fmain/blip)
45.1 KB
Binary file not shown.

test/stencil/model_test.clj

+7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@
3030

3131
))
3232

33+
(deftest test-load-template-model-presentation
34+
(with-open [template (api/prepare "test-resources/presentation/presentation.pptx")]
35+
(let [model (datafy template)
36+
slide-layouts (:stencil.model/slide-layouts (:main model))]
37+
(is (seq slide-layouts))
38+
(is (= 26 (count slide-layouts))))))
39+
3340
(defn- debug-model [model]
3441
(-> model
3542
(assoc-in [:content-types] :CT)

0 commit comments

Comments
 (0)