@imgly/pptx-importer
Version:
Import PowerPoint (PPTX) presentations into IMG.LY's Creative Engine SDK. Platform-agnostic TypeScript library for converting PPTX slides to CE.SDK scenes.
621 lines (447 loc) ⢠16.1 kB
Markdown
# PPTX Importer for CE.SDK
A TypeScript library for importing PowerPoint (PPTX) presentations into [IMG.LY's Creative Engine SDK](https://img.ly/products/creative-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
```bash
npm install @imgly/pptx-importer
```
### Peer Dependencies
You'll need CE.SDK in your project:
```bash
# For browser
npm install @cesdk/engine
# For Node.js
npm install @cesdk/node
```
## Quick Start
### Browser
```typescript
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
```typescript
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 instance
- `fileBuffer: ArrayBuffer` - PPTX file as ArrayBuffer
- `options?: Partial<PPTXParserOptions>` - Optional configuration
**Returns:** `Promise<PPTXParser>`
**Example:**
```typescript
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:**
```typescript
// 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:**
```typescript
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.
```typescript
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:
```typescript
// EMUs to CE.SDK pixels
pixels = (emus / 914400) * 300
// Simplified: pixels = emus / 3048
```
Font 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
```bash
# 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_LICENSE
```
### Building
```bash
# Build the package
npm run build
# Type check
npm run typecheck
# Clean build artifacts
npm run clean
```
### Testing
The project uses a **dual testing strategy**:
#### Generated Tests (Unit/Integration)
Fast, deterministic tests using [PptxGenJS](https://gitbrent.github.io/PptxGenJS/) to create PPTX files programmatically:
```bash
# Run all tests
npm test
# Run generated tests only
npm run test:generated
# Watch mode
npm run test:watch
```
#### Golden Screenshot Tests (Visual Regression)
Compare rendered output against reference screenshots using real PPTX files:
```bash
# 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-scenes
```
### Project 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 script
```
### Inspection Tools
Debug PPTX files and CE.SDK scenes:
```bash
# 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.ts
```
## Architecture
The importer follows a modular architecture:
1. **PPTX Loader** (`utils/pptx-loader.ts`) - Unzips PPTX and parses XML using JSZip + xml2js
2. **Parsers** - Extract data from XML structures
- `SlideParser` - Slide dimensions and element lists
- `ThemeParser` - Theme color schemes
- `ElementParser` - Individual element properties
3. **Handlers** - Create CE.SDK blocks
- `TextHandler` - Text blocks with formatting
- `ShapeHandler` - Graphic blocks with fills/strokes
- `ImageHandler` - Image blocks with data URLs
- `GroupHandler` - Grouped elements
- `PageHandler` - Page blocks (slides)
4. **Converters** - Transform data formats
- `UnitConverter` - EMU to pixels
- `ColorConverter` - PPTX colors to RGBA
- `VectorPathConverter` - Custom geometry to SVG paths
- `FontConverter` - Font name resolution
## Contributing
Contributions are welcome! Please follow the development principles:
### Core Principles
1. **TypeScript-First** - All code must be strictly typed
2. **Test-First Development** - Write tests before implementation
3. **Platform-Agnostic** - No Node.js-specific APIs in library code
4. **Dual Testing** - Generated tests + golden screenshot tests
### Development Workflow
1. Fork the repository
2. Create a feature branch
3. Write failing tests
4. Implement the feature
5. Ensure all tests pass
6. **Add a changeset** (see below)
7. Submit a pull request
### Versioning with Changesets
This project uses [Changesets](https://github.com/changesets/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-changeset` label 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:
```bash
npm run changeset
```
This will prompt you for:
1. **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)
2. **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:
```bash
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`:
```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:
1. **PRs are merged** to main with changesets
2. **GitHub Action** creates a "Version Packages" PR automatically
3. **Maintainer reviews** and merges the Version PR
4. **Automatic release** to npm happens on merge
#### Manual Versioning (for maintainers)
If needed, you can manually version and release:
```bash
# 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 release
```
For more details, see [`.changeset/CONTRIBUTING.md`](./.changeset/CONTRIBUTING.md).
See [CLAUDE.md](./CLAUDE.md) for detailed development guidance.
## Troubleshooting
### Font Substitution Warnings
```
Font 'CustomFont' substituted with 'Arial' for block 42
```
The importer uses Google Fonts for font resolution. If a font isn't available, it falls back to a similar font. To add custom fonts:
```typescript
// 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 XML
```
Some 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:
```bash
npm run test:update-golden
```
## Documentation
### Feature-Specific Guides
- **[Gradients and Shadows](./GRADIENTS_SHADOWS.md)** - Implementation details for gradient fills, shadow effects, and gradient backgrounds
- **[Testing Strategy](./TESTING_STRATEGY.md)** - Dual testing approach with generated and golden tests
- **[Feature Gap Analysis](./FEATURE_GAP_ANALYSIS.md)** - Comprehensive analysis of supported and unsupported PPTX features
### Architecture Documentation
- **[CLAUDE.md](./CLAUDE.md)** - Development guide for working with this codebase
- **[STRUCTURE_GUIDE.md](./STRUCTURE_GUIDE.md)** - PPTX internal structure and parsing guide
## License
ISC
## Credits
Built with:
- [IMG.LY Creative Engine SDK](https://img.ly/products/creative-sdk)
- [JSZip](https://stuk.github.io/jszip/) - PPTX ZIP extraction
- [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) - XML parsing
- [PptxGenJS](https://gitbrent.github.io/PptxGenJS/) - Test PPTX generation
Inspired by the [PSD Importer](https://github.com/imgly/psd-importer) architecture.
## Support
- š [Documentation](https://img.ly/docs/cesdk)
- š¬ [Community Forum](https://community.img.ly)
- š [Report Issues](https://github.com/your-org/pptx-importer/issues)
- š§ [Contact Support](mailto:support@img.ly)