Appearance
Read object model
Presentation.load() returns a typed view of a deck. This page states how that view behaves: what each getter reads, what it inherits, and when it returns null. Each member links to its signature in the API reference.
Tasks are in the reading guides: read and edit a deck, copy slides and shapes between decks and build on a template. What save() writes is on Round-trip guarantee.
Object model
- A proxy reads its DOM element on every access and caches nothing. A collection getter builds new proxies each time, so
slide.shapes[0] !== slide.shapes[0]. The same holds forparagraphs,runs,rows,cellsandpoints. - Two proxies over one element see each other's edits. Key a
Mapor aSeton a part name, a shapeidor a pointmodelId, not on a proxy. - Positions and sizes are in EMU: 914,400 per inch, 12,700 per point.
- A setter or an editing method writes to the DOM and marks the part that holds the element dirty.
- Every class exposes its element as
element_, with amarkDirty()beside it. Read and edit a deck covers editing through them. - A shape's
hostis theSlide,SlideLayout,SlideMasterorNotesSlidewhose part holds its shape tree. All four haveshapes, returning the same five shape classes. shapesunwrapsmc:AlternateContent. It reports the shape in the firstmc:Choicethat holds one, else the shape inmc:Fallback. ChartEx charts, 3D models, zoom frames and inline math arrive this way.
Presentation
slidesfollowsp:sldIdLst. An entry whose relationship names a missing part throwspackage/relationship-target-missing.slideSizereports EMU and inches, and isnullwhenp:sldSzis absent or incomplete.presentationPartresolves the main part through the packageofficeDocumentrelationship. It throws when there is not exactly one.embeddedFontslistsp:embeddedFontLstwith each face's partname, and is[]when the deck embeds none. It skips an entry with no typeface and a face whose relationship is missing. See Embedded fonts.masters()andlayouts()enumerate the chrome and copy nothing: see Masters, layouts and themes.
The methods that add, remove and copy slides are tasks:
Document properties
| Getter | Part | When the part is absent | What it reports |
|---|---|---|---|
coreProperties | docProps/core.xml | {} | Each CoreProperties field that has an element. An empty element reads ''. created, modified and lastPrinted stay the W3CDTF strings the file holds, not Date objects, so no time zone conversion happens. |
appProperties | docProps/app.xml | {} | application, appVersion, company and titlesOfParts. titlesOfParts is the flat vector as written: fonts, then themes, then slide titles. HeadingPairs, which partitions it, is not read. The statistics are kept but not decoded. |
customProperties | docProps/custom.xml | [] | { name, value } pairs in file order. String types read as string, integer and real types as number, vt:bool as boolean, and vt:filetime and vt:date as the raw string. An unknown type reads as its text. |
The write side authors all three parts, from pptx.title, subject, author (read back as creator), revision, company and setCustomProperty(). company is the only appProperties field a caller sets. The library writes the other three about itself.
Tags
presentation.tagsandslide.tagsreturnTagpairs from theppt/tagsparts the owner'stagsrelationships name. PowerPoint exposes the same data asPresentation.TagsandSlide.Tags.- An owner with several tag parts reads them in relationship order. An owner with none reads
[]. - Nothing writes tags, on the write side or through the read model. Tag parts load and save byte-identical.
Slide
A Slide is one slide part, with its index in deck order, slideId, partName, relationships and name. name is null when the slide is unnamed.
shapeslists the top-level shapes.shapeById(),shapeByName()andplaceholder()search top-level shapes only.shapeByIdDeep()also searches groups, visiting a group before its children.textjoins the slide's text in document order with\n: every text-bearing shape, shapes inside groups, table rows with their cells joined by a tab, and SmartArt text. It leaves out speaker notes and chart text.notesText,notesTextFrame,notesSlideandaddNotes()are the speaker notes. Read and edit a deck describes them.layout,master,themeandshowMasterSpreach the chrome: see Masters, layouts and themes.transitionreads and writesp:transition.hasAnimationsandflattenAnimations()check for and remove build animations. See Animations and transitions.addTextBox()andaddPicture()add content. Read and edit a deck covers them.
Hidden slides
hiddenreadsp:sld/@show, anxsd:booleanthat defaults totrue. A slide with noshowattribute readsfalse.show="0"andshow="false"readtrue.- Setting
truewritesshow="0". Settingfalseremoves the attribute. Either marks the slide part dirty. - A slideshow skips hidden slides, and so does a PDF export from PowerPoint or LibreOffice. Once an earlier slide is hidden, rendered page N is no longer
slides[N]:
ts
const hidden = presentation.slides.filter((slide) => slide.hidden).length
const renderedPages = presentation.slides.length - hiddenBackground and slide number
background is the background the slide renders. It walks the inheritance chain: the slide's own p:bg, else its layout's, else its master's. source names the tier that supplied it, and the getter is null when no tier defines one. SlideLayout.background and SlideMaster.background report only that part's own p:bg.
type | Element | Fields |
|---|---|---|
solid | a:solidFill in p:bgPr | colorRef |
gradient | a:gradFill in p:bgPr | gradient |
pattern | a:pattFill in p:bgPr | preset, foreground, background |
image | a:blipFill in p:bgPr | relId, partName, picture |
themeRef | p:bgRef | idx, colorRef, resolvedFill |
none | p:bgPr with a:noFill or no fill the reader recognizes | none |
- The write side authors
solid,gradient,patternandimagebackgrounds. It putsp:bgRef idx="1001"on its default layout, so a slide authored without a background reads{ type: 'themeRef', source: 'layout', idx: 1001 }, with a solid whiteresolvedFill. - An
imagebackground's relationship resolves against the part that holds thep:bg. A background inherited from the layout resolves through the layout's relationships. - A
themeRefkeeps itsidxand resolves it inresolvedFill. Anidxof 1000 or more selects entryidxminus 1000 of the theme'sa:bgFillStyleLst, counting from 1. A loweridxselects that entry ofa:fillStyleLst. The entry'sphClrtakes the colour insidep:bgRef, and an image entry resolves through the theme part's relationships. resolvedFillisnullwhen the theme has noa:fmtScheme, the entry does not exist, or the colour does not resolve.
slideNumberPlaceholder returns the slide's own sldNum placeholder, which the write-side slide.slideNumber option creates. A slide number defined with defineSlideMaster({ slideNumber }) sits on the layout, so this getter reads null for it. Read it from slide.layout.placeholders.
Comments
PowerPoint has two comment formats. A deck uses one of them, and the getters of the other read [].
| Format | Slide getter | Deck getter | Parts | Written by pptx-ts |
|---|---|---|---|---|
| Legacy | comments, returning Comment | commentAuthors, returning CommentAuthor | commentN.xml under ppt/comments/, and ppt/commentAuthors.xml | Yes, by slide.addComment() |
| Modern (2018) | modernComments, returning ModernComment | modernCommentAuthors, returning ModernCommentAuthor | modernComment_*.xml under ppt/comments/, and ppt/authors.xml | No |
commentSchemareports'modern'when the deck has a modern comments part, else'legacy'when it has a legacy one, else'none'.- Both formats are read-only in the read model. Each getter parses the part on every call and returns plain objects. Changing a returned object changes nothing in the deck, and no method adds, edits or removes a comment. Comment parts load and save byte-identical.
- A legacy comment resolves
authorIdagainstcommentAuthorstoauthorandauthorInitials, which arenullwhen no author matches. It carriesidx(the author's comment number),text, the marker positionxandyin EMU, anddateas written. - A modern comment's
idandauthorIdare GUID strings.authorandauthorInitialsresolve againstmodernCommentAuthors, whose entries also carryuserIdandproviderId.createdis the timestamp as written, andtextjoins the comment's paragraphs with\n. - A modern comment's
repliesholds its replies in thread order. A reply hasxandyofnulland no replies of its own.
Masters, layouts and themes
A slide resolves colours, fonts, placeholder positions and its background against three shared parts: its layout, that layout's master, and the master's theme.
slide.layoutfollows the slide'sslideLayoutrelationship,layout.masterthe layout'sslideMasterrelationship, andmaster.themethe master'sthemerelationship. Each isnullwhen its relationship or part is missing.slide.masterisslide.layout?.master, andslide.themeisslide.layout?.master?.theme.layout.themeislayout.master?.theme.- From the deck side,
presentation.masters()lists masters inp:sldMasterIdLstorder, andmaster.layoutslists a master's layouts inp:sldLayoutIdLstorder.presentation.layouts()lists every layout as aLayoutHandle.
The inheritance chain
Every getter below takes the first tier that defines a value.
| Value | Getter | Tiers, in order | Reports the tier |
|---|---|---|---|
| Background | Slide.background | Slide p:bg, layout p:bg, master p:bg | source |
| Placeholder position and size | Shape.resolvedFrame | The shape's own a:xfrm, the matching layout placeholder's, the matching master placeholder's | source |
| Vertical text anchor | TextFrame.resolvedAnchor | The frame's own a:bodyPr/@anchor, the matching layout placeholder's, the matching master placeholder's | No |
| Run colour | Run.resolvedColor | The run's own fill, the shape's p:style/a:fontRef, then the list-style tiers | No |
| Run typeface | Run.resolvedFontFace | The run's own a:latin, the shape's p:style/a:fontRef, then the list-style tiers. A +mj-* or +mn-* token resolves through the theme font scheme. | No |
| Run size, bold and italic | resolvedSizePt, resolvedBold, resolvedItalic | The run's own a:rPr attribute, then the list-style tiers | No |
- The list-style tiers are: the paragraph's
a:pPr/a:defRPr, the text body'sa:lstStylefor the paragraph level, the matching layout placeholder'sa:lstStyle, the matching master placeholder'sa:lstStyle, the master'sp:txStyles, and the presentation'sp:defaultTextStyle. A run outside a placeholder skips the three placeholder tiers. - A run whose own fill is not a solid colour, such as
a:noFillor a gradient, readsnullfromresolvedColor. - A table cell's text inherits differently: see Tables.
- A
schemeClrtoken resolves through the colour map of the tier that holds the shape, then the theme's colour scheme.
A slide placeholder inherits from the layout or master placeholder that matches its p:ph:
dt,ftr,sldNumandhdrmatch only a placeholder of the same type.- Any other type matches, in order: the same
idxin the same category, then the sameidx, then the same category. It never matches one of the four types above. - The categories are title (
title,ctrTitle), body (body,subTitle,obj, or no type) and other. - An absent
idxcounts as0.
The write side puts an a:xfrm on every placeholder it authors, so resolvedFrame.source reads 'own' on a deck this library wrote. PowerPoint leaves a:xfrm off a placeholder the user never moved, and resolvedFrame then reports the layout's or master's box.
resolvedFrame fills in inherited geometry and does not compose groups. absoluteFrame composes groups and does not inherit.
Owned vs shared
- A slide's own shapes belong to that slide alone.
- Its layout, master and theme are shared. Every slide bound to a layout reads the same layout part, and every layout under a master reads the same master and theme.
- An edit to a layout or master, through its shapes, its placeholders or
element_, or an edit to a theme, marks that shared part dirty. It changes every slide that uses the part.
Copying a page follows the same split. Two copies of one page, from cloneSlide(), from importing the same page twice, or from naming it twice in one importSlides() batch, share some parts and each own the rest. importShape() applies the same rule to one shape.
| Shared by the copies | Owned, so each copy gets its own |
|---|---|
| Slide layout, slide master, theme and theme override | A chart or chartEx chart, with its embedded workbook and its chartUserShapes drawing |
| Notes master, handout master, presentation properties, view properties and table styles | The five SmartArt parts: data, layout, quick style, colours and drawing |
| Images, audio, video, 3D models and fonts | OLE embeddings, tags and comments |
| The legacy and modern comment author lists | The notes slide, and its relationship back to the page |
| Another slide a jump link points at, and external hyperlink targets | Every other part |
- Ownership passes down: a part a page owns owns its own subtree, down to the media at the leaves.
- The rule lists what may be shared and copies everything else, so a relationship type it does not know is copied. A wrongly shared part makes a deck PowerPoint refuses to open; a wrongly copied one only duplicates bytes.
- PowerPoint refuses to open a package in which two slides resolve to one chart or one diagram, and the schema validator accepts such a package.
- Copy slides and shapes between decks covers the copy methods.
Master and layout shapes
SlideMaster.shapesandSlideLayout.shapesreturn every shape in that tier's tree, as the same five classesSlide.shapesreturns. A template's bands, rules and logos are here.placeholderslists the placeholder shapes of the same tree asPlaceholderobjects, with type,idx, name, id, own position and size, and text frame.- Read a placeholder through
placeholdersto place it. Read the same element throughshapesto draw it, because only the shape carries the paint getters. Both views resolve text inheritance the same way. Placeholder.idxisnullwhen the attribute is absent.AutoShape.placeholderreports'0'for the same element.- A colour token on a master shape resolves through the master's colour map and theme. On a layout shape it resolves through the layout's master and theme.
defineSlideMaster({ objects })writes its non-placeholder objects into the layout's tree and nothing into the master's. A deck this library wrote readsmaster.shapesas[].- A master's or layout's
nameis''when it is unnamed.
Whether master shapes are drawn
Slide.showMasterSpandSlideLayout.showMasterSpread@showMasterSp, which defaults totrue.- PowerPoint writes
showMasterSp="0"on section dividers and full-bleed layouts. It hides the master's non-placeholder shapes and leaves its placeholders. - A renderer that paints
master.shapeshas to check both tiers:
ts
const drawMasterShapes = slide.showMasterSp && (slide.layout?.showMasterSp ?? true)- Both getters are read-only, and the write side authors neither attribute.
- The object model does not stack the tiers for you. Painting master shapes under layout shapes under slide shapes is the caller's job.
Theme, colour map and layout type
Theme.colorSchemereports the twelve slots as 6-digit hex. Ana:sysClrslot reads itslastClr, and a missing slot readsnull.color()reads one slot.Theme.fontSchemereports the major (heading) and minor (body) faces for Latin, East Asian and complex script. An emptytypefacereadsnull, and the per-scripta:fontlist is not read. The getter isnullwhen the theme has no font scheme.SlideMaster.colorMapmaps each of the twelve tokens, such astx1, to a theme slot. A token the map omits readsnull.SlideLayout.typereadsp:sldLayout/@type. The write side authors none, so a deck this library wrote readsnull.
Shapes
| Element | Class | shapeType |
|---|---|---|
p:sp | AutoShape | autoShape |
p:pic | Picture | picture |
p:cxnSp | Connector | connector |
p:graphicFrame | GraphicFrame | graphicFrame |
p:grpSp | GroupShape | group |
shapesreturnsAnyShape, the union of the five classes. Narrow it onshapeTypeor withisAutoShape()and the other guards.- Only an
AutoShapewith ap:txBodyhas atextFrame.hasTextFrameisfalsefor every other shape, and settingtexton one throwsshape/no-text-frame. presetGeometryreadsa:prstGeom/@prston pictures and connectors as well as auto shapes. A group readsnull.adjustValuesmaps each adjust guide name to its formula.hiddenreadsp:cNvPr/@hidden.descriptionis the alt text, and setting''removes it.titleandisDecorativeare read-only.delete()removes the shape from its tree or group and marks the host part dirty. It also removes the build animations of every shape it removes, and drops each connector binding (a:stCxn,a:endCxn) that named one.
Geometry
left,top,widthandheightread the shape's own transform in EMU. They arenullwhen the shape has none, as for a placeholder that inherits its box.- For a shape inside a group they are in the group's child coordinates: see Absolute frame and groups.
- A setter creates the transform when it is absent:
p:xfrmon a graphic frame,a:xfrminp:grpSpPron a group,a:xfrminp:spPron the rest. It rounds to whole EMU. leftandtopreject a value that is not finite, withcoord/non-finite.widthandheightalso reject zero and negatives, withcoord/not-positive.rotationis in degrees. It isnullwithout an own transform and0for a transform with norot. It is not converted to a signed angle:rot="19216344"reads320.27, not-39.73.flipHandflipVarefalsewhen unset or when the shape has no own transform.resolvedFrameadds inherited placeholder geometry: see The inheritance chain.
Absolute frame and groups
A group states two boxes on its a:xfrm: where it sits on the slide (a:off, a:ext), and the child coordinate space its shapes are placed in (a:chOff, a:chExt). A child's left, top, width and height are in that child space, so they cannot be placed on the slide directly.
absoluteFramemaps the shape through each enclosing group, innermost first, asoff + (p - chOff) * (ext / chExt). It then applies each group's flips, and its rotation about the group centre.- The result is the unrotated box PowerPoint writes when you ungroup, rounded to whole EMU.
rotationis the combined rotation in degrees, from 0 up to 360, andflipHandflipVare the flips combined along the chain. - For a shape at slide level, the box equals its own
left,top,widthandheight. absoluteFrameFailuresays whyabsoluteFrameisnull:
absoluteFrameFailure | Meaning |
|---|---|
null | The frame resolved. |
'no-own-transform' | The shape has no complete a:xfrm, typically a placeholder that inherits its box. The deck is fine: read resolvedFrame. |
'group-transform-missing' | An enclosing group lacks a complete a:off, a:ext, a:chOff and a:chExt set, so its child space is unknown. |
'group-transform-degenerate' | An enclosing group's a:chExt is zero on an axis, so the mapping would divide by zero. |
- When one chain holds both group failures,
'group-transform-missing'is reported. pptx-ts/inspectwarns withinspect/group-transform-missingandinspect/group-transform-degenerate, and stays silent for'no-own-transform'.GroupShape.childFramereturns the group'sa:chOffanda:chExtbox, and isnullwhen either is incomplete. A consumer that rebuilds the group needs it to reproduce the child scaling. A consumer that paints needs onlyabsoluteFrame.GroupShape.shapeslists the shapes directly inside the group.
Fill and line
| Kind | Fill: read | Fill: set | Line: read | Line: set |
|---|---|---|---|---|
AutoShape | p:spPr | Yes | a:ln in p:spPr | Yes |
Connector | p:spPr | Yes | a:ln in p:spPr | Yes |
Picture | p:spPr, not the image | No: shape/fill-unsupported | a:ln in p:spPr, the border | Yes |
GroupShape | p:grpSpPr | Yes | Always null: p:grpSpPr has no a:ln | No: shape/line-unsupported |
GraphicFrame | Always null: a graphic frame has no p:spPr | No: shape/fill-unsupported | Always null | No: shape/line-unsupported |
- The setters are
fillColor,fillSchemeColor,noFill(),lineColorandlineSchemeColor. - A
*Colorsetter takes 6-digit hex, with or without#, and stores it upper-cased. Malformed input throws. A*SchemeColorsetter takes a theme token such asaccent2. - A fill or line holds one solid colour, so setting the hex clears the token and setting the token clears the hex.
- Setting
nullremoves thea:solidFill, and the shape inherits from itsp:styleor placeholder again.noFill()writes<a:noFill/>instead: a transparent surface, not an inherited one.fillNoFillandlineNoFillreport an explicit no-fill. - Setting
nullnever throws, even on a kind the table marks No, so a fill a deck wrote on a picture can still be cleared. - A setter creates
p:spProrp:grpSpPr,a:lnanda:solidFillin schema order when they are absent. - A table or chart in a graphic frame has its own fill model: see Tables and Charts.
The other paint getters are read-only:
resolvedFillresolves a solid fill to hex. With no fill inp:spPrit falls back to thep:style/a:fillReffill. It isnullfor a gradient, pattern, image ora:noFillfill.resolvedLineresolves the line's solid fill. Ana:lnwith no fill of its own falls back to thep:style/a:lnRefcolour, because PowerPoint layers such ana:lnover the style line one property at a time.gradientFill,gradientStops,patternFillandpictureFilldecode the fillsresolvedFilldoes not. The write side authors pattern fills withfill: { type: 'pattern' }and picture fills withfill: { type: 'image' }.lineWidthPt,lineDash,lineCap,lineAlign,lineEndsandlineGradientdescribe the line.
Colours
Every read value that carries a colour carries a ColorRef.
- At most one of
srgb,schemeandpresetis set, naming the colour model the file used.a:sysClranda:hslClrset none of the three and report only throughresolved. - An absent colour has every field
null, so aColorRefitself is nevernull. resolvedis aResolvedColor: the basehex, thetransformsin document order,effectiveHexwith the transforms applied, andalphawhen a transform sets opacity.resolvedisnullwhen the colour cannot be made literal, for an unmapped token or ana:scrgbClr. It is alwaysnullin a chart part, which the reader reads without a theme.effectiveHexis the colour a renderer paints. To re-author the colour against a different theme, carryschemeandtransformsinstead: a literaleffectiveHexstops following the theme.readColorRef()reads one colour element.
Picture fill
pictureFill decodes an a:blipFill used as a fill: in a shape's p:spPr or a group's p:grpSpPr, a table's a:tblPr, a cell's a:tcPr, or a background's p:bgPr. It is a different thing from a Picture, whose image is its own p:blipFill.
resolvedFillreportsnullfor an image fill, so an image-filled shape reads as unfilled there. ReadpictureFill.partNameresolves the relationship through the part that holds the fill. It isnullfor an external or missing target.srcRectandfillRectare per-edge fractions, where0.1is 10 percent.fillRectcan be negative, when the image extends past that edge. An explicit emptya:srcRectreads zeros, notnull.tileoffsets are EMU, and its scales are fractions where1is 100 percent.alphais a fraction, andnullwhen the fill sets none.- See
PictureFillfor every field.
Effects
| Effect | Getter | Element in a:effectLst | The library writes it | The library reads it |
|---|---|---|---|---|
| Outer shadow | shadow | a:outerShdw | Yes, from shadow: { type: 'outer' } on shapes, text boxes and images | Yes |
| Inner shadow | innerShadow | a:innerShdw | Yes, from shadow: { type: 'inner' } | Yes |
| Glow | glow | a:glow | No. The write-side glow option puts a:glow in the text run properties, which no getter reads. | Yes |
| Reflection | reflection | a:reflection | No | Yes |
| Soft edge | softEdge | a:softEdge | No | Yes |
- Each getter returns
nullwhen the shape has no such element. - Distances are points (EMU divided by 12,700), and angles are degrees.
- An attribute the file does not state is left off the result, not set to zero. A soft edge with no
radreadsradiusPt: 0. - A shadow's or glow's opacity is
colorRef.resolved.alpha:transparency: 25on the write side reads back asalpha0.75. - Reflection alpha and position fields are fractions from 0 to 1. A reflection carries no colour.
Custom geometry
customGeometry reads a:custGeom/a:pathLst, and is null for a shape with preset geometry or none. Every shape class has it, as with presetGeometry: a picture clipped to a freeform reads its clip path, and a group reads null.
- It returns one entry per
a:path, each withw,h,fill,strokeand itsGeometryCommandlist in document order. An absent attribute reads its schema default:wandhof0,fillof'norm',strokeoftrue. - Coordinates are path units from
0towand0toh, not EMU. Scale them against the path'swandhand the shape's box. - A coordinate that is not a number, such as a guide name, reads
0. arcToangles are degrees.- The command names match the write-side
GeometryPointlist, one to one. - PowerPoint writes one
a:pathper shape, and a shape with a hole as two contours in that one path. A list with severala:pathelements comes from other producers, such as SVG import.
Pictures and SVG
imageRelIdandimagePartNamename the raster image, froma:blip/@r:embed.svgRelIdandsvgPartNamename the SVG, from theasvg:svgBlipextension.- PowerPoint usually pairs an SVG with a raster fallback. Some exporters write an SVG with no raster, where
imagePartNameisnulland onlysvgPartNameresolves. mediaKindreports'raster','svg','both'or'none'.mediaPartNameis the raster part, else the SVG part.- A partname getter is
nullwhen the id is absent, when the part's relationships lack it, or when it points outside the package, as for a linked image. cropreadsa:srcRectas fractions, andrecolorreads the first recolour effect on the blip.setImage()replaces the image: see Read and edit a deck.
Connector endpoints
startConnectionandendConnectiondecodea:stCxnanda:endCxninto aConnectionSite:shapeId,siteIndexandboundShape.- An unbound end reads
null. So does an end whoseidoridxis not a number. boundShapefinds the shape with that id in the connector's host tree, groups included. It isnullwhen no shape carries the id.- The write-side
addConnector({ startShape, endShape })writes the binding, withidx="0"whenstartShapeIdxorendShapeIdxis omitted. See Connectors.
Text frames, paragraphs and runs
TextFrame.textjoins its paragraphs with\n. Setting it collapses the frame to one paragraph and one run, keeping the first run'sa:rPr.Paragraph.textjoins run and field text in document order, with eacha:bras\n. Setting it replaces that paragraph with one run, keeping its first run'sa:rPrand itsa:pPr, and leaves the other paragraphs alone.Run.textis thea:ttext as written. Setting a value with leading or trailing whitespace addsxml:space="preserve".Paragraph.runslistsa:relements only. Fields and breaks are not runs.bodyPropertiesreports only the insets, anchor, wrap and direction the frame states. An absent inset is PowerPoint's default.levelis0when unset.align,lineSpacing,spaceBeforePt,spaceAfterPt,marginLeftPtandindentPtarenullwhen unset.spaceBeforePtandspaceAfterPtare alsonullfor spacing given as a percentage.lineSpacingreports either form:{ type: 'points', valuePt }or{ type: 'percent', percent }, where150is 1.5 lines.bulletDetailreports the bullet asnone,char,autoNumorpicture, with the bullet's own font, size and colour. It isnullwhen the paragraph inherits its bullet.
A run's own getters and its resolved getters answer different questions:
Own value, null when the run does not set it | Effective value, through the inheritance chain |
|---|---|
fontSizePt | resolvedSizePt |
bold, italic | resolvedBold, resolvedItalic |
fontName, possibly a theme token | resolvedFontFace |
color, schemeColor | resolvedColor |
boldanditalicarenullwhen the attribute is absent, which means inherited, notfalse.- At most one of
colorandschemeColoris set. Setting one clears the other, and settingnullremoves the run's solid fill. fontSizePttakes points and rejects zero, negatives and non-finite values.bold,italic,fontSizePt,underlineandfontNameremove the attribute when set tonull.underlinetakes anST_TextUnderlineTypetoken such assng, and throwstext/invalid-underlinefor any other value.strikeandcapsreport the raw token, because the attribute has three states.baselinePctis a percent: the write side's superscript is30and its subscript-40.charSpacingPtandhighlightare read-only.
Autofit
autofitreads thea:bodyPrautofit child as'none','normAutofit'or'spAutoFit'. Aa:bodyPrwith no autofit child reads'none', and a frame with noa:bodyPrreadsnull.autofitFontScaleandautofitLineSpaceReductionread the percentages stored ona:normAutofit.- The write-side
fit: 'shrink'writes a bare<a:normAutofit/>, soautofitFontScalereadsnull: PowerPoint computes the scale when the text is next edited.fit: { type: 'shrink', fontScale, lnSpcReduction }stores the values. See Text that fits.
Hyperlinks
a:hlinkClick hangs in two places, and both are read into a Hyperlink.
Run.hyperlinkreads the link on a span of text (a:rPr/a:hlinkClick), and isnullwhen the run has no link.Shape.hyperlinkreads the link on the whole shape (p:cNvPr/a:hlinkClick), which is what Insert > Link puts on a picture or an action button. The two are independent: a shape whose text is linked carries no shape-level link, and the reverse.relIdresolves through the relationships of the part that holds the shape or the text. An external target fillsurl. An internal target, such as a slide jump, fillstargetPartName. An action-only link, such as a slide-show navigation button, has neither and reports itsaction.- Runs in shapes, table cells, speaker notes and SmartArt points all resolve their links.
- Text in a SmartArt drawing cache is read without relationships, so its links report
relId,actionandtooltiponly. - An empty
actionortooltipattribute readsnull.
Tables
GraphicFrame.table is set when hasTable is true. Tables lists the members and covers reading and editing a table as tasks. The notes below are how the getters behave.
Table.cell(row, column)countsa:tcelements in the row, and isnulloutside the table. A merged cell's covered positions are cells too, marked byisMergeContinuation.columnCountcountsa:gridColelements.TableRow.heightEmuisnullwhena:trhas noh.styleIdis the rawa:tableStyleIdGUID, the same string the write-sidetableStyleoption takes.resolvedStylelooks the id up inppt/tableStyles.xml. It isnullwhen that part does not define the style, as for a built-in style PowerPoint has not written into the deck.TableCell.resolvedFillis the cell's own solid fill. A cell with no fill of its own takes the table style's fill for its region: header row, banding or whole table. A cell with another kind of fill (a:blipFill,a:gradFill,a:pattFill,a:noFill) readsnull.hasOwnFilltells a cell's own fill from the style's.fillNoFill,pictureFill,gradientFillandpatternFillread the other kinds.Table.resolvedFilland its sibling getters read the table's own background ina:tblPr, which shows through cells with no fill.bordersisnullwhen the cell has noa:tcPror no edge element. Otherwise each of the four edges and two diagonals is aCellBorderornull.- An edge with
noFill: trueis explicitly suppressed. That is not the same as an edge the cell leaves to the table style. - A cell run's colour, typeface, bold and italic come from the table style's text style for the cell's region. When the style names no colour or typeface, they are the theme's
tx1and minor font, with or without a table style. - A cell run's size, and its bold and italic where the table style is silent, come from the master's
p:otherStyle, not fromp:defaultTextStyle.
Charts
GraphicFrame.chart resolves the frame's chart part, and is null when the part is missing.
- Charts are read-only. The values are the caches the chart part stores (
c:numCache,c:strCache), not the embedded workbook. - The chart part is read without a theme. A series colour reports
colorRef.srgbor an unresolvedcolorRef.scheme, andcolorRef.resolvedis alwaysnull. chartTypeis the first plot group's type.chartTypeslists every group, several for a combo chart.Chart.categoriesandcategoryLevelscome from the first series.Chart.dataLabelsis the first plot group's labels block.ChartSeries.dataLabelsis the series' own. A pie keeps the flags the user set on the series, and an all-off block on the group.- A bar or area series has no
a:lnby default, so itslinereadsnull.
| Series | Where the data is |
|---|---|
| Category charts (bar, line, pie and the rest) | values and categories |
| Scatter or bubble with numeric X | xValues, yValues, and bubbleSizes on a bubble. values is []. |
| Scatter or bubble whose X column holds any text | xValues is null at every point, and xLabels holds the text. PowerPoint plots the points at X = 1, 2 and so on, even for labels that read as numbers. |
| Scatter or bubble with no X values | xValues is [], xLabels is null, and PowerPoint plots the points at X = 1, 2 and so on. |
| Multi-level categories | categoryLevels, leaf level first. Every level is as long as the leaf, and an outer level names each group once, at its first category, with null for the rest. categories is the leaf level. |
ChartEx charts
GraphicFrame.chartEx reads the Office 2016 chart family: waterfall, funnel, treemap, sunburst, histogram, pareto, box and whisker, and region map. hasChartEx is true for a frame whose a:graphicData/@uri is the cx namespace.
- A chartEx chart is a separate part from a classic chart:
cx:chartSpace, content typeapplication/vnd.ms-office.chartex+xml, behind Microsoft's chartEx relationship. Its frame sits inmc:AlternateContent, whichshapesunwraps. layoutIdslists the rawcx:series/@layoutIdtokens, andlayoutIdis the first. They are not mapped to a write-side chart type: a histogram and a pareto both readclusteredColumn, and a pareto adds aparetoLineseries.ChartEx.categoriesandChartExSeries.categoriesread the firstcx:lvl, which is the leaf level: a treemap reads its leaf labels, not the parent groups.- Series data lives in
cx:chartData. A series finds its block throughdataId.ownerIndexnames the series a derived series comes from. ChartExAxis.kindcomes from the scaling child,cx:catScalingorcx:valScaling.gapWidthis a fraction where1is 100 percent, unlike a classic axis's integer percent.- The embedded workbook and the style, colours and geography parts are kept but not decoded.
SmartArt
A SmartArt graphic is a p:graphicFrame whose a:graphicData/@uri is the diagram namespace. The frame holds only a dgm:relIds element naming its parts. GraphicFrame.diagram resolves the data part it names, and is null when that part is missing.
Diagram.pointslists everydgm:ptin document order, unfiltered.connectionslists everydgm:cxn, andpoint()finds a point by themodelIda connection names.DiagramPoint.textFramereadsdgm:tthrough the ordinary text classes, run formatting included.layoutTypeIdnames the SmartArt layout, such asurn:microsoft.com/office/officeart/2005/8/layout/hList1.Slide.textincludes each diagram'stext, as it includes table text.
Point type | What it is | In Diagram.text | In Diagram.nodes |
|---|---|---|---|
node | A user's node | Yes | Yes |
asst | An assistant node, drawn off the main branch in an org chart | Yes | Yes |
parTrans, sibTrans | The label on an edge, empty unless the layout labels its arrows | When it has text | No: reach it through DiagramConnection parentTransitionId and siblingTransitionId |
doc | The diagram root | No | No: the roots of nodes hang off it |
pres | A point PowerPoint's layout engine generated to draw another | No | No |
Diagram.textalso leaves out points marked as unfilled placeholders (isPlaceholder), and skips points with no text.Diagram.nodesbuilds the tree fromparOfconnections:sourceIdis the parent,destinationIdthe child, andsourceOrderthe child's place among its siblings. Roots come insourceOrderorder.presOfandpresParOfconnections bind a node to theprespoints that draw it. They are the layout engine's records, not the tree.- A
parOfcycle throwsdiagram/parent-edge-cycle, including a cycle no root reaches.
ts
import type { DiagramNode } from 'pptx-ts/read'
const outline = (node: DiagramNode): string[] => [
`${' '.repeat(node.level)}${node.point.text}`,
...node.children.flatMap(outline),
]
for (const shape of slide.shapes) {
if (shape.shapeType === 'graphicFrame' && shape.diagram) {
console.log(shape.diagram.nodes.flatMap(outline).join('\n'))
}
}SmartArt: data model and drawing cache
A diagram stores each string twice. The data part (dgm:dataModel) is what PowerPoint reads, and PowerPoint redraws the diagram from it on open. The drawing part (dsp:drawing) holds a copy of every drawn string, and a renderer with no SmartArt layout engine paints that copy: LibreOffice, Google Slides, thumbnailers and web previews.
DiagramPoint.drawnShape links a point to its drawn text, and Diagram.drawingPart is the drawing part. The link runs through a pres point:
- A
dsp:spcarries aprespoint'smodelId, never the authored point's. A lookup by the node's own id finds nothing. - One drawn shape can draw several points. The connection's
destOrdis the paragraph index, and it can disagree with document order, so editing the drawn shape's whole text frame would overwrite the other points' text.DiagramDrawnShape.paragraphIndexnames the point's paragraph. - One point can have several
presOfconnections, such as an org chart box and the connector under it.drawnShapetakes the one that reaches adsp:spwith a text body. - An
asstpoint resolves the same way as anode. drawnShapeisnullwhen the deck has no drawing part, when the point has nopresOfconnection (every unlabelled edge label), when theprespoint draws nodsp:sp, or when that shape has no text body, as for a connector or a picture node.
Editing diagram text
Setting DiagramPoint.text writes both copies: the dgm:t PowerPoint reads, and the drawn paragraph other renderers paint. It marks the data part and the drawing part dirty. Like the other text setters, it collapses the point to one run and keeps the first run's a:rPr.
ts
for (const node of diagram.nodes) node.point.text = node.point.text.toUpperCase()- Geometry is not recomputed. A drawn shape keeps its cached size, so a longer string overflows its box in renderers without a layout engine until PowerPoint opens and saves the deck.
- A point that resolves to no drawn paragraph still gets the data-model edit, and a
diagram/drawing-cache-not-updatedwarning says the cache is stale. - A point with no
dgm:tis left unchanged, with adiagram/point-has-no-text-bodywarning. A layout with no room for an edge label stores that label this way, and PowerPoint strips text put on it at the next save. - An edit through
DiagramPoint.textFramechanges the data model only, and the drawing cache keeps the old text. UsetextFramefor per-run formatting, andtextfor an edit other renderers show. pnpm run test:lorenders both cases in LibreOffice, which paints only the cache. See LibreOffice render check.- The library does not author a diagram from nothing. The layout part is a program PowerPoint's layout engine runs, and the tree of
prespoints it generates cannot be derived from the user's content.