PPTX Studio
Packages

model

Slides, layouts, masters and themes as one document, with a resolver that says where every value came from.

@pptx-studio/model0.5.0runs inTabWorkerNodeLive demo →npm →

Slides, layouts, masters and themes as one document, with a resolver that reports where every value came from.

npm install @pptx-studio/model @pptx-studio/opc @pptx-studio/xml @pptx-studio/geometry @pptx-studio/paint

What it is

A shape on a slide usually declares only what differs from its layout placeholder, which declares only what differs from the master's, which reads its colours and fonts from the theme. @pptx-studio/model parses all of those from a PartStore, binds them through each part's own relationships, and exposes a resolver that answers with the value and its origin.

A property the file did not state stays undefined. That is the one decision the later phases - change layout, theme swap, per-property reset - rest on.

30-second example

resolve.ts
const doc = loadDocument(PartStore.open(bytes));
const slide = doc.slides[0];
if (slide === undefined) throw new Error('no slides');

for (const shape of slide.shapes) {
  const xfrm = resolveXfrm(shape, slide);
  console.log(shape.name, xfrm?.origin, xfrm?.value); // 'Title 1' 'masterPh' { x, y, cx, cy, rot, … }
  console.log(
    inheritanceChain(shape, slide).map((link) => `${link.origin} ${link.sheet.partName}`),
  );
}

Key concepts

undefined means the file did not say

Other editors bake inherited values into the slide the moment they open it and lose the fact that the slide never had them. Here shape.xfrm === undefined is information, and resolveXfrm walks the chain on demand.

The two hops use different keys

A slide placeholder finds its layout placeholder by idx alone; a layout placeholder finds its master placeholder by a folded type. inheritanceChain shows the hops and what matched.

Every binding comes from the part's own rels

Which layout a slide uses, which master a layout uses, which theme a master uses: each is one relationship in that part's .rels, and nothing is looked up by name.

The style matrix and phClr

A shape with an a:style reference takes its fill and line from the theme's format scheme, with the placeholder colour substituted in. resolveAppearance reports which of the three sources answered.

The resolver reports where it looked

Every Resolved<T> carries origin, explicit, sheet and shape, so a provenance panel is a rendering of the answer, not a second computation.

API reference

190 exports of @pptx-studio/model 0.5.0, read from the package this site installed. Click a name for its declaration.

index.ts

  • COLOR_TRANSFORM_OPSre-export
    re-exported from @pptx-studio/paint

src/errors.ts

  • ModelErrorCodetypeTyped failures, as everywhere else in this repository.
    type ModelErrorCode =
    /** A part the chain needs is not in the package. */
    'MODEL_PART_MISSING' |
    /** A part is present but its root element is not the one its rel promised. */
    'MODEL_PART_KIND' |
    /** `ppt/presentation.xml` is missing, or the root rels do not name it. */
    'MODEL_NO_PRESENTATION' |
    /** A slide has no `slideLayout` relationship, or a layout no `slideMaster`. */
    'MODEL_NO_PARENT' |
    /** A master has no `theme` relationship. */
    'MODEL_NO_THEME' |
    /** A `p:clrMap` or `a:overrideClrMapping` missing one of its twelve attributes. */
    'MODEL_CLRMAP_INCOMPLETE' |
    /** A `p:clrMap` attribute naming something that is not one of the twelve slots. */
    'MODEL_CLRMAP_SLOT' |
    /** A `p:ph/@idx` that is not a non-negative integer below 2^32. */
    'MODEL_PLACEHOLDER_IDX' |
    /** An `a:off`/`a:ext`/`@rot` attribute that is not an integer. */
    'MODEL_XFRM_NUMBER' |
    /** A style-matrix reference whose `@idx` does not parse. */
    'MODEL_STYLE_IDX' |
    /** An `a:fontRef/@idx` outside `major`, `minor` and `none`. */
    'MODEL_FONT_COLLECTION' |
    /** A theme with no `a:fmtScheme`, asked for a style-matrix entry. */
    'MODEL_NO_STYLE_MATRIX' |
    /** A `a:fillStyleLst`/`a:lnStyleLst`/`a:bgFillStyleLst` with no entries at all. */
    'MODEL_STYLE_LIST_EMPTY' |
    /** A sheet chain that returns to a sheet it has already visited. */
    'MODEL_SHEET_CYCLE' |
    /** A sheet that does not belong to the document it was asked about. */
    'MODEL_FOREIGN_SHEET' |
    /** `a:prstGeom` with no `@prst`, or an `a:custGeom` command missing a point. */
    'MODEL_GEOMETRY' |
    /** A text attribute whose value is not of the type its schema names. */
    'MODEL_TEXT_ATTR' |
    /** An `a:fld` with no `@id`, which is a required `ST_Guid`. */
    'MODEL_TEXT_FIELD' |
    /**
     * A bullet that contradicts itself or omits what the schema requires.
     *
     * The four kinds are an exclusive group, `a:buAutoNum` must carry a @type and
     * `a:buBlip` must resolve to a relationship. A file that breaks one of those is
     * one PowerPoint would repair, and repairing it here quietly would hide which.
     */
    'MODEL_TEXT_BULLET' |
    /** A paragraph level that is not an integer. */
    'MODEL_TEXT_LEVEL' | 'MODEL_TEXT_TYPEFACE' |
    /** A table attribute missing where the schema requires it, or not of the type it names. */
    'MODEL_TABLE_ATTR' |
    /** A table-style edge with neither `a:ln` nor `a:lnRef`, or an `a:fill` holding no fill. */
    'MODEL_TABLE_STYLE' |
    /** A grid position or grid edge asked of a table that has no such position or edge. */
    'MODEL_TABLE_POSITION' | 'BLIP_NO_EMBED' | 'BLIP_DUOTONE' | 'BLIP_CLR_CHANGE' | 'BLIP_TILE_ALIGN' | 'BLIP_TILE_FLIP';
  • ModelErrorclass
    class ModelError extends Error {
      readonly name = "ModelError";
      readonly code: ModelErrorCode;
      /** The part the failure is about, when there is one. */
      readonly partName: string | null;
      /** Whatever detail names the failure: an attribute value, a rel id, a slot. */
      readonly detail: string | null;
      constructor(code: ModelErrorCode, message: string, partName?: string | null, detail?: string | null);
    }
  • isModelErrorfunction
    function isModelError(value: unknown): value is ModelError;
  • MODEL_ERROR_CODESconst
    const MODEL_ERROR_CODES: readonly ["MODEL_PART_MISSING", "MODEL_PART_KIND", "MODEL_NO_PRESENTATION", "MODEL_NO_PARENT", "MODEL_NO_THEME", "MODEL_CLRMAP_INCOMPLETE", "MODEL_CLRMAP_SLOT", "MODEL_PLACEHOLDER_IDX", "MODEL_XFRM_NUMBER", "MODEL_GEOMETRY", "MODEL_STYLE_IDX", "MODEL_FONT_COLLECTION", "MODEL_NO_STYLE_MATRIX", "MODEL_STYLE_LIST_EMPTY", "MODEL_SHEET_CYCLE", "MODEL_FOREIGN_SHEET", "MODEL_TEXT_ATTR", "MODEL_TEXT_FIELD", "MODEL_TEXT_LEVEL", "MODEL_TEXT_BULLET", "MODEL_TEXT_TYPEFACE", "MODEL_TABLE_ATTR", "MODEL_TABLE_STYLE", "MODEL_TABLE_POSITION", "BLIP_NO_EMBED", "BLIP_DUOTONE", "BLIP_CLR_CHANGE", "BLIP_TILE_ALIGN", "BLIP_TILE_FLIP"];

