Skip to content

OLE embedded objects ​

slide.addOleObject() embeds a file in the .pptx and places it on the slide as an OLE object, the kind PowerPoint's Insert > Object > Create from File makes. Double-clicking it in PowerPoint opens the embedded file in the application its progId names.

ts
import TsPptx from 'pptx-ts'

const pptx = new TsPptx()
pptx.addSlide().addOleObject({
  path: 'assets/quarterly-budget.xlsx',
  cover: { path: 'assets/quarterly-budget.png' },
  x: 1,
  y: 1,
  w: 6,
  h: 3,
})
await pptx.writeFile({ fileName: 'budget.pptx' })

data or path is required, and everything else is optional. The payload's bytes are stored in the package, so the deck needs no file beside it. addOleObject returns the slide, so calls chain.

Options at a glance ​

OptionTypeDefaultEffect
datastringnoneThe payload as base64, with or without a data: header
pathstringnoneA file path or URL, read when the deck is written
cover{ path?: string; data?: string }a gray placeholderThe picture drawn for the object
extnstringfrom data, path or progIdThe payload kind
progIdstringthe kind's defaultThe OLE server PowerPoint launches
showAsIconbooleanfalseSets PowerPoint's "Display as icon" flag
imgW, imgHnumberthe frame's w and h, in EMUThe object's picture size, in EMU
x, yCoord0Top-left corner
w, hCoord4, 3Size
objectNamestringObject 1, Object 2, ...Selection Pane name
altTextstringnoneAlt text
objectLockObjectLockProps{ noChangeAspect: true }Lock flags on the object's frame

Supply a cover picture ​

The library never opens the payload, so it cannot draw a picture of it. Pass one as cover, by path or as base64 data with a header, the way addImage takes an image:

ts
slide.addOleObject({ path: 'budget.xlsx', cover: { data: `image/png;base64,${pngBase64}` } })
  • With no cover, a 32 by 32 gray PNG is embedded and nothing is reported.
  • A cover.data with no base64 header warns preview-image/missing-base64-header, and the gray PNG is embedded instead.
  • The cover goes into the object's mc:Fallback branch only. A reader that does not take the mc:Choice branch draws the cover in place of the object. Supply a preview picture on the 3D models page explains the two branches.
  • A cover used by two objects is stored once, like any other image.

Choose the payload kind ​

The payload kind sets the part's extension, its content type, its relationship type and the default progId. The library takes the kind from the first of these that names one of the six Office kinds in the table:

  1. extn, with or without a leading dot, in any case. An extn outside the table makes the payload a generic blob, and the later sources are not read.
  2. The MIME type of a data value that starts with data:.
  3. The extension of path, ignoring any query string or fragment.
  4. progId, when it is one of the six defaults in the table.

When none of them names an Office kind, the payload is a generic blob.

KindprogId defaultMIME type read from a data: URI
xlsxExcel.Sheet.12application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsmExcel.SheetMacroEnabled.12application/vnd.ms-excel.sheet.macroEnabled.12
docxWord.Document.12application/vnd.openxmlformats-officedocument.wordprocessingml.document
docmWord.DocumentMacroEnabled.12application/vnd.ms-word.document.macroEnabled.12
pptxPowerPoint.Show.12application/vnd.openxmlformats-officedocument.presentationml.presentation
pptmPowerPoint.ShowMacroEnabled.12application/vnd.ms-powerpoint.presentation.macroEnabled.12
generic blobPackagenone
ts
// Bare base64 has no MIME type and no file name, so progId decides the kind.
slide.addOleObject({ data: workbookBase64, progId: 'Excel.Sheet.12' })

// A path with no extension needs extn.
slide.addOleObject({ path: 'exports/budget', extn: 'xlsx' })
  • An Office kind keeps its extension, as in ppt/embeddings/oleObject-1-1.xlsx, with a content type for that extension.
  • A generic blob is stored as .bin with the content type application/vnd.openxmlformats-officedocument.oleObject, so an unknown extension never reaches [Content_Types].xml.
  • A MIME header with no data: in front, such as application/vnd.ms-excel.sheet.macroEnabled.12;base64,, is not read for the kind. The bytes still load.
  • An explicit progId is written as given. It picks the kind only when no earlier source did.
  • Every object gets its own payload part, even when two objects carry the same bytes, so editing one object never changes the other.

Size the object ​

ts
slide.addOleObject({
  path: 'budget.xlsx',
  cover: { path: 'excel-icon.png' },
  showAsIcon: true,
  x: 1,
  y: 1,
  w: 1,
  h: 1,
})
  • w and h default to 4 by 3 inches, and x and y to 0. The library does not open the payload, so it has no size to measure. Set all four.
  • imgW and imgH are written to p:oleObj as the size of the object's picture, in EMU. Each defaults to the frame's width or height in EMU. A fraction is rounded.
  • showAsIcon: true does not change what is drawn. The cover is still the picture, so give an icon picture to match.
  • The frame is locked against aspect-ratio changes. Flags in objectLock are added to that lock, and noChangeAspect: false removes it.

Invalid input ​

Throws happen inside the addOleObject() call, as InvalidOptionError. A file that fails to load is reported when the deck is written.

ConditionWarns or throwsCode
neither data nor path is setthrowsole/missing-source
imgW or imgH is not a number from 0 to 2147483647throwsole/invalid-image-size
x, y, w or h is not a finite numberthrowscoord/non-finite
w or h is 0warns, and the zero is keptframe/zero-extent
cover.data has no base64 headerwarns, and the gray placeholder is embeddedpreview-image/missing-base64-header
path or cover.path fails to load (when written)throws MediaErrormedia/load-failed
the same, with onMediaError: 'placeholder'still throws MediaError, because a placeholder picture cannot stand in for the payloadmedia/load-failed
objectName is only whitespace, longer than 255 characters, or holds control characterswarnsobject-name/empty, object-name/too-long, object-name/control-characters

Errors and warnings covers the error classes and how to route warnings.

Limits ​

  • Linked objects, which point at a file outside the package, cannot be authored.
  • The library never opens or checks the payload. It draws no cover, measures no size, and does not notice bytes that do not match the kind.
  • A generic blob's bytes are written unchanged. The library does not package a file into an OLE compound file.
  • Only a data: URI's MIME type is read, and only for the six Office kinds.
  • Two objects never share a payload part.
  • pptx-ts/read has no typed accessor for an OLE object.

Reading it back ​

ts
import { readFile } from 'node:fs/promises'
import { Presentation } from 'pptx-ts/read'

const deck = await Presentation.load(await readFile('budget.pptx'))
for (const slide of deck.slides) {
  for (const shape of slide.shapes) {
    if (shape.shapeType === 'graphicFrame') console.log(shape.name)
  }
}
  • Before export, slide.objects lists the object with type: "oleObject" and canGroup: false.
  • pptx-ts/read loads the object as a graphicFrame shape whose name is its objectName. There is no accessor for the payload, the progId or the cover. See Kept but not decoded.
  • Saving a loaded deck keeps the payload and cover parts, and importSlide copies both into the target deck.
  • Inspect a package reports the object as a graphicFrame element with graphicKind: 'other'.

See also ​