Skip to content

Commit

Permalink
fix: pptx rendering (#161)
Browse files Browse the repository at this point in the history
  • Loading branch information
erdos authored May 21, 2024
1 parent 65d7d1b commit 2cd6406
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 12 deletions.
57 changes: 57 additions & 0 deletions docs/DeveloperTroubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,5 +80,62 @@ Problem: The zip entry paths mut not contain a `../` part.
+-----------------+
| word/styles.xml | > shared across all
+-----------------+
```

## OOXML Presentation Model

- Entry point is the same `.rels` file and main document is usually `ppt/_rels/presentation.xml`
- Main document references both `slide` and `slideMaster` and `theme` and `notesMaster`
- SlideMaster references `slideLayout` (and `theme`) pages
- Slide references `slideLayout` pages and `notesSlide`
- Theme page has no references
- SlideLayout references `slideMaster` pages. Note, there is a circular reference there!
- NotesSlide references `NotesMaster`
- NotesMaster references back to Theme.

### SlideMaster

> 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)
### SlideLayout

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

```
┌─────────────┐
│ _rels/.rels │
└──────┬──────┘
┌─────────────────────┐
┌───────────────────────────────┤/ppt/presentation.xml├───────────────────────────┐
│ └─────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │/ppt/slides/slide{N}.xml│ │
│ └─────┬──────────────────┘ │
│ │ ▲ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────┐ ┌─────────────────┐ │
│ │/ppt/slideLayouts/slideLayout{N}.xml│ │notesSlide{N}.xml│ │
│ └────────────────────────────────────┘ └─────┬───────────┘ │
│ ▲ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌────────────────────────────────────┐ ┌──────────────────────────────────┐ │
└─►│/ppt/slideMasters/slideMaster{N}.xml│ │/ppt/notesMasters/notesMaster1.xml│◄─┤
└───────────────────────────────┬────┘ └─────┬────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────┐ │
└──────►│theme{N}.xml│◄────────────────────────┤
└────────────┘ │
▲ │
│ │
┌───────┴────────────────────────────┐ │
│/handoutMasters/handoutMaster{N}.xml│◄─┘
└────────────────────────────────────┘
```
29 changes: 21 additions & 8 deletions src/stencil/model.clj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@
(cleanup/process)
(select-keys [:variables :dynamic? :executable :fragments]))))

(defn- ->submodel [dir f]
{::path (fs/unix-path (fs/unroll f))
:source-file (file dir f)
:executable (->exec (file dir f))
:relations (relations/->rels dir f)})

(defn- assoc-slide-layouts-notes [main-document dir]
(->> (for [hf (:headers+footers main-document)
:when (:relations hf)
target (relations/targets-by-type (:relations hf)
#{relations/rel-type-slide-layout relations/rel-type-notes-slide})]
(->submodel dir (file (fs/parent-file (file (::path hf))) target)))
(doall)
(assoc main-document ::slide-layouts)))

(defn load-template-model [dir, options-map]
(assert (fs/exists? dir))
(assert (fs/directory? dir))
Expand All @@ -41,12 +56,9 @@
:executable (->exec (file dir main-document))
:relations main-document-rels
:headers+footers (doall
(for [t (relations/targets-by-type main-document-rels relations/extra-relations)
:let [f (file (fs/parent-file (file main-document)) t)]]
{::path (fs/unix-path f)
:source-file (file dir f)
:executable (->exec (file dir f))
:relations (relations/->rels dir f)}))}
(for [t (relations/targets-by-type main-document-rels relations/extra-relations)]
(->submodel dir (fs/unroll (file (fs/parent-file (file main-document)) t)))))}
(assoc-slide-layouts-notes dir)
(style/assoc-style dir)
(numbering/assoc-numbering dir))}))

Expand Down Expand Up @@ -93,10 +105,11 @@
(assoc :result result)))))]
(-> template-model
(update-in [:main :headers+footers] (partial mapv evaluate))
(update-in [:main ::slide-layouts] (partial mapv evaluate))
(update :main evaluate))))))))

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


Expand Down Expand Up @@ -161,7 +174,7 @@
;; TODO: we could speed this up!
(if-let [f (attr-mappers (:tag xml-tree))]
(update-in xml-tree [:attrs ooxml/val] f)
(assoc xml-tree :content (mapv (partial xml-map-attrs attr-mappers) (:content xml-tree))))
(assoc xml-tree :content (mapv (partial xml-map-attrs attr-mappers) (:content xml-tree))))
xml-tree))

; And therefore:
Expand Down
22 changes: 19 additions & 3 deletions src/stencil/model/relations.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,28 @@
(def rel-type-header
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/header")

;; PPTX

(def rel-type-slide
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")

(def extra-relations
#{rel-type-footer rel-type-header rel-type-slide})
(def rel-type-slide-master
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideMaster")

(def rel-type-slide-layout
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/slideLayout")

(def rel-type-theme
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme")

(def rel-type-notes-slide
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesSlide")

(def rel-type-notes-master
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")

(def extra-relations
#{rel-type-footer rel-type-header rel-type-slide rel-type-slide-master rel-type-notes-master})

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

(defn ->rels [^java.io.File dir f]
(let [rels-path (if f
(unix-path (file (fs/parent-file (file f)) "_rels" (str (.getName (file f)) ".rels")))
(unix-path (fs/unroll (file (fs/parent-file (file f)) "_rels" (str (.getName (file f)) ".rels"))))
(unix-path (file "_rels" ".rels")))
rels-file (file dir rels-path)]
(when (fs/exists? rels-file)
Expand Down
8 changes: 7 additions & 1 deletion src/stencil/ooxml.clj
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,13 @@
"http://schemas.microsoft.com/office/spreadsheetml/2015/revision2" "xr2"
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision3" "xr3"
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision6" "xr6"
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" "xr10"})
"http://schemas.microsoft.com/office/spreadsheetml/2016/revision10" "xr10"
;additional aliases from PowerPoint
"http://schemas.openxmlformats.org/drawingml/2006/main" "a"
"http://schemas.openxmlformats.org/presentationml/2006/main" "p"
"http://schemas.microsoft.com/office/powerpoint/2010/main" "p14"
"http://schemas.microsoft.com/office/powerpoint/2012/main" "p15"
})

;; drawing, binary large image or picture
(def blip :xmlns.http%3A%2F%2Fschemas.openxmlformats.org%2Fdrawingml%2F2006%2Fmain/blip)
Expand Down
Binary file added test-resources/presentation/presentation.pptx
Binary file not shown.
7 changes: 7 additions & 0 deletions test/stencil/model_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@

))

(deftest test-load-template-model-presentation
(with-open [template (api/prepare "test-resources/presentation/presentation.pptx")]
(let [model (datafy template)
slide-layouts (:stencil.model/slide-layouts (:main model))]
(is (seq slide-layouts))
(is (= 26 (count slide-layouts))))))

(defn- debug-model [model]
(-> model
(assoc-in [:content-types] :CT)
Expand Down

0 comments on commit 2cd6406

Please sign in to comment.