src/parse/geometry.ts

  • ShapeGeometrytypeWhat a shape says it is.
    type ShapeGeometry = {
      readonly kind: 'preset';
      readonly prst: string;
      readonly adjust: readonly PresetGuide[];
    } | {
      readonly kind: 'custom';
      readonly geometry: Geometry;
    };
  • parseGeometryfunctionThe geometry a shape declares, or undefined when it declares none.
    function parseGeometry(spPr: XElement | undefined, partName: string): ShapeGeometry | undefined;

src/text.ts

  • TextAligntypeST_TextAlignType.
    type TextAlign = 'l' | 'ctr' | 'r' | 'just' | 'justLow' | 'dist' | 'thaiDist';
  • FontAligntypeST_TextFontAlignType.
    type FontAlign = 'auto' | 't' | 'ctr' | 'base' | 'b';
  • UnderlinetypeST_TextUnderlineType, all seventeen, as written.
    type Underline = 'none' | 'words' | 'sng' | 'dbl' | 'heavy' | 'dotted' | 'dottedHeavy' | 'dash' | 'dashHeavy' | 'dashLong' | 'dashLongHeavy' | 'dotDash' | 'dotDashHeavy' | 'dotDotDash' | 'dotDotDashHeavy' | 'wavy' | 'wavyHeavy' | 'wavyDbl';
  • StriketypeST_TextStrikeType.
    type Strike = 'noStrike' | 'sngStrike' | 'dblStrike';
  • CapstypeST_TextCapsType.
    type Caps = 'none' | 'small' | 'all';
  • Spacingtypea:lnSpc, a:spcBef and a:spcAft, which are one of two quite different things and say which in their child element's name.
    type Spacing = {
      readonly kind: 'percent';
      readonly value: number;
    } | {
      readonly kind: 'points';
      readonly value: number;
    };
  • TypefacetypeOne of the four typeface slots on a run.
    interface Typeface {
      readonly typeface: string;
      /** `@panose`, twenty hex characters. */
      readonly panose: string | undefined;
      /** `@pitchFamily`, `(family << 4) | pitch`. */
      readonly pitchFamily: number | undefined;
      /** `@charset`, **signed**: Shift-JIS is -128, not 128. */
      readonly charset: number | undefined;
    }
  • ThemeFontReftypeWhich of a theme's two font collections a +mj-/+mn- reference names.
    type ThemeFontRef = {
      readonly collection: 'major' | 'minor';
      readonly script: 'latin' | 'ea' | 'cs';
    };
  • themeFontReffunction+mn-lt and its five siblings, or null for a real typeface name.
    function themeFontRef(typeface: string): ThemeFontRef | null;
  • RunPropstypeCT_TextCharacterProperties - a:rPr, a:defRPr and a:endParaRPr.
    interface RunProps {
      /** `@sz`, hundredths of a point. 2400 is 24pt. */
      readonly sz: number | undefined;
      readonly b: boolean | undefined;
      readonly i: boolean | undefined;
      readonly u: Underline | undefined;
      readonly strike: Strike | undefined;
      readonly cap: Caps | undefined;
      /** `@spc`, hundredths of a point. May be negative. */
      readonly spc: number | undefined;
      /** `@kern`, hundredths of a point: the size at or above which to kern. */
      readonly kern: number | undefined;
      /** `@baseline`, hundred-thousandths. 30000 is superscript. */
      readonly baseline: number | undefined;
      readonly noProof: boolean | undefined;
      readonly lang: string | undefined;
      readonly altLang: string | undefined;
      readonly latin: Typeface | undefined;
      readonly ea: Typeface | undefined;
      readonly cs: Typeface | undefined;
      readonly sym: Typeface | undefined;
      /** The text's own fill: `a:solidFill` and its siblings inside `a:rPr`. */
      readonly fill: Fill | undefined;
      /** `a:ln` inside `a:rPr`: the outline of the glyphs. */
      readonly line: Line | undefined;
      readonly effects: readonly Effect[] | undefined;
      /** `a:highlight`, which is a colour and not a fill. */
      readonly highlight: Color | undefined;
      /** The element this was read from. Edits go here, never to the fields above. */
      readonly node: XElement;
    }
  • BulletKindtypeThe exclusive group in CT_TextParagraphProperties: one of four, or nothing.
    type BulletKind = 'none' | 'char' | 'autonum' | 'blip';
  • BulletFonttypea:buFont / a:buFontTx, which are exclusive of each other.
    type BulletFont = {
      readonly kind: 'typeface';
      readonly value: Typeface;
    } |
    /** `a:buFontTx`: follow the text, and cancel anything inherited. */
    {
      readonly kind: 'text';
    };
  • BulletSizetypea:buSzPct / a:buSzPts / a:buSzTx.
    type BulletSize =
    /** `a:buSzPct/@val`, thousandths of a percent of the first run's size. */
    {
      readonly kind: 'percent';
      readonly value: number;
    } |
    /** `a:buSzPts/@val`, hundredths of a point, absolute. */
    {
      readonly kind: 'points';
      readonly value: number;
    } | {
      readonly kind: 'text';
    };
  • BulletColortypea:buClr / a:buClrTx.
    type BulletColor = {
      readonly kind: 'color';
      readonly value: Color;
    } | {
      readonly kind: 'text';
    };
  • BulletAutoNumtypea:buAutoNum.
    interface BulletAutoNum {
      /** `@type`, one of the 41 `ST_TextAutonumberScheme` values. */
      readonly type: string;
      /**
       * `@startAt`. Absent is measured to behave exactly as `1` - but the two are
       * kept apart, because a paragraph whose `startAt` differs from its
       * predecessor's begins a new run, and "absent" has to compare equal to "1"
       * for that rule rather than to nothing.
       */
      readonly startAt: number | undefined;
    }
  • ParaPropstypeCT_TextParagraphProperties - a:pPr and every a:lvlNpPr.
    interface ParaProps {
      /** `@marL`, EMU. Measured to default to **0**, not to the schema's 347663. */
      readonly marL: number | undefined;
      readonly marR: number | undefined;
      /** `@indent`, EMU, usually negative. Defaults to 0, not to -342900. */
      readonly indent: number | undefined;
      readonly algn: TextAlign | undefined;
      /** `@defTabSz`, EMU. */
      readonly defTabSz: number | undefined;
      readonly rtl: boolean | undefined;
      readonly eaLnBrk: boolean | undefined;
      readonly fontAlgn: FontAlign | undefined;
      /** `@latinLnBrk`. ECMA says the default is true; PowerPoint behaves as false. */
      readonly latinLnBrk: boolean | undefined;
      readonly hangingPunct: boolean | undefined;
      readonly lnSpc: Spacing | undefined;
      readonly spcBef: Spacing | undefined;
      readonly spcAft: Spacing | undefined;
      /** `a:defRPr`: the run properties every run in this paragraph starts from. */
      readonly defRPr: RunProps | undefined;
      /**
       * Which of `a:buNone`, `a:buChar`, `a:buAutoNum` and `a:buBlip` this level
       * states, or `undefined` where it states none and inherits instead.
       */
      readonly buKind: BulletKind | undefined;
      /** `a:buChar/@char`, exactly as written. The symbol mapping happens at draw time. */
      readonly buChar: string | undefined;
      readonly buAutoNum: BulletAutoNum | undefined;
      /** `a:buBlip/a:blip/@r:embed`. */
      readonly buBlip: string | undefined;
      /**
       * The three decorations, each its own slot.
       *
       * They merge independently of the kind and of each other, which is measured
       * rather than assumed: a level declaring only `a:buFont` re-faces the
       * character it inherits and keeps its size and colour, and a level declaring
       * only `a:buSzTx` cancels an inherited `a:buSzPct` and keeps the rest.
       * Measured on eleven cases twice - once through a shape's own `a:lstStyle`
       * and once through three hops of the master chain.
       */
      readonly buFont: BulletFont | undefined;
      readonly buSize: BulletSize | undefined;
      readonly buColor: BulletColor | undefined;
      readonly node: XElement;
    }
  • ListStyletypeCT_TextListStyle: nine levels, and an a:defPPr nothing reads.
    interface ListStyle {
      /** Nine entries, `a:lvl1pPr` through `a:lvl9pPr`, absent ones `undefined`. */
      readonly levels: readonly (ParaProps | undefined)[];
      /** `a:defPPr`. Preserved, never resolved against. */
      readonly defPPr: ParaProps | undefined;
      readonly node: XElement;
    }
  • LEVELSconstThe number of levels a CT_TextListStyle holds, and @lvl's range plus one.
    const LEVELS = 9;
  • TextRuntypea:r: a run of text with its own properties.
    interface TextRun {
      readonly kind: 'run';
      readonly props: RunProps | undefined;
      readonly text: string;
      readonly node: XElement;
    }
  • TextBreaktypea:br: a hard line break.
    interface TextBreak {
      readonly kind: 'br';
      readonly props: RunProps | undefined;
      readonly node: XElement;
    }
  • TextFieldtypea:fld: a field, with the text PowerPoint last cached for it.
    interface TextField {
      readonly kind: 'field';
      /** `@id`, a required `ST_Guid`. Regenerating it is a repair risk. */
      readonly id: string;
      /** `@type`, one of the fourteen reserved names or a custom one. */
      readonly fieldType: string | undefined;
      readonly props: RunProps | undefined;
      readonly text: string;
      readonly node: XElement;
    }
  • TextContenttype
    type TextContent = TextRun | TextBreak | TextField;
  • Paragraphtypea:p.
    interface Paragraph {
      readonly props: ParaProps | undefined;
      /**
       * `a:pPr/@lvl`, 0 through 8, defaulting to 0.
       *
       * Read off the paragraph rather than inherited, and clamped rather than
       * thrown on: `ST_TextIndentLevelType` bounds it at 8, and a file outside the
       * bound is one PowerPoint still opens.
       */
      readonly level: number;
      readonly content: readonly TextContent[];
      /** `a:endParaRPr`: the properties of the (empty) run after the last one. */
      readonly endParaRPr: RunProps | undefined;
      readonly node: XElement;
    }
  • TextAnchortypeST_TextAnchoringType. PowerPoint lays just and dist out as b.
    type TextAnchor = 't' | 'ctr' | 'b' | 'just' | 'dist';
  • VerticalTexttypeST_TextVerticalType.
    type VerticalText = 'horz' | 'vert' | 'vert270' | 'wordArtVert' | 'eaVert' | 'mongolianVert' | 'wordArtVertRtl';
  • TextBodytypep:txBody / a:txBody.
    interface TextBody {
      readonly bodyPr: BodyProps | undefined;
      readonly lstStyle: ListStyle | undefined;
      readonly paragraphs: readonly Paragraph[];
      readonly node: XElement;
    }
  • TextStyleBuckettypeThe bucket of p:txStyles a shape reads, or null for one that reads none.
    type TextStyleBucket = 'title' | 'body' | 'other';
  • TextStylestypep:txStyles on a master.
    interface TextStyles {
      readonly title: ListStyle | undefined;
      readonly body: ListStyle | undefined;
      readonly other: ListStyle | undefined;
      readonly node: XElement;
    }

