How a presentation becomes PDF and PNG pages. Namespace RecursiveAI.OneDocument.Rendering.Presentations, in the
RecursiveAI.OneDocument.Rendering package. The hub it reads is described in presentations.md, the shape painter in
drawingml-rendering.md, the shared paint contract in layout.md. References are to ECMA-376 Part 1. Items marked to check against
PowerPoint are rules the standard leaves open; they are settled by comparing with PowerPoint's own output, and are listed in the
table at the end. Nothing here has been compared with PowerPoint yet.
Entry points
| Call | Result |
|---|---|
PresentationRenderer.WritePdf(presentation, stream, options) | A PDF with one page per page of output, and a PresentationRenderReport (pages, hidden slides skipped, font substitutions, notes). |
PresentationRenderer.RenderPng(presentation, pageIndex, options) | One page as a PNG at 144 dpi. |
presentation.SaveAs("deck.pdf"), Office.Convert("deck.pptx", "deck.pdf") | The same with the default options; a .png target writes the first page. Registered by RenderingFormats.Register, which referencing the package does by itself. |
CLI onedocument convert deck.pptx deck.pdf (or .png) | The same, through the registry. |
PresentationRenderOptions: Output (flags Slides, NotesPages, Handouts; default Slides), IncludeHiddenSlides (default false),
Tagged (true), Compress, Profile (PDF/UA-1, PDF/A-2a), Title, Fonts (an IFontProvider, default the open fonts of
FontLibrary.CreateDefault()), Clock, Autofit, HandoutSlidesPerPage (1, 2, 3, 4, 6 or 9; default 6). Rendering reads the
presentation and never changes it, and is not safe to run on one presentation from several threads.
A slide
The page is the slide size (p:sldSz, 10 by 7.5 inches when it is missing; limited to 1 pt to 200 in). A slide is painted back to front:
- Background. The first of the slide's, its layout's and its master's
p:bgis painted over the page:bgPrwith a solid, gradient, picture or pattern fill, orbgRefinto the theme's background fill styles (§19.3.1.1). The part that owns the background supplies the colour map, theme and pictures. - Master and layout shapes, unless the slide says
showMasterSp="0"(which hides both); the master's are also hidden when the layout says so (§19.3.1.38). Only shapes that are not placeholders are drawn: placeholders on a layout or master supply positions and formatting, and show nothing of their own. They are one artifact in the structure tree. - The slide's own shapes in shape-tree order (the z-order and the reading order). Shapes marked hidden (
cNvPr/@hidden) are skipped.
Hidden slides (show="0") are left out of the output unless IncludeHiddenSlides; the report counts them. A presentation with nothing to
render still writes a one-page PDF (blank, with the note slide.no-pages).
Placeholders and inheritance
The hub resolves which layout and master placeholder a shape inherits from (presentations.md). The painter asks for that chain through
DrawingContext.ShapeResolver and takes, per property block, the first shape in the chain that has it:
- position and size (
a:xfrm), preset or custom geometry, fill, line and effects, each independently; - the shape's
p:stylewhen it has none of its own; - a shape with a text body and no geometry anywhere in its chain draws no outline of its own and keeps its text in its box.
Text properties inherit as the hub describes (shape lstStyle, layout and master placeholder lstStyle, the master's title, body or other
style by placeholder type, the presentation's defaultTextStyle; the notes master's notesStyle for notes pages), by paragraph level 1
to 9, attribute by attribute. A bullet is taken as a unit from the first source that names one; its font, size and colour are
independent. Scheme colours go through the slide's colour map override or the master's, then the master's theme; theme fonts
(+mj-lt, +mn-lt) resolve to the theme's major and minor Latin fonts. East Asian and complex-script theme fonts are not read from the
theme: those characters use the run's own ea/cs typeface when it names one, else the font library's script fallback.
Pictures, charts, diagrams, objects, tables
| Content | Painted as |
|---|---|
p:pic | the shape painter's picture path (crop, outline, effects); metafiles through the picture hook (metafiles.md). A picture is a Figure with its descr as alternative text, or an artifact when marked decorative. |
| chart frame | the chart renderer (charts.md) at the frame's box; a Figure with the frame's description. |
| SmartArt | the drawing PowerPoint saved with the diagram (dsp:drawing, found through the data part's dataModelExt and the slide's relationship), painted as ordinary shapes in the frame; note slide.smartart-cached. A diagram with no saved drawing is not painted (slide.smartart-not-painted); regenerating one from its layout definition is a later unit. |
| embedded object (OLE) | the preview picture saved with it (p:pic inside p:oleObj); note slide.object-not-painted when there is none. Objects are never opened or run. |
table (a:tbl) | see below |
| connectors, other shapes | the shape painter; a connector is an artifact. |
Animations and transitions are preserved in the file and not rendered.
Text bodies
Text goes through OneDocument's own text layout (SlideTextLayout), built on OneFont: bidi levels, Unicode line-break opportunities,
shaping with script fallback, and the same font provider and substitution notes as Word layout. Lengths are points.
The body (§21.1.2.1.1 bodyPr), each attribute inherited like the rest:
- Insets default to 0.1 in left and right and 0.05 in top and bottom. The text rectangle is the shape's text rectangle (for a preset shape, the preset's own, so an ellipse or a rounded rectangle takes a smaller one) less the insets.
anchort/ctr/bplaces the block of lines in the rectangle. Text taller than the rectangle is not clipped; it overflows downward from the top anchor, both ways from the middle, upward from the bottom.anchorCtrcentres the block horizontally (the widest line's extent, which is what a body withwrap="none"is about).wrap="none"does not break lines; a centred or right-aligned line is placed against the box's edges even when it is wider.numCol/spcCol: the width is divided into equal columns and lines flow down the first column until the next would pass the bottom of the rectangle, then into the next; the last column takes the rest.vert:vertrotates the text 90° clockwise (lines run down, the first line is at the right),vert27090° counter-clockwise (first line at the left);eaVert,mongolianVert,wordArtVertandwordArtVertRtlare drawn as these (notesslide.text-eavert-approximated,slide.text-vertical-approximated). Columns do not apply to vertical text.rotturns the text about the centre of its rectangle on top of the shape's rotation;upright="1"keeps the text level whatever the shape's rotation (about the rectangle's centre). A flipped shape does not mirror its text (a vertical flip turns it over, as PowerPoint does).
Paragraphs (§21.1.2.2.7 pPr): marL is the left margin of every line, indent moves the first line from it, marR the right
margin; algn l, ctr, r, just (the last line is not stretched), dist (every line, letters included, is spread across the
width); lnSpc as a percentage of the font's natural line height (ascent plus descent plus line gap) or exact points, the line's
baseline sitting at the same proportion of the line; spcBef/spcAft in points or as a percentage of the line height; tabLst stops
and defTabSz intervals measured from the left edge of the text rectangle (every stop acts as a left tab); a:br is a line break that
starts the next line at the paragraph's indent. Lines are broken greedily at the last break opportunity that fits; spaces at the end of a
line hang. rtl="1" sets the paragraph's base direction; margins and algn stay physical.
Runs (§21.1.2.3.9 rPr): sz (default 18 pt), b, i, u (every underline style is drawn as a single line, dbl as two,
heavy… thicker), strike/dblStrike, cap (all, small at 80 % of the size), spc (added after each cluster),
baseline (shifted by that fraction of the size, the text set at 2/3 size), kern (kerning on when the size is at least the value),
colour from solidFill (a gradient takes its first stop), highlight, latin/ea/cs typefaces. A run with a hyperlink takes the
theme's link colour and an underline and is a Link with its target (external hyperlinks only; slide jumps and actions are drawn as
plain underlined text).
Fields (§21.1.2.2.4): slidenum shows the slide's number (firstSlideNum plus the slide's index, hidden slides counted); a
datetime… field shows the text stored in the file, or, when Clock is set, the date or time in the format its type names
(datetime1 is M/d/yyyy and so on). The output does not depend on the date it is made unless the caller supplies the clock.
Bullets (§21.1.2.4): buChar and buAutoNum text is shaped in the bullet's font (buFont, else the text's) at buSzPct
(default 100 %) or buSzPts of the first run's size, in buClr or the first run's colour, at marL + indent. Symbol and Wingdings
code points are mapped to Unicode characters the open symbol font has. A picture bullet (buBlip) is drawn as a round bullet. When the
bullet fits in the hanging space the text starts at marL; a wider bullet is followed by the next tab stop.
Numbers count up through consecutive paragraphs of the same scheme and startAt at one level; a paragraph at a shallower level, one
without that numbering, or a different scheme ends the run. Deeper levels in between do not reset a shallower count. A paragraph with
no text shows no bullet and takes no number. Schemes: arabic, alpha (a, b … z, aa, bb …), roman, each lower or upper with Period,
ParenR, ParenBoth or Plain; other schemes are numbered as arabic with a period.
Equations (a14:m holding m:oMath or m:oMathPara in an mc:Choice) are laid out by the equation layout (equations in layout.md) as one
unbreakable inline box on the baseline at the run's size and colour, tagged as a Formula whose alternative text is the equation's linear
form; the Fallback is not drawn.
Autofit
a:noAutofit(or none anywhere in the chain): text is laid out as it is and may overflow.a:normAutofit(shrink text on overflow):fontScalemultiplies every font size (bullets included) andlnSpcReductionis taken off percentage line spacing (100 % becomes 90 % for 10000), as stored, which is what PowerPoint shows. Exact line spacing and spacing in points are not changed. When the file stores neither, the scale is computed (defaultSlideAutofitMode.StoredThenComputed): the first of these steps whose text fits the rectangle is used, the last one when none does.font scale 100 % 100 % 100 % 92.5 % 92.5 % 85 % 77.5 % 70 % 62.5 % 55 % 47.5 % 40 % 32.5 % 25 % line spacing reduction 0 10 % 20 % 10 % 20 % 20 % 20 % 20 % 20 % 20 % 20 % 20 % 20 % 20 % The steps are the values PowerPoint is seen to store; which step it picks for a given text, and whether it rounds sizes, is to check.
Autofit = Storednever computes;Computedignores stored values.a:spAutoFit(resize shape to fit text): the shape's height becomes the text's height plus the top and bottom insets, keeping the top edge for a top anchor, the centre for a middle anchor and the bottom edge for a bottom anchor, before the shape is painted, so its fill and outline follow. The width is not changed, including forwrap="none"; vertical text does not resize.
Tables
A graphic frame holding a:tbl is painted from the grid: column widths from a:gridCol, row heights from a:tr/@h, never narrower
than the frame says and growing taller when a cell's text needs it (a merged cell's need goes to the last row it spans). The frame's
own ext is not used to scale the grid.
- Merges:
gridSpan+hMerge,rowSpan+vMerge; the origin cell is drawn over the whole region and the continuation cells are skipped. - Cell margins
marL/marR/marT/marB(0.1 in, 0.1 in, 0.05 in, 0.05 in),anchort/ctr/b; cell text goes through the text layout with the presentation's default text style. - Table styles (§20.1.4.2.27
tblStyle): the style named bytableStyleId, looked up inppt/tableStyles.xml, applieswholeTbl, thenband1H/band2H(withbandRow, counting from the first data row),band1V/band2V(bandCol),firstCol/lastCol,lastRow,firstRow(the later part wins) for text bold and colour, fill (a:fillorfillRef) and the six borders (insideH/insideVon interior edges). A run's own bold or colour wins over the style's. The cell's owntcPrfill andlnL/lnR/lnT/lnBwin over the style. Generators often name the default style{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}without defining it; the built-in Medium Style 2 – Accent 1 is used for that id. - Borders are solid bars centred on the cell edge (dash styles are not drawn); gradient, pattern and picture cell fills are approximated
(notes
slide.table-gradient-approximated,slide.table-fill-approximated). A table with more than 20,000 cells is not painted (slide.table-limit).
Notes pages and handouts
Output.NotesPages adds, after the slides, one page per rendered slide at the notes size (p:notesSz, 6 by 8 in when absent): the
notes master's background and non-placeholder shapes, the slide scaled into the notes master's (or notes slide's) slide-image
placeholder with its outline, and the notes slide's own shapes (the notes text in the body placeholder, in the notes master's
notesStyle). A slide without notes gets a page with the picture and no text. Without a notes master the picture is placed in the
upper part of the page. The picture is a Figure named "Slide n: title".
Output.Handouts adds pages of HandoutSlidesPerPage slide pictures (1×1, 1×2, 1×3, 2×2, 2×3 or 3×3 grids) with a thin frame, on the
notes page size. The handout master (header, footer, lines) is not drawn (slide.handout-master-ignored).
Tagging
Each page is a Sect. A title or centre-title placeholder's paragraphs are H1; other paragraphs are P; bulleted and numbered
paragraphs are L > LI > Lbl + LBody (consecutive ones share a list); tables are Table > TR > TH/TD with spans, the
first row always being header cells (PDF/UA wants a header in every table, so a table that does not mark firstRow still gets one); pictures, charts and diagrams are Figure with alternative text;
connectors and objects marked decorative are artifacts; backgrounds, master and layout shapes, date, footer and slide-number
placeholders, and shape fills are artifacts. Reading order is the shape-tree order. Equations are Formula. Artifact kinds are not set on slides (see layout.md for the Word kinds).
Limits and defects
A text body longer than 200,000 characters is cut off (slide.text-truncated); lengths, scales and spacing read from the file are
clamped to what a slide can show; shapes per drawing, nesting and tables are limited as above and in drawingml-rendering.md; the
page size is clamped and a PNG over 100 million pixels raises OfficeFormatException with code render.failed. Malformed parts reach
rendering as the hub's typed defects (defects.md, pptx.*); rendering adds no defect codes. What was approximated or left out is
reported as notes on the report, once per code:
| Code | Meaning |
|---|---|
slide.no-size, slide.no-pages, slide.text-body-missing | no p:sldSz; nothing to render; a shape's text body was not found |
slide.text-truncated, slide.table-limit | limits |
slide.text-vertical-approximated, slide.text-eavert-approximated | vertical text variants |
slide.smartart-cached, slide.smartart-not-painted, slide.object-not-painted | diagrams and objects |
slide.table-gradient-approximated, slide.table-fill-approximated | table fills |
slide.handout-master-ignored | handouts |
slide.math-display-inline | a display equation in slide text is laid out inline at the surrounding text size |
drawing.* | from the shape painter (drawingml-rendering.md) |
Fonts
The default provider substitutes metric-compatible open fonts for the common Office fonts and reports each substitution
(PresentationRenderReport.FontNotes). Aptos and the other new Office defaults are approximated by Carlito, so line breaks of decks in
those fonts differ from PowerPoint's until both sides use the same installed fonts (layout.md).
To check against PowerPoint
Generated inputs are in testdata/slides (tools/layout-differential.sh asks PowerPoint for its PDF of each); none is answered yet.
| Rule | Chosen here | Case |
|---|---|---|
| Space before the first paragraph of a body | not applied | spacing-checks |
| Percentage spacing before/after | percentage of the first line's height | spacing-checks |
| Line spacing below 100 % on the first line | the whole line shrinks, baseline kept at the same proportion | spacing-checks |
| Text start after a bullet wider than the hanging space | next tab stop | bullets, spacing-checks |
| Autofit step chosen for a text; font size rounding | first fitting step of the table above | autofit (stored values only; PowerPoint recomputes when text is edited, so the oracle driver must edit text to answer) |
Percentage line spacing is cut by lnSpcReduction | subtracted (100 % → 90 %) | autofit |
| Margins and alignment of right-to-left paragraphs | physical (marL stays on the left) | spacing-checks |
| Centre, right and decimal tab stops | treated as left | spacing-checks |
| Empty numbered paragraph | no bullet, no number consumed | bullets |
| Non-placeholder text style source | master otherStyle, then defaultTextStyle | inherit-position |
bodyPr/@rot pivot and upright placement | rectangle centre | vertical-and-columns |
| Underline thickness and position, strike position | font metrics; 30 % of the size above the baseline | runs |
| Baseline-shifted text size | two thirds | runs |
Table borders with cmpd/dash, border winner on shared edges | solid; later cell wins | table |