UNPKG

@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
# 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)