src/table.ts

  • TABLE_URIconsta:graphicData/@uri of a table.
    const TABLE_URI = "http://schemas.openxmlformats.org/drawingml/2006/table";
  • INVENTED_COLUMN_WIDTHconstThe column PowerPoint invents for a grid that declares none, empty: two margins and 2 pt.
    const INVENTED_COLUMN_WIDTH = 208280;
  • TablePropstypea:tblPr. The seven flags are the file's own and inherit from nothing, so absent is false.
    interface TableProps {
      readonly rtl: boolean;
      readonly firstRow: boolean;
      readonly firstCol: boolean;
      readonly lastRow: boolean;
      readonly lastCol: boolean;
      readonly bandRow: boolean;
      readonly bandCol: boolean;
      readonly fill: Fill | undefined;
      readonly effects: readonly Effect[] | undefined;
      readonly style: TableStyleRef | undefined;
      readonly node: XElement;
    }
  • TableStyleReftypea:tableStyleId, or an inline a:tableStyle, which PowerPoint resolves by its @styleId alone.
    type TableStyleRef = {
      readonly kind: 'id';
      readonly id: string;
    } | {
      readonly kind: 'inline';
      readonly id: string;
      readonly node: XElement;
    };
  • TableColumntypea:gridCol.
    interface TableColumn {
      /** `@w` in EMU. */
      readonly w: number;
      readonly node: XElement;
    }
  • TableRowtypea:tr.
    interface TableRow {
      /** `@h` in EMU: the least the row is drawn at, never the most. */
      readonly h: number;
      readonly cells: readonly TableCell[];
      readonly node: XElement;
    }
  • TableCelltypea:tc: an absent span reads as 1 and an absent flag as false; tableGrid says what they mean.
    interface TableCell {
      readonly gridSpan: number;
      readonly rowSpan: number;
      readonly hMerge: boolean;
      readonly vMerge: boolean;
      /** `@id`, which `a:headers` in other cells name. */
      readonly id: string | null;
      readonly text: TextBody | undefined;
      readonly props: TableCellProps | undefined;
      readonly node: XElement;
    }
  • TableCellBorderstypeThe six a:tcPr borders, each an a:ln under another name.
    interface TableCellBorders {
      readonly left: Line | undefined;
      readonly right: Line | undefined;
      readonly top: Line | undefined;
      readonly bottom: Line | undefined;
      readonly tlToBr: Line | undefined;
      readonly blToTr: Line | undefined;
    }
  • TableCellPropstypea:tcPr. Margins are EMU as written; the schema's defaults are 91440 and 45720.
    interface TableCellProps {
      readonly marL: number | undefined;
      readonly marR: number | undefined;
      readonly marT: number | undefined;
      readonly marB: number | undefined;
      readonly vert: VerticalText | undefined;
      readonly anchor: TextAnchor | undefined;
      readonly anchorCtr: boolean | undefined;
      readonly horzOverflow: HorzOverflow | undefined;
      readonly borders: TableCellBorders;
      readonly fill: Fill | undefined;
      /** `a:headers/a:header`, the ids of the cells that head this one. */
      readonly headers: readonly string[];
      readonly node: XElement;
    }
  • Tabletype
    interface Table {
      readonly props: TableProps | undefined;
      readonly columns: readonly TableColumn[];
      readonly rows: readonly TableRow[];
      readonly node: XElement;
    }
  • GridCelltypeA grid position's owner: the anchor cell, its clamped span, and the a:tc there.
    interface GridCell {
      readonly row: number;
      readonly col: number;
      readonly rows: number;
      readonly cols: number;
      /** `null` for a position no `a:tc` reached, which PowerPoint draws empty. */
      readonly cell: TableCell | null;
    }
  • TableGridtypeThe grid as drawn: positions[r][c] is the owner of (r, c); anchors lists each owner once.
    interface TableGrid {
      readonly rows: number;
      readonly cols: number;
      /** Column widths in EMU. */
      readonly widths: readonly number[];
      /** Row heights in EMU, each the least its row is drawn at. */
      readonly heights: readonly number[];
      readonly positions: readonly (readonly GridCell[])[];
      readonly anchors: readonly GridCell[];
    }
  • tableGridfunctionThe occupancy C7 measured, 76/76 against 52/76 for the flags: each a:tc takes the next column, a claimed position is covered whatever it says, a span stops at the edge or a claim.
    function tableGrid(table: Table): TableGrid;
  • OnOffStyletypeST_OnOffStyleType.
    type OnOffStyle = 'on' | 'off' | 'def';
  • ThemeabletypeA value written out, or a reference into the theme: the EG_Themeable* choices.
    type Themeable<T, Ref = StyleRef> = {
      readonly kind: 'value';
      readonly value: T;
    } | {
      readonly kind: 'ref';
      readonly ref: Ref;
    };
  • TableStyleTexttypea:tcTxStyle.
    interface TableStyleText {
      readonly b: OnOffStyle | undefined;
      readonly i: OnOffStyle | undefined;
      readonly font: Themeable<FontCollection, FontRef> | undefined;
      readonly color: Color | undefined;
    }
  • TableStyleBorderstypea:tcBdr; tl2br and tr2bl take the names TableCellBorders gives the diagonals.
    interface TableStyleBorders {
      readonly left: Themeable<Line> | undefined;
      readonly right: Themeable<Line> | undefined;
      readonly top: Themeable<Line> | undefined;
      readonly bottom: Themeable<Line> | undefined;
      readonly insideH: Themeable<Line> | undefined;
      readonly insideV: Themeable<Line> | undefined;
      readonly tlToBr: Themeable<Line> | undefined;
      readonly blToTr: Themeable<Line> | undefined;
    }
  • TableStyleCelltypea:tcStyle.
    interface TableStyleCell {
      readonly borders: TableStyleBorders | undefined;
      readonly fill: Themeable<Fill> | undefined;
      /** `a:cell3D`, kept as written. */
      readonly cell3D: XElement | undefined;
    }
  • TableStyleParttypeOne of a style's thirteen parts.
    interface TableStylePart {
      readonly text: TableStyleText | undefined;
      readonly cell: TableStyleCell | undefined;
    }
  • TableBackgroundtypea:tblBg. An a:effect holding an a:effectDag reads as undefined, as parseEffects does.
    interface TableBackground {
      readonly fill: Themeable<Fill> | undefined;
      readonly effect: Themeable<readonly Effect[] | undefined> | undefined;
    }
  • TableStylePartNametypeThe thirteen parts in schema order, which is the order they compose in, lowest first (C9).
    type TableStylePartName = 'wholeTbl' | 'band1H' | 'band2H' | 'band1V' | 'band2V' | 'lastCol' | 'firstCol' | 'lastRow' | 'seCell' | 'swCell' | 'firstRow' | 'neCell' | 'nwCell';
  • TableStyletypeCT_TableStyle: an a:tblStyle, or an inline a:tableStyle. Nothing absent is defaulted.
    interface TableStyle {
      readonly id: string;
      readonly name: string;
      readonly background: TableBackground | undefined;
      readonly parts: Readonly<Partial<Record<TableStylePartName, TableStylePart>>>;
      readonly node: XElement;
    }
  • TableBackgroundLayerstypeWhat paints under a table's cells, each layer with where it came from.
    interface TableBackgroundLayers {
      readonly fill: TableSourced<Themeable<Fill>> | null;
      readonly effects: TableSourced<Themeable<readonly Effect[] | undefined>> | null;
    }
  • TableDiagonalstypeA cell's diagonals as drawn: down from its visual top left, up from its visual bottom left.
    interface TableDiagonals {
      readonly down: Line | null;
      readonly up: Line | null;
    }
  • TableEdgetypeA grid edge: h is the top of row row at column col (row = rows is the bottom); v the left of column col.
    interface TableEdge {
      readonly axis: 'h' | 'v';
      readonly row: number;
      readonly col: number;
    }
  • TableSourcetypeWhere a table's format came from: a style part, tblBg, a cell's a:tcPr, a:tblPr, or the default grid.
    type TableSource = TableStylePartName | 'tblBg' | 'tcPr' | 'tblPr' | 'grid';
  • TableSourcedtype
    interface TableSourced<T> {
      readonly value: T;
      readonly source: TableSource;
    }

