Rendering and Assembly
The rendering and assembly pipeline in pptcraft transforms high-level JSON specifications into binary PowerPoint packages by leveraging python-pptx to manipulate OOXML structures. The core strategy involves opening a pre-built theme template, stripping its existing slides to preserve only the master layouts and theme definitions, and then programmatically injecting new slide content. This approach ensures that every generated slide inherits the correct theme colors, fonts, and background styles, avoiding the corruption or duplication issues that arise from naively merging standalone PPTX files. The system supports both single-slide rendering for immediate editing and multi-slide assembly for full deck generation, with visual elements like charts and tables handled through specific OOXML-aware functions to maintain data integrity.
Theme Application and Slide Initialization
Section titled “Theme Application and Slide Initialization”The foundation of the rendering process is the _open_blank_from_theme function, which loads a .pptx theme template and removes all existing slides while preserving the underlying masters and layouts . This is critical because python-pptx does not expose a clean Slide.delete() method; instead, the code iterates through the sldIdLst relationship list, drops the relationships, and removes the slide IDs to leave a clean slate . The theme metadata, including layout indices and color palettes, is loaded via _theme_meta, which reads from a JSON file generated by the ppt-craft themes build command .
When adding a slide, the renderer determines the appropriate layout index from the theme metadata based on the requested layout name, defaulting to index 1 (Title and Content) if unspecified . The slide is then added using prs.slides.add_slide(layout), ensuring it inherits the theme’s master properties . For single-slide rendering, this process happens in isolation, while deck assembly reuses the same theme-initialized presentation object to add multiple slides sequentially .
Content Population and OOXML Editing
Section titled “Content Population and OOXML Editing”Text content is populated by setting the title directly via slide.shapes.title.text if the placeholder exists . Body content, however, requires more granular control to preserve formatting like bold, italic, and color. The _apply_body_paragraphs function drives this by accessing the placeholder’s underlying XML element (sp_xml) and passing it to slide_edit.apply_paragraphs at the OOXML layer . This ensures that paragraph runs are correctly mapped to the OpenXML structure, maintaining parity with how Office.js handles edits .
If a slide layout lacks a body placeholder, the renderer currently returns None without adding content, as the POC keeps textbox synthesis simple . Speaker notes are handled straightforwardly by assigning the text to sld.notes_slide.notes_text_frame.text .
Visual Element Assembly
Section titled “Visual Element Assembly”Visual elements such as charts, tables, and images are positioned within a default bounding box that occupies the bottom 60% of the slide canvas, with a 7% margin on the sides . The coordinates are calculated in EMUs (English Metric Units) based on the slide width and height .
Charts are added using add_chart_to_slide, which accepts a chart specification and a palette. The palette is derived from the theme metadata, prioritizing “accent” colors for better contrast, falling back to the full palette if no accents are found . Tables are constructed by creating a shape with slide.shapes.add_table, then iterating through the TableSpec to populate headers and rows . Images are inserted using sld.shapes.add_picture if the specified path exists .
Deck Assembly and Output
Section titled “Deck Assembly and Output”The assemble_deck_pptx function iterates through a DeckRow’s slides, applying the same initialization and content population steps for each slide within a single Presentation object . This strategy avoids the complexity of merging multiple PPTX files, each of which would carry its own theme and master parts, potentially leading to a deck with duplicated masters . After all slides are added, the presentation is saved to a BytesIO buffer and returned as bytes .
For empty decks, _empty_presentation returns a valid but empty PPTX bytes object initialized from the theme, ensuring the caller receives a cleanly opening file . The resulting bytes are consumed by the Office.js taskpane via context.presentation.insertSlidesFromBase64, which expects a single-slide or multi-slide package drawn from the chosen theme template .