@imgly/pptx-importer
v2.0.0-rc.1
Published
Import PowerPoint (PPTX) presentations into IMG.LY's Creative Engine SDK. Platform-agnostic TypeScript library for converting PPTX slides to CE.SDK scenes.
Downloads
27
Readme
PPTX Importer for CE.SDK
A TypeScript library for importing PowerPoint (PPTX) presentations into IMG.LY's Creative Engine SDK. Converts PPTX slides into CE.SDK scenes with full support for text, shapes, images, and formatting.
Features
✨ Comprehensive PPTX Support
- Text Elements: Full text formatting including font families, sizes, colors, bold, italic, character spacing, and line height
- Shapes: Rectangles, ellipses, and custom vector shapes with fills and strokes
- Gradient Fills: Linear and radial gradients on shapes (70% of presentations)
- Shadow Effects: Outer drop shadows with blur, offset, and transparency (60% of presentations)
- Gradient Backgrounds: Linear and radial gradients on slide backgrounds
- Images: Embedded images with proper positioning and dimensions
- Groups: Grouped elements with preserved hierarchy
- Layout: Accurate positioning, sizing, and rotation
- Z-Order: Maintains element stacking order from PowerPoint
- Theme Colors: Resolves PowerPoint theme color references
🌐 Platform-Agnostic
Works in both browser and Node.js environments:
- No file system dependencies
- Pure ArrayBuffer/Uint8Array handling
- Platform-neutral base64 encoding
- ESM module format
🎯 Production-Ready
- TypeScript-first with full type definitions
- Comprehensive test suite with 80+ passing tests
- Visual regression testing with golden screenshots
- Font resolution via Google Fonts integration
- Error handling with detailed warnings for unsupported features
Installation
npm install @imgly/pptx-importerPeer Dependencies
You'll need CE.SDK in your project:
# For browser
npm install @cesdk/engine
# For Node.js
npm install @cesdk/nodeQuick Start
Browser
import CreativeEngine from '@cesdk/engine';
import { PPTXParser } from '@imgly/pptx-importer';
// Initialize CE.SDK engine
const config = {
license: 'your-license-key',
userId: 'your-user-id',
};
const engine = await CreativeEngine.init(config);
// Load PPTX file
const response = await fetch('presentation.pptx');
const arrayBuffer = await response.arrayBuffer();
// Parse PPTX and create CE.SDK scene (automatically parses all slides)
const parser = await PPTXParser.fromFile(engine, arrayBuffer);
await parser.parse();
// Get created pages
const pages = engine.block.findByType('//ly.img.ubq/page');
console.log(`Imported ${pages.length} slides`);
// Check for any warnings
const warnings = parser.getWarnings();
if (warnings.length > 0) {
console.warn('Unsupported features:', warnings);
}
// Export first slide
const blob = await engine.block.export(pages[0], 'image/png');Node.js
import CreativeEngine from '@cesdk/node';
import { PPTXParser } from '@imgly/pptx-importer';
import { readFileSync } from 'fs';
// Initialize CE.SDK engine
const engine = await CreativeEngine.init({
license: process.env.CESDK_LICENSE,
});
// Load PPTX file
const fileBuffer = readFileSync('presentation.pptx');
const arrayBuffer = fileBuffer.buffer.slice(
fileBuffer.byteOffset,
fileBuffer.byteOffset + fileBuffer.byteLength
);
// Parse PPTX (automatically parses all slides and attaches to scene)
const parser = await PPTXParser.fromFile(engine, arrayBuffer);
await parser.parse();
// Get created pages
const pages = engine.block.findByType('//ly.img.ubq/page');
// Export first slide
const blob = await engine.block.export(pages[0], 'image/png');API Reference
PPTXParser
Static Methods
PPTXParser.fromFile(engine, fileBuffer, options?)
Creates a parser instance from a PPTX file.
Parameters:
engine: CreativeEngine- CE.SDK engine instancefileBuffer: ArrayBuffer- PPTX file as ArrayBufferoptions?: Partial<PPTXParserOptions>- Optional configuration
Returns: Promise<PPTXParser>
Example:
const parser = await PPTXParser.fromFile(engine, arrayBuffer, {
tolerancePercent: 5,
logWarnings: true,
strictMode: false,
});Instance Methods
parser.parse()
Parses all slides in the PPTX file and automatically attaches them to the scene.
Parameters: None
Returns: Promise<void>
Example:
// Parse all slides
await parser.parse();
// Get created pages
const pages = engine.block.findByType('//ly.img.ubq/page');
console.log(`Imported ${pages.length} slides`);
// Access individual pages
pages.forEach((pageId, index) => {
console.log(`Slide ${index + 1}: block ID ${pageId}`);
});Note: This API matches the PSD importer pattern for consistency across IMG.LY importers. All slides are parsed and attached to the scene automatically. Use
engine.block.findByType()to retrieve page block IDs.
parser.getSlideCount()
Returns the total number of slides in the PPTX file.
Returns: number
parser.getWarnings()
Returns warnings about unsupported features encountered during parsing.
Returns: UnsupportedFeatureWarning[]
Example:
const warnings = parser.getWarnings();
warnings.forEach(w => {
console.log(`Warning: ${w.feature} in ${w.pptxProperty}`);
});parser.clearWarnings()
Clears all logged warnings.
PPTXParserOptions
Configuration options for the parser.
interface PPTXParserOptions {
/**
* Tolerance percentage for numeric property validation in tests
* @default 5
*/
tolerancePercent?: number;
/**
* Enable warning logs for unsupported PPTX features
* @default true
*/
logWarnings?: boolean;
/**
* Strict mode - throw errors for unsupported features
* @default false
*/
strictMode?: boolean;
}Supported Features
✅ Fully Supported
Text Blocks
- Font family, size, color
- Bold, italic formatting
- Character spacing
- Line height
- Multiple text runs with different formatting
- Vertical alignment
Shapes
- Rectangles (with corner radius)
- Ellipses/circles
- Custom vector shapes (via SVG path conversion)
- Fill colors (solid, theme colors)
- Stroke colors and widths
Images
- PNG, JPEG, GIF, BMP, WebP
- Embedded images
- Proper sizing and positioning
Layout
- Absolute positioning
- Rotation
- Z-order preservation
- Groups and nested elements
⚠️ Partially Supported
Colors
- ✅ RGB colors
- ✅ Theme colors (with fallback)
- ⚠️ Gradients (not yet implemented)
- ⚠️ Transparency (basic support)
Text
- ✅ Basic formatting
- ⚠️ Bullets and numbering (basic)
- ⚠️ Tables (not yet implemented)
❌ Not Supported
- Animations and transitions
- Slide masters and layouts
- Charts and SmartArt
- Audio and video
- Comments and notes
- Slide backgrounds (partially)
Unit System
PowerPoint uses EMUs (English Metric Units) for measurements:
- 1 inch = 914,400 EMUs
- 1 cm = 360,000 EMUs
CE.SDK scenes use Pixels at 300 DPI by default. The importer automatically converts:
// EMUs to CE.SDK pixels
pixels = (emus / 914400) * 300
// Simplified: pixels = emus / 3048Font sizes use points (72 points = 1 inch), which are DPI-independent and don't require conversion.
Platform Compatibility
Browser Requirements
- Modern browsers with ES2022 support
- Chrome 94+, Firefox 93+, Safari 15+, Edge 94+
Node.js Requirements
- Node.js 18+
- Works with Bun, Deno (with Node.js compatibility)
Build Targets
The package is built with platform: 'neutral' to work in any JavaScript environment.
Development
Setup
# Clone repository
git clone https://github.com/your-org/pptx-importer.git
cd pptx-importer
# Install dependencies
npm install
# Set up environment variables
cp .env.example .env
# Edit .env and add your CESDK_LICENSEBuilding
# Build the package
npm run build
# Type check
npm run typecheck
# Clean build artifacts
npm run cleanTesting
The project uses a dual testing strategy:
Generated Tests (Unit/Integration)
Fast, deterministic tests using PptxGenJS to create PPTX files programmatically:
# Run all tests
npm test
# Run generated tests only
npm run test:generated
# Watch mode
npm run test:watchGolden Screenshot Tests (Visual Regression)
Compare rendered output against reference screenshots using real PPTX files:
# Run golden tests
npm run test:golden
# Update golden screenshots (after intentional changes)
npm run test:update-golden
# Export scene archives for debugging
npm run test:golden:export-scenesProject Structure
pptx-importer/
├── src/
│ ├── entries/
│ │ └── index.ts # Public API exports
│ └── lib/
│ └── pptx-parser/
│ ├── index.ts # Main PPTXParser class
│ ├── interfaces.ts # TypeScript interfaces
│ ├── converters/ # Unit & color conversion
│ ├── handlers/ # Element handlers (text, shape, image)
│ ├── parsers/ # PPTX XML parsers
│ └── utils/ # Utilities & helpers
├── test/
│ ├── generated/ # Generated PPTX tests
│ ├── golden/ # Golden screenshot tests
│ └── fixtures/ # Test PPTX files
├── dist/ # Build output (npm package)
└── build.mjs # Build scriptInspection Tools
Debug PPTX files and CE.SDK scenes:
# Inspect raw PPTX structure
npx tsx tools/inspect-pptx.ts ./path/to/file.pptx
# Inspect CE.SDK blocks after parsing
npx tsx tools/inspect-cesdk.ts ./path/to/file.pptx
# Inspect CE.SDK unit system
npx tsx tools/inspect-cesdk-units.tsArchitecture
The importer follows a modular architecture:
- PPTX Loader (
utils/pptx-loader.ts) - Unzips PPTX and parses XML using JSZip + xml2js - Parsers - Extract data from XML structures
SlideParser- Slide dimensions and element listsThemeParser- Theme color schemesElementParser- Individual element properties
- Handlers - Create CE.SDK blocks
TextHandler- Text blocks with formattingShapeHandler- Graphic blocks with fills/strokesImageHandler- Image blocks with data URLsGroupHandler- Grouped elementsPageHandler- Page blocks (slides)
- Converters - Transform data formats
UnitConverter- EMU to pixelsColorConverter- PPTX colors to RGBAVectorPathConverter- Custom geometry to SVG pathsFontConverter- Font name resolution
Contributing
Contributions are welcome! Please follow the development principles:
Core Principles
- TypeScript-First - All code must be strictly typed
- Test-First Development - Write tests before implementation
- Platform-Agnostic - No Node.js-specific APIs in library code
- Dual Testing - Generated tests + golden screenshot tests
Development Workflow
- Fork the repository
- Create a feature branch
- Write failing tests
- Implement the feature
- Ensure all tests pass
- Add a changeset (see below)
- Submit a pull request
Versioning with Changesets
This project uses Changesets to manage versioning and changelogs.
When to Add a Changeset
Add a changeset when your PR includes changes that should be released to users:
✅ Add a changeset for:
- New features
- Bug fixes
- Performance improvements
- Breaking changes
- Documentation improvements that affect users
❌ Skip changeset (add
no-changesetlabel to PR) for:- Internal refactoring with no user impact
- Test updates
- CI/CD changes
- Development tooling updates
How to Add a Changeset
After making your changes, run:
npm run changesetThis will prompt you for:
Bump type - Choose the appropriate version bump:
major- Breaking changes (1.0.0 → 2.0.0)minor- New features (1.0.0 → 1.1.0)patch- Bug fixes (1.0.0 → 1.0.1)
Summary - Write a clear description of your changes:
- Use present tense ("Add gradient support" not "Added gradient support")
- Be specific and user-focused
- Mention breaking changes if applicable
This creates a changeset file in .changeset/ that you should commit with your changes:
git add .changeset/*.md
git commit -m "feat: add gradient fill support"Example Changeset
When you run npm run changeset, it creates a file like .changeset/cool-pandas-smile.md:
---
"@imgly/pptx-importer": minor
---
Add support for gradient fills on shapes and backgrounds. Linear and radial gradients are now fully supported.Release Process
The release process is automated via GitHub Actions:
- PRs are merged to main with changesets
- GitHub Action creates a "Version Packages" PR automatically
- Maintainer reviews and merges the Version PR
- Automatic release to npm happens on merge
Manual Versioning (for maintainers)
If needed, you can manually version and release:
# Apply changesets and update versions
npm run version
# Commit the changes
git add .
git commit -m "chore: version packages"
git push
# Publish to npm
npm run releaseFor more details, see .changeset/CONTRIBUTING.md.
See CLAUDE.md for detailed development guidance.
Troubleshooting
Font Substitution Warnings
Font 'CustomFont' substituted with 'Arial' for block 42The importer uses Google Fonts for font resolution. If a font isn't available, it falls back to a similar font. To add custom fonts:
// Add custom font to CE.SDK asset library before parsing
await engine.asset.addAssetToSource('my-fonts', {
id: 'custom-font',
meta: { name: 'Custom Font' },
payload: {
typeface: {
name: 'Custom Font',
fonts: [{ uri: 'https://example.com/font.ttf' }]
}
}
});Missing Theme Colors
Color scheme not found in theme XMLSome PPTX files have corrupted or missing theme data. The parser falls back to default colors. To fix, re-save the PPTX in PowerPoint.
Visual Differences in Golden Tests
Golden screenshot tests may show pixel differences due to:
- Font rendering differences across platforms
- CE.SDK version updates
- Intentional parser improvements
Update golden screenshots when differences are expected:
npm run test:update-goldenDocumentation
Feature-Specific Guides
- Gradients and Shadows - Implementation details for gradient fills, shadow effects, and gradient backgrounds
- Testing Strategy - Dual testing approach with generated and golden tests
- Feature Gap Analysis - Comprehensive analysis of supported and unsupported PPTX features
Architecture Documentation
- CLAUDE.md - Development guide for working with this codebase
- STRUCTURE_GUIDE.md - PPTX internal structure and parsing guide
License
ISC
Credits
Built with:
- IMG.LY Creative Engine SDK
- JSZip - PPTX ZIP extraction
- xml2js - XML parsing
- PptxGenJS - Test PPTX generation
Inspired by the PSD Importer architecture.