src/types.ts

  • Xfrmtypea:off and a:ext together, in EMU, plus the three transform attributes.
    interface Xfrm {
      readonly x: number;
      readonly y: number;
      readonly cx: number;
      readonly cy: number;
      /** `@rot`, sixtieths of a degree. Zero when the attribute was absent. */
      readonly rot: number;
      readonly flipH: boolean;
      readonly flipV: boolean;
      /** `a:chOff`/`a:chExt`, present only on a group's `a:xfrm`. */
      readonly child: {
        readonly x: number;
        readonly y: number;
        readonly cx: number;
        readonly cy: number;
      } | null;
    }
  • PlaceholderTypetypeST_PlaceholderType. All nineteen, as written.
    type PlaceholderType = 'title' | 'body' | 'ctrTitle' | 'subTitle' | 'obj' | 'chart' | 'tbl' | 'clipArt' | 'dgm' | 'media' | 'sldImg' | 'pic' | 'sldNum' | 'hdr' | 'ftr' | 'dt';
  • PLACEHOLDER_TYPESconst
    const PLACEHOLDER_TYPES: readonly PlaceholderType[];
  • MASTER_PLACEHOLDER_TYPESconstThe six a slide master may carry. Measured; see PlaceholderType.
    const MASTER_PLACEHOLDER_TYPES: readonly PlaceholderType[];
  • PlaceholderSizetype@sz, a sizing hint. Recorded, and not part of matching - measured.
    type PlaceholderSize = 'full' | 'half' | 'quarter';
  • Placeholdertype
    interface Placeholder {
      /**
       * `@type` as written, or `null` when the attribute was absent.
       *
       * `null` is kept rather than defaulted, because "the file said `obj`" and
       * "the file said nothing" are different facts and only the second one is safe
       * to rewrite. `normalizePlaceholder` supplies the default when a comparison
       * needs one.
       */
      readonly type: PlaceholderType | null;
      /** `@idx` as written, or `null` when absent. Defaults to 0 when compared. */
      readonly idx: number | null;
      readonly size: PlaceholderSize | null;
      /** `@orient`. Recorded, and not part of matching. */
      readonly orient: 'horz' | 'vert' | null;
      readonly hasCustomPrompt: boolean;
    }
  • NormalPlaceholdertypeA placeholder with its defaults supplied: what the matcher compares.
    interface NormalPlaceholder {
      readonly type: PlaceholderType;
      readonly idx: number;
    }
  • ShapeKindtypeOne of the six things a p:spTree may contain.
    type ShapeKind = 'sp' | 'pic' | 'grpSp' | 'graphicFrame' | 'cxnSp' | 'contentPart';
  • StyleReftypea:lnRef, a:fillRef and a:effectRef: an index into the style matrix.
    interface StyleRef {
      /**
       * `@idx`. Zero means none; 1..999 index the main list; 1001 and up index the
       * background list, offset by 1000. Measured on both `a:fillRef` and
       * `p:bgRef`, which turn out to be the same rule over the same six entries.
       */
      readonly idx: number;
      /** The colour `phClr` takes inside the entry this reference names. */
      readonly color: Color | null;
    }
  • FontReftypea:fontRef. @idx is a collection name, never a number.
    interface FontRef {
      readonly idx: 'major' | 'minor' | 'none';
      readonly color: Color | null;
    }
  • ShapeStyletypep:style: four references into the theme's a:fmtScheme and a:fontScheme.
    interface ShapeStyle {
      readonly lnRef: StyleRef;
      readonly fillRef: StyleRef;
      readonly effectRef: StyleRef;
      readonly fontRef: FontRef;
    }
  • ShapetypeA shape, exactly as its part wrote it.
    interface Shape {
      readonly kind: ShapeKind;
      /** `p:cNvPr/@id`. Unique within a part, and may repeat across parts. */
      readonly cNvPrId: number;
      readonly name: string;
      /** `p:cNvPr/@descr`, the alt text. */
      readonly descr: string | null;
      readonly hidden: boolean;
      readonly placeholder: Placeholder | null;
      readonly xfrm: Xfrm | undefined;
      readonly fill: Fill | undefined;
      readonly line: Line | undefined;
      readonly effects: readonly Effect[] | undefined;
      readonly style: ShapeStyle | undefined;
      /** `a:prstGeom/@prst`, or `null` for a `custGeom` or no geometry at all. */
      readonly prstGeom: string | undefined;
      /**
       * `a:prstGeom` or `a:custGeom`, parsed far enough to draw.
       *
       * `undefined` when the shape declares neither, which is the ordinary state of
       * a slide placeholder: it inherits its outline from its layout exactly as it
       * inherits its rectangle, and `resolve` is what asks.
       */
      readonly geometry: ShapeGeometry | undefined;
      /**
       * `p:txBody`, when the shape has one.
       *
       * Present on every `p:sp` PowerPoint writes, including the ones with no text
       * in them, and absent from a `p:pic` or a `p:graphicFrame`. Its `a:lstStyle`
       * is one level of the text cascade; the paragraphs are the text itself.
       */
      readonly text: TextBody | undefined;
      /** The `a:tbl` of a `p:graphicFrame` whose graphic data is a table. */
      readonly table: Table | undefined;
      /** Children, for a `grpSp`. Empty for everything else. */
      readonly children: readonly Shape[];
      /** The element this was read from. Edits go here, never to the fields above. */
      readonly node: XElement;
    }
  • Backgroundtypep:bg, which is one of two quite different things.
    type Background = {
      readonly kind: 'fill';
      readonly fill: Fill;
      readonly effects: readonly Effect[] | undefined;
    } | {
      readonly kind: 'ref';
      readonly ref: StyleRef;
    };
  • FormatSchemetypea:fmtScheme: four lists of style entries, held as the elements they were.
    interface FormatScheme {
      readonly name: string | null;
      /** `a:fillStyleLst`. Each entry is a whole `EG_FillProperties` element. */
      readonly fillStyles: readonly Fill[];
      /** `a:lnStyleLst`. Each entry is a whole `a:ln`. */
      readonly lineStyles: readonly Line[];
      /** `a:effectStyleLst`. Each entry's `a:effectLst`, flattened. */
      readonly effectStyles: readonly (readonly Effect[])[];
      /** `a:bgFillStyleLst`, which `@idx` 1001 and up reach. */
      readonly bgFillStyles: readonly Fill[];
    }
  • FontCollectiontypea:fontScheme: the two collections +mj- and +mn- name.
    interface FontCollection {
      /** `a:latin/@typeface`. An empty string means the theme states none. */
      readonly latin: string | null;
      readonly ea: string | null;
      readonly cs: string | null;
    }
  • FontSchemetype
    interface FontScheme {
      readonly name: string | null;
      readonly major: FontCollection;
      readonly minor: FontCollection;
    }
  • Themetype
    interface Theme {
      readonly partName: string;
      readonly name: string | null;
      readonly scheme: ClrScheme;
      readonly fonts: FontScheme;
      readonly format: FormatScheme | null;
      readonly node: XElement;
    }
  • SheetKindtype
    type SheetKind = 'slide' | 'layout' | 'master';
  • ColorMapOverridetypep:clrMapOvr, which has exactly two forms and one surprise.
    type ColorMapOverride = {
      readonly kind: 'inherit';
    } | {
      readonly kind: 'override';
      readonly map: ClrMap;
    };
  • SheettypeA slide, a layout or a master, with its parent already resolved.
    interface Sheet {
      readonly kind: SheetKind;
      readonly partName: string;
      /** `p:cSld/@name`. */
      readonly name: string | null;
      /** `p:sldLayout/@type`, one of `ST_SlideLayoutType`. Layouts only. */
      readonly layoutType: string | null;
      /** `p:sldLayout/@matchingName`. Layouts only, and only when written. */
      readonly matchingName: string | null;
      readonly shapes: readonly Shape[];
      readonly background: Background | undefined;
      /** `p:clrMap`, on a master. `undefined` everywhere else. */
      readonly clrMap: ClrMap | undefined;
      /**
       * `p:txStyles`, on a master. `undefined` everywhere else, and meaningfully so.
       *
       * A master that declares none does not get a partial one: PowerPoint
       * substitutes its whole built-in set, measured in 3.1. So the difference
       * between `undefined` and a `p:txStyles` whose buckets say nothing is the
       * difference between a 28-point body placeholder and an 18-point one.
       */
      readonly txStyles: TextStyles | undefined;
      /** `p:clrMapOvr`, on a layout or a slide. */
      readonly clrMapOvr: ColorMapOverride | undefined;
      /** `@showMasterSp`, defaulting to true. Slides and layouts. */
      readonly showMasterShapes: boolean;
      /** The layout of a slide, the master of a layout, `null` for a master and for
       *  a sheet whose binding is missing - which PowerPoint repairs rather than
       *  refuses, so it has to be representable. */
      readonly parent: Sheet | null;
      /** The theme, on a master. Every other sheet reaches it through `parent`. */
      readonly theme: Theme | null;
      readonly node: XElement;
    }
  • OrigintypeWhere a resolved value came from: each member is a level the text cascade reads (ADR 0027, 0064).
    type Origin =
    /** The run's own `a:rPr`. */
    'run' |
    /** The paragraph's `a:pPr`, or its `a:defRPr`. */
    'paragraph' |
    /** The shape itself: its `p:spPr`, or its own `a:lstStyle`. */
    'shape' |
    /** A table cell's own `a:txBody/a:lstStyle`. */
    'cell' |
    /** What a table's style, or PowerPoint's default grid, gives a cell's text. */
    'tableStyle' | 'layoutPh' | 'masterPh' |
    /** The master's `p:txStyles`: the bucket a shape's chain selects, `p:otherStyle` for a cell. */
    'txStyles' |
    /** `p:defaultTextStyle`, which only a shape with no bucket reaches. */
    'defaultTextStyle' |
    /** PowerPoint's own text styles, substituted for a master that declares none. */
    'builtin' | 'theme' | 'schemaDefault';
  • ResolvedtypeA value, where it came from, and whether the thing that owns it said so.
    interface Resolved<T> {
      readonly value: T;
      readonly origin: Origin;
      readonly explicit: boolean;
      /** The sheet the value was found on, when one was involved. */
      readonly sheet: Sheet | null;
      /** The shape the value was found on, when one was involved. */
      readonly shape: Shape | null;
    }

