typ2pptx 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,369 @@
1
+ Metadata-Version: 2.4
2
+ Name: typ2pptx
3
+ Version: 0.1.0
4
+ Summary: Convert Typst presentations (Touying) to editable PowerPoint files
5
+ License: MIT
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: python-pptx>=0.6.21
9
+ Requires-Dist: lxml>=4.9.0
10
+ Requires-Dist: Pillow>=9.0.0
11
+ Requires-Dist: typst>=0.14.0
12
+ Requires-Dist: cssselect>=1.2.0
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=7.0; extra == "dev"
15
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
16
+
17
+ # typ2pptx
18
+
19
+ Convert [Typst](https://typst.app/) presentations (using the [Touying](https://github.com/touying-typ/touying) framework) to editable PowerPoint (.pptx) files.
20
+
21
+ ## Features
22
+
23
+ - **Editable text**: All text is extracted as editable, selectable, copyable PowerPoint text (not rasterized images)
24
+ - **Font variants**: Detects and preserves regular, bold, italic, bold-italic, and monospace text styles
25
+ - **Math formulas**: Inline math rendered as Cambria Math text with PPTX-native sub/superscript baseline offsets (auto-sized by PowerPoint); display math rendered as native DrawingML curve shapes (glyph outlines) grouped per formula
26
+ - **Heuristic math mode**: Auto-classifies formulas as simple (text) or complex (glyph curves) for best rendering; stacked fractions (e.g. `$1/2$`) are auto-detected and routed to glyph mode
27
+ - **Native shapes**: Converts SVG shapes (rectangles, circles, ellipses, lines, paths, polygons) to native DrawingML custom geometry
28
+ - **Gradient fills**: Supports SVG linear gradients converted to PowerPoint gradient fills
29
+ - **Transparency/opacity**: Full support for alpha channels in colors (#RRGGBBAA, rgba), fill-opacity, and element opacity
30
+ - **Hyperlinks**: External links from Typst `#link()` are preserved as clickable hyperlinks in PowerPoint; internal document links are rendered as normal text without hyperlink styling; theme-level hyperlink colors are neutralized to prevent default blue/purple override
31
+ - **Speaker notes**: Extracts Touying speaker notes via `typst.query()` (Python package) and attaches them to slides
32
+ - **Color preservation**: Supports hex, rgb(), rgba(), named CSS colors, and per-character coloring
33
+ - **Multi-run textboxes**: Groups same-line text segments into single textboxes with multiple styled runs
34
+ - **Paragraph alignment**: Auto-detects left, center, right, and justify alignment from Typst layout
35
+ - **Code blocks**: Syntax-highlighted code blocks rendered with Consolas font, preserving per-token colors
36
+ - **Images**: Supports embedded (data URI) and external image references (PNG, SVG, PDF); SVG/PDF images rasterized to PNG with transparent background via the `typst` Python package
37
+ - **Tables**: Table content (cells, headers, colored fills) converted to text and shapes
38
+
39
+ ## Prerequisites
40
+
41
+ - **Python 3.9+**
42
+ - **typst** (Python package, v0.14+): For speaker notes extraction and SVG/PDF image rasterization
43
+ - Installed automatically via pip
44
+ - **typst-ts-cli** (v0.6.0+): For compiling `.typ` files to SVG with foreignObject text overlays
45
+ - Download from [typst.ts releases](https://github.com/nickelc/typst.ts/releases)
46
+
47
+ ## Installation
48
+
49
+ ### From PyPI (recommended)
50
+
51
+ ```bash
52
+ pip install typ2pptx
53
+ ```
54
+
55
+ After installation, the `typ2pptx` CLI command is available system-wide.
56
+
57
+ ### Development install
58
+
59
+ ```bash
60
+ # Install in editable/development mode
61
+ pip install -e .
62
+
63
+ # Install with dev dependencies (pytest, etc.)
64
+ pip install -e ".[dev]"
65
+ ```
66
+
67
+ ### Using uv
68
+
69
+ ```bash
70
+ # Install from PyPI
71
+ uv pip install typ2pptx
72
+
73
+ # Or install in editable/development mode
74
+ uv pip install -e .
75
+
76
+ # Install with dev dependencies
77
+ uv pip install -e ".[dev]"
78
+ ```
79
+
80
+ ### Updating dependencies
81
+
82
+ All dependencies are declared in `pyproject.toml`. After modifying them:
83
+
84
+ ```bash
85
+ # pip
86
+ pip install -e .
87
+
88
+ # uv
89
+ uv pip install -e .
90
+ ```
91
+
92
+ ## Usage
93
+
94
+ ### Command Line
95
+
96
+ ```bash
97
+ # Convert a Typst presentation to PPTX
98
+ typ2pptx slides.typ -o slides.pptx
99
+
100
+ # Convert with verbose output
101
+ typ2pptx slides.typ -o slides.pptx -v
102
+
103
+ # Convert from pre-compiled SVG (no typst-ts-cli needed)
104
+ typ2pptx slides.artifact.svg -o slides.pptx
105
+
106
+ # Specify custom tool paths
107
+ typ2pptx slides.typ -o slides.pptx \
108
+ --typst-ts-cli /path/to/typst-ts-cli
109
+
110
+ # Math rendering mode options
111
+ typ2pptx slides.typ -o slides.pptx \
112
+ --inline-math-mode auto \ # "text", "glyph", or "auto" (default: auto)
113
+ --display-math-mode glyph # "text", "glyph", or "auto" (default: glyph)
114
+ ```
115
+
116
+ ### Math Rendering Modes
117
+
118
+ | Mode | Inline Math Default | Display Math Default | Description |
119
+ |------|--------------------|--------------------|-------------|
120
+ | `text` | Cambria Math font | Cambria Math font | Renders math as editable text runs |
121
+ | `glyph` | Glyph curves | Glyph curves | Renders math as native DrawingML shapes (pixel-perfect) |
122
+ | `auto` | Heuristic | Heuristic | Simple formulas as text, complex ones (integrals, matrices, stacked fractions) as glyph curves |
123
+
124
+ ### Python API
125
+
126
+ ```python
127
+ from typ2pptx.core.converter import convert_typst_to_pptx
128
+
129
+ # Simple conversion
130
+ convert_typst_to_pptx("slides.typ", "slides.pptx")
131
+
132
+ # With options
133
+ convert_typst_to_pptx(
134
+ "slides.typ",
135
+ "slides.pptx",
136
+ typst_ts_cli="/path/to/typst-ts-cli",
137
+ verbose=True,
138
+ )
139
+
140
+ # Convert from SVG directly
141
+ convert_typst_to_pptx("slides.artifact.svg", "slides.pptx")
142
+ ```
143
+
144
+ ### Advanced: Step-by-step conversion
145
+
146
+ ```python
147
+ from typ2pptx.core.converter import (
148
+ compile_typst_to_svg,
149
+ query_speaker_notes,
150
+ TypstSVGConverter,
151
+ ConversionConfig,
152
+ )
153
+
154
+ # Step 1: Compile to SVG
155
+ svg_path = compile_typst_to_svg("slides.typ")
156
+
157
+ # Step 2: Extract speaker notes
158
+ notes = query_speaker_notes("slides.typ")
159
+
160
+ # Step 3: Convert to PPTX with custom config
161
+ config = ConversionConfig(
162
+ verbose=True,
163
+ inline_math_mode="auto", # "text", "glyph", or "auto"
164
+ display_math_mode="glyph", # "text", "glyph", or "auto"
165
+ )
166
+ converter = TypstSVGConverter(config)
167
+ converter.convert(svg_path, "slides.pptx", speaker_notes=notes)
168
+ ```
169
+
170
+ ## How It Works
171
+
172
+ ### Pipeline
173
+
174
+ ```
175
+ Typst (.typ)
176
+ |
177
+ v
178
+ typst-ts-cli --> SVG (with foreignObject text overlays)
179
+ |
180
+ v
181
+ typst.query() --> Speaker notes (pdfpc JSON format, via Python package)
182
+ |
183
+ v
184
+ typ2pptx --> PowerPoint (.pptx)
185
+ ```
186
+
187
+ ### Architecture
188
+
189
+ 1. **SVG Parser** (`typst_svg_parser.py`): Parses the typst.ts SVG structure, which uses:
190
+ - Glyph outlines as `<path>` + `<use>` references (for rendering)
191
+ - `<foreignObject>` overlays with HTML text (for selection/copy)
192
+ - `scale(S, -S)` transforms with Y-axis flipping
193
+ - 5-character hash prefixes per font variant
194
+ - `<a>` hyperlink elements with `<rect>` bounding boxes for link regions
195
+
196
+ 2. **Font Variant Detection**: Identifies font styles by analyzing glyph paths:
197
+ - Quadratic curves (Q commands) indicate monospace fonts
198
+ - Glyph width comparison differentiates bold from italic
199
+ - Unicode math character detection (U+1D400+) identifies math fonts
200
+ - Usage frequency determines the regular (body text) font
201
+
202
+ 3. **Shape Converter**: Uses the ppt-master `svg_to_shapes.py` pipeline:
203
+ - `parse_svg_path()` -> `svg_path_to_absolute()` -> `normalize_path_commands()` -> `path_commands_to_drawingml()`
204
+ - Generates DrawingML `<a:custGeom>` XML for custom geometry
205
+ - Supports solid fills (with alpha transparency), gradient fills, and strokes
206
+
207
+ 4. **Text Converter**: Groups and renders text:
208
+ - Groups same-line segments (within 2px baseline tolerance) into multi-run textboxes
209
+ - Handles gap-based space detection for word boundaries
210
+ - Inline math sub/superscripts merged into adjacent text lines with PPTX-native baseline offsets
211
+ - Math segments clustered spatially into formula regions
212
+ - Sets font properties (bold, italic, name, size, color) per run
213
+ - Auto-detects paragraph alignment (left, center, right, justify) from segment positions
214
+
215
+ 5. **Math Renderer**: Dual-mode math formula handling:
216
+ - **Text mode**: Renders as Cambria Math text runs with sub/superscript baseline offsets
217
+ - **Graphics mode**: Renders glyph outlines as DrawingML `<a:custGeom>` shapes grouped in `<p:grpSp>`
218
+ - **Auto mode**: Heuristic classification - simple formulas (letters, digits, basic operators) as text, complex formulas (integrals, matrices, roots, stacked fractions) as glyph curves
219
+
220
+ 6. **Link Processor**: Detects SVG `<a>` elements and applies hyperlinks to overlapping text runs in PPTX
221
+ - Only external links (http, https, mailto) become PPTX hyperlinks
222
+ - Internal document links are rendered as normal text
223
+ - Explicitly suppresses PowerPoint's default hyperlink styling (blue color + underline) via `u="none"` and explicit `solidFill`
224
+ - Theme-level hyperlink colors (hlink/folHlink) are neutralized to prevent blue/purple override
225
+
226
+ 7. **Speaker Notes**: Extracts via `typst.query()` (Python package):
227
+ - Uses `typst.query(path, "<pdfpc-file>", field="value")` to extract pdfpc JSON
228
+ - Touying framework outputs pdfpc JSON with page indices and note text
229
+ - Notes are attached to the corresponding PowerPoint slides
230
+ - Falls back to CLI `typst query` if the Python package is unavailable
231
+
232
+ ## Supported Typst Content
233
+
234
+ | Category | Feature | Support |
235
+ |----------|---------|---------|
236
+ | **Text** | Regular, Bold, Italic, Bold-Italic | Full |
237
+ | **Text** | Monospace / inline code | Full |
238
+ | **Text** | Colored text | Full |
239
+ | **Text** | Font size variants | Full |
240
+ | **Text** | Chinese/CJK text | Full |
241
+ | **Math** | Inline formulas | Cambria Math text (auto/text mode) or glyph curves (glyph mode) |
242
+ | **Math** | Display formulas | Glyph curves (default) or Cambria Math text |
243
+ | **Math** | Stacked fractions | Auto-detected and rendered as glyph curves in auto mode |
244
+ | **Math** | Subscripts/superscripts | PPTX-native baseline offset (auto-sized by PowerPoint) |
245
+ | **Math** | Formula grouping | Grouped as single draggable unit in PPTX |
246
+ | **Shapes** | Rectangles, circles, ellipses | Native DrawingML |
247
+ | **Shapes** | Lines, paths, polygons | Native DrawingML |
248
+ | **Shapes** | Gradient fills | DrawingML gradFill |
249
+ | **Shapes** | Transparency/opacity | Alpha channel support (RRGGBBAA, rgba, fill-opacity) |
250
+ | **Code** | Inline code | Consolas font |
251
+ | **Code** | Code blocks | Consolas font with syntax highlighting colors |
252
+ | **Images** | Embedded PNG (data URI) | Full |
253
+ | **Images** | Embedded SVG | Rasterized to PNG via typst (transparent background) |
254
+ | **Images** | Embedded/external PDF | Rasterized to PNG via typst (transparent background) |
255
+ | **Images** | External references | Full |
256
+ | **Links** | External hyperlinks (`#link()`) | Clickable in PPTX, preserves original styling |
257
+ | **Links** | Internal document links | Rendered as normal text (no hyperlink) |
258
+ | **Tables** | Table cells and headers | Text + shapes |
259
+ | **Tables** | Colored table backgrounds | Filled shapes |
260
+ | **Layout** | Slide dimensions (16:9, 4:3) | Full |
261
+ | **Layout** | Text alignment (left, center, right, justify) | Auto-detected |
262
+ | **Notes** | Touying speaker notes | Full |
263
+ | **Lists** | Bullet points | Text with bullet chars |
264
+ | **Plugins** | Pinit highlights | Colored overlay shapes |
265
+
266
+ ## Testing
267
+
268
+ ```bash
269
+ # Run all tests
270
+ pytest tests/ -v
271
+
272
+ # Run specific test modules
273
+ pytest tests/test_converter.py -v
274
+ pytest tests/test_math.py -v
275
+ pytest tests/test_inline_math.py -v
276
+ pytest tests/test_table.py -v
277
+ pytest tests/test_pinit.py -v
278
+ pytest tests/test_links.py -v
279
+ pytest tests/test_images.py -v
280
+ pytest tests/test_chinese.py -v
281
+ pytest tests/test_alignment.py -v
282
+ pytest tests/test_code_blocks.py -v
283
+ ```
284
+
285
+ ### Test Coverage
286
+
287
+ - **254 tests** covering:
288
+ - Converter & configuration (56 tests)
289
+ - SVG parser (30 tests)
290
+ - Inline math & stacked fractions (22 tests)
291
+ - Image embedding & rasterization (21 tests)
292
+ - SVG path pipeline (17 tests)
293
+ - Table rendering (17 tests)
294
+ - Math formulas & display curves (16 tests)
295
+ - Pinit annotations (15 tests)
296
+ - Code blocks & syntax highlighting (12 tests)
297
+ - Text positioning & multi-run merging (12 tests)
298
+ - Chinese text (11 tests)
299
+ - Hyperlinks (11 tests)
300
+ - Columns layout (7 tests)
301
+ - Text alignment (7 tests)
302
+
303
+ ## Project Structure
304
+
305
+ ```
306
+ typ2pptx/
307
+ core/
308
+ converter.py # Main SVG -> PPTX conversion logic
309
+ typst_svg_parser.py # typst.ts SVG parsing and text extraction
310
+ scripts/
311
+ svg_to_shapes.py # SVG path -> DrawingML pipeline (from ppt-master)
312
+ __main__.py # CLI entry point
313
+ tests/
314
+ conftest.py # Shared test fixtures
315
+ test_converter.py # Converter tests
316
+ test_math.py # Math formula tests
317
+ test_inline_math.py # Inline math and display math curve tests
318
+ test_chinese.py # Chinese text tests
319
+ test_table.py # Table rendering tests
320
+ test_pinit.py # Pinit annotation tests
321
+ test_links.py # Hyperlink tests
322
+ test_images.py # Image embedding tests
323
+ test_alignment.py # Text alignment tests
324
+ test_code_blocks.py # Code block & syntax highlighting tests
325
+ test_text_positioning.py # Text positioning tests
326
+ test_svg_parser.py # SVG parser tests
327
+ test_path_pipeline.py # Path conversion tests
328
+ typ_sources/ # Test Typst source files
329
+ basic_text.typ
330
+ shapes_test.typ
331
+ speaker_notes_test.typ
332
+ math_test.typ
333
+ chinese_test.typ
334
+ inline_math_test.typ
335
+ table_test.typ
336
+ pinit_test.typ
337
+ link_test.typ
338
+ image_test.typ
339
+ alignment_test.typ
340
+ code_block_test.typ
341
+ columns_test.typ
342
+ ```
343
+
344
+ ## Acknowledgments
345
+
346
+ ### ppt-master Attribution
347
+
348
+ The file `typ2pptx/scripts/svg_to_shapes.py` is adapted from the [ppt-master](https://github.com/niccolocorsani/ppt-master) project, which provides the core SVG path to DrawingML conversion pipeline:
349
+
350
+ - `parse_svg_path()` -- tokenizes SVG path `d` attributes into structured commands
351
+ - `svg_path_to_absolute()` -- converts relative path commands to absolute coordinates
352
+ - `normalize_path_commands()` -- reduces all curve types (S, Q, T, A) to cubic beziers (C)
353
+ - `path_commands_to_drawingml()` -- generates DrawingML `<a:custGeom>` XML for custom geometry
354
+
355
+ The pipeline supports solid fills, gradient fills (linear and radial), and strokes with configurable dash patterns and line caps.
356
+
357
+ The original ppt-master code has been modified for typst SVG compatibility, including:
358
+
359
+ - Added inherited style propagation through nested `<g>` elements via `ConvertContext`
360
+ - Added CJK font detection and Windows font fallback mapping for cross-platform PPTX compatibility
361
+ - Added donut-chart arc segment detection (SVG `stroke-dasharray` circles converted to filled annular sectors)
362
+ - Added support for element opacity, fill-opacity, and stroke-opacity (including multiplicative inheritance)
363
+ - Added `<ellipse>`, `<polyline>`, `<image>`, and `<text>` (with multi-run `<tspan>`) element converters
364
+ - Added group (`<g>`) to `<p:grpSp>` conversion with automatic bounds calculation
365
+ - Added shadow effect support via SVG `<filter>` (feGaussianBlur + feOffset)
366
+
367
+ ## License
368
+
369
+ MIT