src/parse/paint.ts

  • parseColorElementfunctionOne of the six EG_ColorChoice members.
    function parseColorElement(element: XElement): Color;
  • parseColorChildfunctionThe first colour child of a wrapper such as a:solidFill or a:fillRef.
    function parseColorChild(parent: XElement | undefined): Color | null;
  • parseFillElementfunctionOne member of EG_FillProperties.
    function parseFillElement(element: XElement, partName: string): Fill;
  • parseFillfunctionThe fill a container declares, or undefined when it declares none.
    function parseFill(parent: XElement, partName: string): Fill | undefined;
  • parseLineElementfunctiona:ln, lazily: every field is null when the attribute was absent.
    function parseLineElement(element: XElement, partName: string): Line;
  • parseLinefunction
    function parseLine(parent: XElement, partName: string): Line | undefined;
  • parseEffectsfunctiona:effectLst, in the order the file wrote it.
    function parseEffects(parent: XElement): readonly Effect[] | undefined;

src/parse/sheet.ts

  • parseClrMapfunctionp:clrMap or a:overrideClrMapping: all twelve attributes, every time.
    function parseClrMap(element: XElement, partName: string): ClrMap;
  • parseThemefunction
    function parseTheme(root: XElement, partName: string): Theme;
  • parseSheetfunctionOne part into one sheet. The parent and the theme are filled in by document.ts, which is the only thing that can follow a relationship.
    function parseSheet(root: XElement, partName: string): Omit<Sheet, 'parent' | 'theme'>;

src/resolve/placeholder.ts

  • DEFAULT_PLACEHOLDER_TYPEconstThe type of a p:ph that has none.
    const DEFAULT_PLACEHOLDER_TYPE: PlaceholderType;
  • DEFAULT_PLACEHOLDER_IDXconstThe @idx of a p:ph that has none.
    const DEFAULT_PLACEHOLDER_IDX = 0;
  • normalizePlaceholderfunctionSupply the two defaults, so a comparison has something to compare.
    function normalizePlaceholder(ph: Placeholder): NormalPlaceholder;
  • masterPlaceholderTypefunctionThe type a placeholder presents when it asks a master for its parent.
    function masterPlaceholderType(type: PlaceholderType): PlaceholderType;
  • placeholdersfunctionEvery placeholder in a sheet's top-level shape tree, in document order.
    function placeholders(sheet: Sheet): readonly Shape[];
  • matchInLayoutfunctionSlide to layout: the first placeholder whose @idx agrees.
    function matchInLayout(ph: Placeholder, layout: Sheet): Shape | null;
  • matchInMasterfunctionLayout to master: the first placeholder of the folded type.
    function matchInMaster(ph: Placeholder, master: Sheet): Shape | null;
  • inheritanceChainfunctionThe chain a shape inherits along, nearest first.
    function inheritanceChain(shape: Shape, sheet: Sheet): readonly ChainLink[];
  • ORPHAN_RECTconstA placeholder that reached no parent and states no geometry of its own.
    const ORPHAN_RECT: {
      readonly x: 0;
      readonly y: 0;
      readonly cx: 0;
      readonly cy: 0;
    };

src/resolve/resolve.ts

  • resolvefunctionThe first level of the chain that declared something.
    function resolve<T>(shape: Shape, sheet: Sheet, pick: (shape: Shape) => T | undefined): Resolved<T> | undefined;
  • resolveXfrmfunctionThe rectangle a shape occupies, and which sheet stated it.
    function resolveXfrm(shape: Shape, sheet: Sheet): Resolved<Xfrm> | undefined;
  • sheetChainfunctionEvery sheet from this one up to its master, nearest first.
    function sheetChain(sheet: Sheet): readonly Sheet[];
  • masterOffunctionThe master at the top of a sheet's chain, or null if the chain is broken.
    function masterOf(sheet: Sheet): Sheet | null;
  • themeOffunctionThe theme a sheet resolves against.
    function themeOf(sheet: Sheet): Theme | null;
  • schemeOffunction
    function schemeOf(sheet: Sheet): ClrScheme | undefined;
  • colorMapOffunctionThe colour map in force on a sheet.
    function colorMapOf(sheet: Sheet): ClrMap | undefined;
  • colorContextOffunctionEverything resolveColor needs, for a colour written on this sheet.
    function colorContextOf(sheet: Sheet, phClr?: Rgba): ColorContext;

src/style.ts

  • STYLE_MATRIX_OFFSETconstThe offset that separates the two style lists.
    const STYLE_MATRIX_OFFSET = 1000;
  • StyleMatrixTargettypeWhich of the two lists an index reaches, and where in it.
    type StyleMatrixTarget = {
      readonly list: 'none';
    } | {
      readonly list: 'main';
      readonly at: number;
    } | {
      readonly list: 'background';
      readonly at: number;
    };
  • styleMatrixTargetfunctionWhere an index points, before anything is fetched.
    function styleMatrixTarget(idx: number): StyleMatrixTarget;
  • styleMatrixFillfunctionThe fill a fillRef/bgRef index names, or null for none.
    function styleMatrixFill(ref: StyleRef, theme: Theme): Fill | null;
  • styleMatrixLinefunctionThe line an lnRef index names, or null for none.
    function styleMatrixLine(ref: StyleRef, theme: Theme): Line | null;
  • styleMatrixEffectsfunctionThe effects an effectRef index names. Empty for none.
    function styleMatrixEffects(ref: StyleRef, theme: Theme): readonly Effect[];
  • phClrOffunctionThe colour a style reference invokes its entry with.
    function phClrOf(ref: StyleRef, sheet: Sheet): Rgba | null;
  • ResolvedAppearancetypeWhat a shape paints, and where each half of the answer came from.
    interface ResolvedAppearance {
      /** `null` means nothing is painted: no fill was declared and no style names one. */
      readonly fill: Fill | null;
      readonly fillOrigin: Origin | null;
      /** The colour `phClr` resolves to inside `fill`, when it came from the theme. */
      readonly fillPhClr: Rgba | null;
      readonly line: Line | null;
      readonly lineOrigin: Origin | null;
      readonly linePhClr: Rgba | null;
      readonly effects: readonly Effect[] | null;
    }
  • resolveAppearancefunctionWhat a shape paints, following both routes and in the right order.
    function resolveAppearance(shape: Shape, sheet: Sheet): ResolvedAppearance;
  • resolveSolidFillfunctionA shape's fill as a single colour, when it is one.
    function resolveSolidFill(shape: Shape, sheet: Sheet): Rgba | null;
  • resolveOnSheetfunctionResolve any colour written on a sheet, with an optional phClr in scope.
    function resolveOnSheet(color: Color, sheet: Sheet, phClr?: Rgba): Rgba;

src/resolve/background.ts

  • ResolvedBackgroundtypeA background, with the sheet that declared it and how it was expressed.
    interface ResolvedBackground {
      readonly fill: Fill;
      /** The sheet whose `p:bg` this is. */
      readonly sheet: Sheet;
      /** True when the sheet asked for it is the one that declared it. */
      readonly explicit: boolean;
      /** `bgPr` or `bgRef`, because they round-trip differently. */
      readonly form: 'bgPr' | 'bgRef';
      /** The colour `phClr` takes inside `fill`, for a `bgRef`. */
      readonly phClr: Rgba | null;
    }
  • backgroundSheetfunctionWhich sheet's p:bg applies, without unpacking it.
    function backgroundSheet(sheet: Sheet): {
      sheet: Sheet;
      background: Background;
    } | null;
  • resolveBackgroundfunctionThe background of a slide, layout or master.
    function resolveBackground(sheet: Sheet): ResolvedBackground | null;
  • resolveBackgroundColorfunctionThe background as one colour, when it is a solid. null otherwise.
    function resolveBackgroundColor(sheet: Sheet): Rgba | null;

src/document.ts

  • DocumentProblemtypeOne thing wrong with the package that did not stop the load.
    interface DocumentProblem {
      readonly code: 'MODEL_NO_PARENT' | 'MODEL_NO_THEME' | 'MODEL_PART_MISSING' | 'MODEL_PART_KIND';
      readonly partName: string;
      readonly message: string;
    }
  • DocumenttypeA loaded presentation: its slides, in p:sldIdLst order, each with its chain.
    interface Document {
      /** The presentation part, for the parts of it 2.9 does not model. */
      readonly presentation: XElement;
      readonly presentationPartName: string;
      /** In `p:sldIdLst` order, which *is* the deck's order. */
      readonly slides: readonly Sheet[];
      /** In `p:sldMasterIdLst` order. */
      readonly masters: readonly Sheet[];
      /** Every layout reachable from a master, in the order its master lists it. */
      readonly layouts: readonly Sheet[];
      readonly themes: readonly Theme[];
      readonly problems: readonly DocumentProblem[];
      /**
       * `p:defaultTextStyle`, the terminus of the text cascade for every shape that
       * reaches no `p:txStyles` bucket - which is every shape that is not a
       * placeholder, and the `dt`, `ftr`, `sldNum` and `hdr` placeholders besides.
       *
       * It lives on the presentation part, so it belongs to the package rather than
       * to any sheet, and `undefined` means the package declared none.
       */
      readonly defaultTextStyle: ListStyle | undefined;
      /** Slide size in EMU, from `p:sldSz`. */
      readonly slideSize: {
        readonly cx: number;
        readonly cy: number;
      };
      sheet(partName: string): Sheet | undefined;
    }
  • loadDocumentfunction
    function loadDocument(store: PartStore): Document;

src/parse/text.ts

  • parseRunPropsfunctiona:rPr, a:defRPr or a:endParaRPr - one type under three names.
    function parseRunProps(element: XElement, partName: string): RunProps;
  • parseParaPropsfunctiona:pPr, a:defPPr or any a:lvlNpPr - one type under eleven names.
    function parseParaProps(element: XElement, partName: string): ParaProps;
  • parseListStylefunctiona:lstStyle, or a p:txStyles bucket, which is the same type unwrapped.
    function parseListStyle(element: XElement, partName: string): ListStyle;
  • parseTextStylesfunctionp:txStyles on a master.
    function parseTextStyles(element: XElement, partName: string): TextStyles;
  • parseDefaultTextStylefunctionp:defaultTextStyle on ppt/presentation.xml, which is a CT_TextListStyle.
    function parseDefaultTextStyle(presentation: XElement, partName: string): ListStyle | undefined;
  • parseTextBodyfunctionA p:txBody or an a:txBody.
    function parseTextBody(element: XElement, partName: string): TextBody;
  • parseTextBodyChildfunctionThe p:txBody of a shape, when it has one.
    function parseTextBodyChild(parent: XElement, partName: string): TextBody | undefined;

src/builtin/text-styles.ts

  • BuiltinLeveltypeOne level of a built-in list style.
    interface BuiltinLevel {
      /** Hundredths of a point, as `a:defRPr/@sz` holds it. */
      readonly sz: number;
      /** EMU, as `a:lvlNpPr/@marL` holds it. */
      readonly marL: number;
      /** EMU, as `a:lvlNpPr/@indent` holds it. Negative is a hanging indent. */
      readonly indent: number;
      readonly bullet: boolean;
      /**
       * The theme reference this level names, or `null` where it names none.
       *
       * A reference and not a face, because the built-in styles are the same
       * whatever theme a package carries: `+mj-lt` measured as the theme's major
       * face and `+mn-lt` as its minor.
       */
      readonly typeface: string | null;
    }
  • BUILTIN_TEXT_STYLESconstThe three buckets, nine levels each, level 1 first.
    const BUILTIN_TEXT_STYLES: {
      readonly title: readonly BuiltinLevel[];
      readonly body: readonly BuiltinLevel[];
      readonly other: readonly BuiltinLevel[];
    };
  • TEXT_FLOORconstWhat is left when every source is silent and the master *does* declare p:txStyles.
    const TEXT_FLOOR: BuiltinLevel;

src/builtin/table-styles.ts

  • BuiltinTableStyletypePowerPoint's 74 built-in table styles, each a:tblStyle byte for byte as PowerPoint writes it. GENERATED by tools/ground-truth/model/tables/styles/write-tables.ts from corpus/ground-truth/table-styles.json. Do not edit: table.test.ts re-derives it.
    interface BuiltinTableStyle {
      readonly id: string;
      readonly name: string;
      /** The `a:tblStyle` PowerPoint writes into `ppt/tableStyles.xml` for this style. */
      readonly xml: string;
    }
  • BUILTIN_TABLE_STYLESconstIn the order of PowerPoint's Table Styles gallery.
    const BUILTIN_TABLE_STYLES: readonly BuiltinTableStyle[];

src/resolve/text.ts

  • bucketOffunctionWhich p:txStyles bucket a placeholder type reads, or null for none.
    function bucketOf(type: string): 'title' | 'body' | null;
  • TextContexttypeEverything the cascade needs that is not on the shape. defaultTextStyle is the package's, from ppt/presentation.xml; undefined is a package that declares none, which PowerPoint tells apart.
    interface TextContext {
      readonly sheet: Sheet;
      readonly shape: Shape;
      readonly defaultTextStyle: ListStyle | undefined;
      /** Set for the text of a table cell, whose walk is its own (C9, ADR 0064). */
      readonly cell?: TableCellText;
    }
  • TableCellTexttypeA table cell's two levels of its own: its a:lstStyle, and what the table's style gives it.
    interface TableCellText {
      readonly lstStyle: ListStyle | undefined;
      /** `tableTextLayer`'s answer for the cell. */
      readonly layer: RunProps;
    }
  • textLevelsfunctionThe list styles a shape or a table cell reads, nearest first, ending at whichever terminus it reaches. Exported so a caller that shows where a value could come from walks the same list.
    function textLevels(context: TextContext): readonly Level[];
  • floorOffunctionThe values left when every level has been asked and none of them said (ADR 0027). A master with p:txStyles leaves TEXT_FLOOR; one without substitutes PowerPoint's built-ins.
    function floorOf(context: TextContext, level: number): BuiltinLevel;
  • resolveParagraphfunctionA paragraph property, from the paragraph's own a:pPr or up the walk.
    function resolveParagraph<T>(context: TextContext, paragraph: Paragraph, pick: (props: ParaProps) => T | undefined): Resolved<T> | undefined;
  • resolveRunfunctionA run property, from the run's own a:rPr and then every a:defRPr above it.
    function resolveRun<T>(context: TextContext, paragraph: Paragraph, run: TextContent | undefined, pick: (props: RunProps) => T | undefined): Resolved<T> | undefined;
  • resolveSizefunctionThe font size of a run, in hundredths of a point, always.
    function resolveSize(context: TextContext, paragraph: Paragraph, run: TextContent | undefined): Resolved<number>;
  • resolveLatinTypefacefunctionThe Latin typeface of a run, with any theme reference followed.
    function resolveLatinTypeface(context: TextContext, paragraph: Paragraph, run: TextContent | undefined): Resolved<string>;
  • resolveMarginLeftfunction@marL in EMU. Measured to be 0 when nothing declares it, not 347663.
    function resolveMarginLeft(context: TextContext, paragraph: Paragraph): Resolved<number>;
  • resolveIndentfunction@indent in EMU. Measured to be 0 when nothing declares it, not -342900.
    function resolveIndent(context: TextContext, paragraph: Paragraph): Resolved<number>;
  • resolveBulletKindfunctionThe bullet, merged the way T5 measured it: five slots, each on its own.
    function resolveBulletKind(context: TextContext, paragraph: Paragraph): Resolved<BulletKind> | undefined;
  • resolveBulletCharfunctiona:buChar/@char, as written. The symbol mapping belongs to the renderer.
    function resolveBulletChar(context: TextContext, paragraph: Paragraph): Resolved<string> | undefined;
  • resolveBulletAutoNumfunctiona:buAutoNum, type and start value together, since one is meaningless alone.
    function resolveBulletAutoNum(context: TextContext, paragraph: Paragraph): Resolved<BulletAutoNum> | undefined;
  • resolveBulletBlipfunctiona:buBlip/a:blip/@r:embed, which the caller resolves against the part's rels.
    function resolveBulletBlip(context: TextContext, paragraph: Paragraph): Resolved<string> | undefined;
  • resolveBulletFontfunctiona:buFont or a:buFontTx.
    function resolveBulletFont(context: TextContext, paragraph: Paragraph): Resolved<BulletFont> | undefined;
  • resolveBulletSizefunctiona:buSzPct, a:buSzPts or a:buSzTx; a percentage is of the first run's size.
    function resolveBulletSize(context: TextContext, paragraph: Paragraph): Resolved<BulletSize> | undefined;
  • resolveBulletColorfunctiona:buClr or a:buClrTx. Unlike the font, this one *does* reach an autonumber.
    function resolveBulletColor(context: TextContext, paragraph: Paragraph): Resolved<BulletColor> | undefined;

src/resolve/body.ts

  • ResolvedInsetstypeThe four insets in points, per attribute.
    interface ResolvedInsets {
      readonly left: number;
      readonly top: number;
      readonly right: number;
      readonly bottom: number;
    }
  • resolveBodyfunctionOne property of the text frame, from the shape's own a:bodyPr or above it.
    function resolveBody<T>(shape: Shape, sheet: Sheet, pick: (props: BodyProps) => T | undefined): Resolved<T> | undefined;
  • resolveAnchorfunction
    function resolveAnchor(shape: Shape, sheet: Sheet): Resolved<TextAnchor> | undefined;
  • resolveAnchorCtrfunction
    function resolveAnchorCtr(shape: Shape, sheet: Sheet): Resolved<boolean> | undefined;
  • resolveVerticalfunction
    function resolveVertical(shape: Shape, sheet: Sheet): Resolved<VerticalText> | undefined;
  • resolveWrapfunction
    function resolveWrap(shape: Shape, sheet: Sheet): Resolved<TextWrap> | undefined;
  • resolveColumnsfunction
    function resolveColumns(shape: Shape, sheet: Sheet): Resolved<number> | undefined;
  • resolveInsetsfunctionThe four insets, in points, each falling back on its own.
    function resolveInsets(shape: Shape, sheet: Sheet): ResolvedInsets;

src/parse/body.ts

  • parseBodyPropsfunctionParse an a:bodyPr. Lengths stay in EMU and angles in 60000ths of a degree.
    function parseBodyProps(element: XElement, partName: string): BodyProps;
  • parseBodyPropsChildfunctionThe a:bodyPr of a p:txBody, when it has one.
    function parseBodyPropsChild(parent: XElement, partName: string): BodyProps | undefined;

src/parse/table.ts

  • parseTablefunctionAn a:tbl.
    function parseTable(element: XElement, part: string): Table;
  • parseTableChildfunctionThe table of a p:graphicFrame, when its a:graphicData carries one.
    function parseTableChild(frame: XElement, part: string): Table | undefined;
  • parseTableStylefunctionAn a:tblStyle or an inline a:tableStyle: CT_TableStyle.
    function parseTableStyle(element: XElement, part: string): TableStyle;

src/resolve/table.ts

  • builtinTableStylefunctionOne of PowerPoint's 74 built-ins by GUID, in any case, parsed afresh; undefined for any other.
    function builtinTableStyle(id: string): TableStyle | undefined;
  • tableStyleOffunctionThe built-in style a table is drawn with, or null for PowerPoint's default: a 1-pt black grid and no fill, whatever the theme and whatever the package defines.
    function tableStyleOf(table: Table): TableStyle | null;
  • TABLE_PART_ORDERconstThe order the parts compose in, lowest first: C9 on every drawable table (ADR 0064).
    const TABLE_PART_ORDER: readonly ["wholeTbl", "band1H", "band2H", "band1V", "band2V", "lastCol", "firstCol", "lastRow", "seCell", "swCell", "firstRow", "neCell", "nwCell"];
  • tablePartsAtfunctionThe parts reaching grid position (row, col), highest first: ECMA-376's reading, which C9 found alone fits (ADR 0064). Bands skip the rows and columns their end flags take, and a corner part needs both of its flags.
    function tablePartsAt(props: TableProps | undefined, rows: number, cols: number, row: number, col: number): readonly TableStylePartName[];
  • tableCellFillfunctionThe fill of the cell at grid position (row, col): its own a:tcPr fill, else the highest part that states one. Parts compose per property (C9); null paints nothing, and one translucent fill is painted alone, never over another part's.
    function tableCellFill(table: Table, style: TableStyle | null, grid: TableGrid, row: number, col: number): TableSourced<Themeable<Fill>> | null;
  • tableBackgroundfunctionWhat paints under the cells, over the grid and never the frame as written: a:tblPr's own fill and effect list, each in place of the style's tblBg one, an empty list included (C9).
    function tableBackground(table: Table, style: TableStyle | null): TableBackgroundLayers;
  • tableCellDiagonalsfunctionThe diagonals of the cell at (row, col) as drawn across its whole span: down from its visual top left, up from its visual bottom left. Only the anchor's own lines draw, mirrored in an rtl table; no built-in states a diagonal (C8) and a covered position's own are never read (C9).
    function tableCellDiagonals(table: Table, grid: TableGrid, row: number, col: number): TableDiagonals;
  • DEFAULT_GRID_LINEconstPowerPoint's default grid: a 1-pt black line on every edge of a table that names no built-in (C8).
    const DEFAULT_GRID_LINE: Line;
  • tableEdgeLinefunctionThe line a grid edge draws: its owner's a:tcPr line, else the highest part of either cell that states it, a part reaching both offering its inside edge (C9). The owner is the cell before (above, left) where its anchor is level with the edge, else the cell after where its anchor is, else the cell before; null inside a merged cell.
    function tableEdgeLine(table: Table, style: TableStyle | null, grid: TableGrid, edge: TableEdge): TableSourced<Themeable<Line>> | null;
  • tableTextLayerfunctionWhat the style gives the text of the cell at (row, col): bold, italic, face and colour, each from the highest part that states it (C9), as run properties for the text cascade. The default grid gives tx1 in the minor face whatever the flags; node is the style's element, or the table's for the grid.
    function tableTextLayer(table: Table, style: TableStyle | null, grid: TableGrid, row: number, col: number): RunProps;
  • themedFillfunctionA style fill with a fillRef followed into the theme, and the colour phClr takes in it.
    function themedFill(fill: Themeable<Fill>, theme: Theme, colors: ColorContext): {
      readonly fill: Fill | null;
      readonly phClr: Rgba | null;
    };
  • themedEffectsfunctionA style effect list with an effectRef followed into the theme, and the colour phClr takes.
    function themedEffects(effects: Themeable<readonly Effect[] | undefined>, theme: Theme, colors: ColorContext): {
      readonly effects: readonly Effect[];
      readonly phClr: Rgba | null;
    };
  • themedLinefunctionA style line with an lnRef followed into the theme, and the colour phClr takes in it.
    function themedLine(line: Themeable<Line>, theme: Theme, colors: ColorContext): {
      readonly line: Line | null;
      readonly phClr: Rgba | null;
    };

src/resolve/typeface.ts

  • ScriptSlottypeThe four slots a CT_TextCharacterProperties can name.
    type ScriptSlot = 'latin' | 'ea' | 'cs' | 'sym';
  • resolveTypefacefunctionThe typeface a slot asks for, with any theme reference followed.
    function resolveTypeface(typeface: string, scheme: FontScheme): string | undefined;
  • resolveTypefaceOffunctionThe same, for a whole CT_TextFont.
    function resolveTypefaceOf(font: Typeface, scheme: FontScheme): string | undefined;
  • requestedTypefacesfunctionEvery distinct typeface a set of runs asks for, theme references followed.
    function requestedTypefaces(fonts: Iterable<Typeface | undefined>, scheme: FontScheme): readonly string[];

Errors

Throws ModelError, whose code is one of:

  • MODEL_PART_MISSING
  • MODEL_PART_KIND
  • MODEL_NO_PRESENTATION
  • MODEL_NO_PARENT
  • MODEL_NO_THEME
  • MODEL_CLRMAP_INCOMPLETE
  • MODEL_CLRMAP_SLOT
  • MODEL_PLACEHOLDER_IDX
  • MODEL_XFRM_NUMBER
  • MODEL_GEOMETRY
  • MODEL_STYLE_IDX
  • MODEL_FONT_COLLECTION
  • MODEL_NO_STYLE_MATRIX
  • MODEL_STYLE_LIST_EMPTY
  • MODEL_SHEET_CYCLE
  • MODEL_FOREIGN_SHEET
  • MODEL_TEXT_ATTR
  • MODEL_TEXT_FIELD
  • MODEL_TEXT_LEVEL
  • MODEL_TEXT_BULLET
  • MODEL_TEXT_TYPEFACE
  • MODEL_TABLE_ATTR
  • MODEL_TABLE_STYLE
  • MODEL_TABLE_POSITION
  • BLIP_NO_EMBED
  • BLIP_DUOTONE
  • BLIP_CLR_CHANGE
  • BLIP_TILE_ALIGN
  • BLIP_TILE_FLIP

Try it live

Reading the deck…

Open the full demo →

Read more

On this page