pptx-svg 0.1.0
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.
- package/LICENSE +21 -0
- package/README.ja.md +221 -0
- package/README.md +221 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/main.wasm +0 -0
- package/dist/pptx-renderer.d.ts +81 -0
- package/dist/pptx-renderer.d.ts.map +1 -0
- package/dist/pptx-renderer.js +183 -0
- package/dist/pptx-renderer.js.map +1 -0
- package/dist/utils.d.ts +8 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +24 -0
- package/dist/utils.js.map +1 -0
- package/dist/wasm-compat.d.ts +23 -0
- package/dist/wasm-compat.d.ts.map +1 -0
- package/dist/wasm-compat.js +133 -0
- package/dist/wasm-compat.js.map +1 -0
- package/dist/zip.d.ts +24 -0
- package/dist/zip.d.ts.map +1 -0
- package/dist/zip.js +241 -0
- package/dist/zip.js.map +1 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 t-ujiie-g
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.ja.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# pptx-svg
|
|
2
|
+
|
|
3
|
+
PPTX と SVG の双方向変換ライブラリ。外部依存なし、ブラウザのみで動作します。
|
|
4
|
+
|
|
5
|
+
[English](README.md)
|
|
6
|
+
|
|
7
|
+
## 特徴
|
|
8
|
+
|
|
9
|
+
- **PPTX → SVG**: PowerPoint スライドを高品質な SVG に変換
|
|
10
|
+
- **SVG → PPTX**: SVG を編集して有効な .pptx ファイルにエクスポート(ロスレス往復)
|
|
11
|
+
- **サーバー不要**: ZIP 解凍・OOXML パース・SVG 生成すべてブラウザ内で完結
|
|
12
|
+
- **外部依存なし**: Wasm バイナリ約 200KB、npm 依存パッケージなし
|
|
13
|
+
- **フレームワーク非依存**: React、Vue、Svelte、バニラ JS など何でも利用可能
|
|
14
|
+
|
|
15
|
+
## インストール
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install pptx-svg
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## クイックスタート
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
25
|
+
|
|
26
|
+
const renderer = new PptxRenderer();
|
|
27
|
+
await renderer.init(); // Wasm は自動で読み込まれます
|
|
28
|
+
|
|
29
|
+
const file = await fetch('presentation.pptx');
|
|
30
|
+
await renderer.loadPptx(await file.arrayBuffer());
|
|
31
|
+
|
|
32
|
+
const svgString = renderer.renderSlideSvg(0); // スライド1を SVG に変換
|
|
33
|
+
document.getElementById('viewer').innerHTML = svgString;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### React
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { useEffect, useRef, useState } from 'react';
|
|
40
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
41
|
+
|
|
42
|
+
function SlideViewer({ pptxBuffer }: { pptxBuffer: ArrayBuffer }) {
|
|
43
|
+
const [svg, setSvg] = useState('');
|
|
44
|
+
const rendererRef = useRef<PptxRenderer | null>(null);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const renderer = new PptxRenderer();
|
|
48
|
+
rendererRef.current = renderer;
|
|
49
|
+
renderer.init()
|
|
50
|
+
.then(() => renderer.loadPptx(pptxBuffer))
|
|
51
|
+
.then(() => setSvg(renderer.renderSlideSvg(0)));
|
|
52
|
+
}, [pptxBuffer]);
|
|
53
|
+
|
|
54
|
+
return <div dangerouslySetInnerHTML={{ __html: svg }} />;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### バニラ JS(バンドラなし)
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script type="importmap">
|
|
62
|
+
{ "imports": { "pptx-svg": "https://cdn.jsdelivr.net/npm/pptx-svg/dist/index.js" } }
|
|
63
|
+
</script>
|
|
64
|
+
<script type="module">
|
|
65
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
66
|
+
const renderer = new PptxRenderer();
|
|
67
|
+
await renderer.init();
|
|
68
|
+
// ...
|
|
69
|
+
</script>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
完全なサンプルは [`examples/`](examples/) を参照してください。
|
|
73
|
+
|
|
74
|
+
## API リファレンス
|
|
75
|
+
|
|
76
|
+
### `PptxRenderer`
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
80
|
+
|
|
81
|
+
const renderer = new PptxRenderer(options?);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**オプション:**
|
|
85
|
+
|
|
86
|
+
| オプション | 型 | 説明 |
|
|
87
|
+
|-----------|------|------|
|
|
88
|
+
| `measureText` | `(text, fontFace, fontSizePt) => number` | テキスト幅計測のカスタム関数。デフォルトは Canvas 2D。 |
|
|
89
|
+
|
|
90
|
+
**メソッド:**
|
|
91
|
+
|
|
92
|
+
| メソッド | 戻り値 | 説明 |
|
|
93
|
+
|--------|---------|------|
|
|
94
|
+
| `init(wasmSource?)` | `Promise<void>` | Wasm モジュールを読み込み。引数なしで自動解決。URL や ArrayBuffer で上書き可能。 |
|
|
95
|
+
| `loadPptx(buffer)` | `Promise<{ slideCount }>` | ArrayBuffer から PPTX を読み込み。 |
|
|
96
|
+
| `getSlideCount()` | `number` | スライド数。 |
|
|
97
|
+
| `renderSlideSvg(idx)` | `string` | スライドを SVG 文字列として描画(0始まり)。 |
|
|
98
|
+
| `updateSlideFromSvg(idx, svg)` | `string` | 編集済み SVG からスライドデータを更新。`"OK"` または `"ERROR:..."` を返す。 |
|
|
99
|
+
| `getSlideOoxml(idx)` | `string` | スライドの OOXML XML を取得。 |
|
|
100
|
+
| `exportPptx()` | `Promise<ArrayBuffer>` | 変更を反映した .pptx ファイルとしてエクスポート。 |
|
|
101
|
+
| `getSlideXmlRaw(idx)` | `string` | 生のスライド XML(デバッグ用)。 |
|
|
102
|
+
| `getEntryList()` | `string[]` | 全 ZIP エントリパス(デバッグ用)。 |
|
|
103
|
+
|
|
104
|
+
## 対応機能
|
|
105
|
+
|
|
106
|
+
### 完全対応
|
|
107
|
+
|
|
108
|
+
- **シェイプ**: AutoShape (rect/ellipse/roundRect/line/プリセット約154種), カスタムジオメトリ (`a:custGeom`), コネクタ (直線/折れ線/曲線)
|
|
109
|
+
- **テキスト**: 段落, ラン, バレット (文字/自動/画像), フォント (Latin/EA/CS/Symbol), 太字/斜体/下線/取消線, 上付き/下付き, 文字間隔, カーニング, 大文字化, ハイパーリンク, タブ, RTL
|
|
110
|
+
- **テキストボディ**: 縦方向整列, 余白, 自動調整, フォントスケール, 回転, 縦書き, 多段組, テキストワープ (prstTxWarp)
|
|
111
|
+
- **塗りつぶし**: 単色, グラデーション (線形/放射 + ストップ), パターン (48プリセット), 画像フィル (stretch/tile/crop)
|
|
112
|
+
- **線/ストローク**: 破線11種, 矢印5種, 線端/結合, 複合線, グラデーション/パターンストローク
|
|
113
|
+
- **エフェクト**: 外部シャドウ, 内部シャドウ, グロー, ソフトエッジ, リフレクション (全て SVG フィルタ)
|
|
114
|
+
- **画像**: PNG/JPEG/GIF/SVG, クロップ, アルファ, 明るさ/コントラスト, デュオトーン, カラーチェンジ
|
|
115
|
+
- **テーブル**: セル結合, ボーダー (対角線含む), マージン, アンカー, テーブルスタイル, 条件書式
|
|
116
|
+
- **チャート**: 棒/折れ線/円/ドーナツ/散布/面/レーダー/バブル/株価/等高線/ofPie (13種), データラベル, トレンドライン, エラーバー, 複合チャート
|
|
117
|
+
- **グループシェイプ**: 再帰ネスト + 座標変換
|
|
118
|
+
- **テーマ**: 12テーマカラー, フォントスキーム, 全カラー修飾子
|
|
119
|
+
- **マスター/レイアウト継承**: プレースホルダ継承, `p:clrMapOvr`
|
|
120
|
+
- **背景**: 単色, グラデーション, 画像, パターン
|
|
121
|
+
- **3D**: Round-trip 用データ保持 (ベベル, 押し出し, 輪郭, マテリアル, カメラ, ライティング)
|
|
122
|
+
- **プレースホルダ自動内容**: スライド番号, 日付, フッター
|
|
123
|
+
|
|
124
|
+
### 未対応(今後対応予定)
|
|
125
|
+
|
|
126
|
+
- **SmartArt** (`dgm:*`) — フォールバック画像表示を予定
|
|
127
|
+
- **OLE / 埋め込みオブジェクト** (`p:oleObj`) — フォールバック画像表示を予定
|
|
128
|
+
- **メディア** (動画/音声) — ポスターフレーム表示を予定
|
|
129
|
+
- **EMF/WMF 画像** — ブラウザでデコード不可
|
|
130
|
+
- **TIFF 画像** — ブラウザ `<img>` 非対応
|
|
131
|
+
- **数式** (OMML `m:oMath`) — プレーンテキストフォールバックを予定
|
|
132
|
+
- **埋め込みフォント** — システムフォントフォールバック
|
|
133
|
+
- **スピーカーノート** (`p:notes`) — 予定
|
|
134
|
+
- **コメント** (`p:cmAuthorLst` / `p:cmLst`) — 予定
|
|
135
|
+
|
|
136
|
+
### スコープ外
|
|
137
|
+
|
|
138
|
+
- **アニメーション** (`p:timing`) — 静的レンダリングのみ
|
|
139
|
+
- **トランジション** (`p:transition`) — 静的レンダリングのみ
|
|
140
|
+
- **マクロ / VBA** — セキュリティ上の理由で非対応
|
|
141
|
+
|
|
142
|
+
## SVG 出力フォーマット
|
|
143
|
+
|
|
144
|
+
生成される SVG には `data-ooxml-*` 属性が埋め込まれ、OOXML メタデータを保持します。属性の完全なリファレンスは [`docs/svg-specification.md`](docs/svg-specification.md) を参照してください。
|
|
145
|
+
|
|
146
|
+
## ブラウザ互換性
|
|
147
|
+
|
|
148
|
+
| ブラウザ | 最小バージョン | 備考 |
|
|
149
|
+
|---------|--------------|------|
|
|
150
|
+
| Chrome | 111+ | 完全対応 (Tier 3 Wasm フォールバック) |
|
|
151
|
+
| Firefox | 120+ | 完全対応 |
|
|
152
|
+
| Safari | 17+ | 完全対応 |
|
|
153
|
+
| Edge | 111+ | Chrome と同等 |
|
|
154
|
+
| Node.js | 非対応 | Wasm-GC はブラウザランタイムが必要 |
|
|
155
|
+
|
|
156
|
+
## アーキテクチャ
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
[ブラウザ]
|
|
160
|
+
PptxRenderer (TypeScript)
|
|
161
|
+
├── ZIP 解凍 (DecompressionStream)
|
|
162
|
+
├── ZIP 構築 (CompressionStream + CRC-32)
|
|
163
|
+
└── FFI ─── WebAssembly GC (MoonBit)
|
|
164
|
+
├── XML パーサー
|
|
165
|
+
├── OOXML パーサー (型定義, テーマ, テキスト, シェイプ, チャート)
|
|
166
|
+
├── SVG レンダラー (シェイプ, テキスト, フィル, ジオメトリ, チャート)
|
|
167
|
+
├── SVG パーサー (data-ooxml-* → SlideData)
|
|
168
|
+
└── OOXML シリアライザー (SlideData → XML)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## 開発
|
|
172
|
+
|
|
173
|
+
### 前提条件
|
|
174
|
+
|
|
175
|
+
- [MoonBit ツールチェイン](https://moonbitlang.com/download/)
|
|
176
|
+
- Node.js 18+
|
|
177
|
+
|
|
178
|
+
### ビルド
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npm run build # Wasm + TypeScript + wasm を dist/ にコピー
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### テスト
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm test # Node.js テスト (ZIP + XML 構造アサーション)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### ブラウザテスト
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
python3 -m http.server 8765 --directory .
|
|
194
|
+
# http://localhost:8765/web/index.html を開く
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## リリース
|
|
198
|
+
|
|
199
|
+
npm へのリリースは GitHub Actions でバージョンタグ push 時に自動実行されます:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# package.json のバージョンを更新後:
|
|
203
|
+
git tag v0.1.0
|
|
204
|
+
git push origin v0.1.0
|
|
205
|
+
# GitHub Actions がビルド・テスト・npm publish を実行
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
GitHub リポジトリ設定で `NPM_TOKEN` シークレットの設定が必要です。
|
|
209
|
+
|
|
210
|
+
## コントリビュート
|
|
211
|
+
|
|
212
|
+
1. リポジトリをフォーク
|
|
213
|
+
2. フィーチャーブランチを作成
|
|
214
|
+
3. 既存のコードスタイルに従って変更
|
|
215
|
+
4. `test_fixtures/gen_test_features.py` と `test_fixtures/test_node.mjs` にテストを追加
|
|
216
|
+
5. `npm run build && npm test` で検証
|
|
217
|
+
6. プルリクエストを提出
|
|
218
|
+
|
|
219
|
+
## ライセンス
|
|
220
|
+
|
|
221
|
+
[MIT](LICENSE)
|
package/README.md
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
# pptx-svg
|
|
2
|
+
|
|
3
|
+
PPTX and SVG round-trip conversion library. Runs entirely in the browser with zero dependencies.
|
|
4
|
+
|
|
5
|
+
[Japanese / 日本語](README.ja.md)
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **PPTX to SVG**: Convert PowerPoint slides to high-quality SVG
|
|
10
|
+
- **SVG to PPTX**: Edit SVG and export back to a valid .pptx file (lossless round-trip)
|
|
11
|
+
- **Browser-native**: No server required. ZIP, OOXML parsing, SVG generation all run client-side
|
|
12
|
+
- **Zero dependencies**: ~200KB Wasm binary, no npm dependencies
|
|
13
|
+
- **Framework-agnostic**: Works with React, Vue, Svelte, vanilla JS, or any framework
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install pptx-svg
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Quick Start
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
25
|
+
|
|
26
|
+
const renderer = new PptxRenderer();
|
|
27
|
+
await renderer.init(); // Wasm loaded automatically
|
|
28
|
+
|
|
29
|
+
const file = await fetch('presentation.pptx');
|
|
30
|
+
await renderer.loadPptx(await file.arrayBuffer());
|
|
31
|
+
|
|
32
|
+
const svgString = renderer.renderSlideSvg(0); // Slide 1 as SVG
|
|
33
|
+
document.getElementById('viewer').innerHTML = svgString;
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### React
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import { useEffect, useRef, useState } from 'react';
|
|
40
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
41
|
+
|
|
42
|
+
function SlideViewer({ pptxBuffer }: { pptxBuffer: ArrayBuffer }) {
|
|
43
|
+
const [svg, setSvg] = useState('');
|
|
44
|
+
const rendererRef = useRef<PptxRenderer | null>(null);
|
|
45
|
+
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const renderer = new PptxRenderer();
|
|
48
|
+
rendererRef.current = renderer;
|
|
49
|
+
renderer.init()
|
|
50
|
+
.then(() => renderer.loadPptx(pptxBuffer))
|
|
51
|
+
.then(() => setSvg(renderer.renderSlideSvg(0)));
|
|
52
|
+
}, [pptxBuffer]);
|
|
53
|
+
|
|
54
|
+
return <div dangerouslySetInnerHTML={{ __html: svg }} />;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Vanilla JS (no bundler)
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script type="importmap">
|
|
62
|
+
{ "imports": { "pptx-svg": "https://cdn.jsdelivr.net/npm/pptx-svg/dist/index.js" } }
|
|
63
|
+
</script>
|
|
64
|
+
<script type="module">
|
|
65
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
66
|
+
const renderer = new PptxRenderer();
|
|
67
|
+
await renderer.init();
|
|
68
|
+
// ...
|
|
69
|
+
</script>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
See [`examples/`](examples/) for complete working examples.
|
|
73
|
+
|
|
74
|
+
## API Reference
|
|
75
|
+
|
|
76
|
+
### `PptxRenderer`
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { PptxRenderer } from 'pptx-svg';
|
|
80
|
+
|
|
81
|
+
const renderer = new PptxRenderer(options?);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Options:**
|
|
85
|
+
|
|
86
|
+
| Option | Type | Description |
|
|
87
|
+
|--------|------|-------------|
|
|
88
|
+
| `measureText` | `(text, fontFace, fontSizePt) => number` | Custom text width measurement. Defaults to Canvas 2D. |
|
|
89
|
+
|
|
90
|
+
**Methods:**
|
|
91
|
+
|
|
92
|
+
| Method | Returns | Description |
|
|
93
|
+
|--------|---------|-------------|
|
|
94
|
+
| `init(wasmSource?)` | `Promise<void>` | Load the Wasm module. No arguments needed (auto-resolved). Pass URL or ArrayBuffer to override. |
|
|
95
|
+
| `loadPptx(buffer)` | `Promise<{ slideCount }>` | Load a PPTX file from ArrayBuffer. |
|
|
96
|
+
| `getSlideCount()` | `number` | Number of slides. |
|
|
97
|
+
| `renderSlideSvg(idx)` | `string` | Render slide as SVG string (0-indexed). |
|
|
98
|
+
| `updateSlideFromSvg(idx, svg)` | `string` | Update slide data from edited SVG. Returns `"OK"` or `"ERROR:..."`. |
|
|
99
|
+
| `getSlideOoxml(idx)` | `string` | Get OOXML XML for a slide. |
|
|
100
|
+
| `exportPptx()` | `Promise<ArrayBuffer>` | Export as .pptx file with modifications applied. |
|
|
101
|
+
| `getSlideXmlRaw(idx)` | `string` | Raw slide XML (for debugging). |
|
|
102
|
+
| `getEntryList()` | `string[]` | All ZIP entry paths (for debugging). |
|
|
103
|
+
|
|
104
|
+
## Supported Features
|
|
105
|
+
|
|
106
|
+
### Fully Supported
|
|
107
|
+
|
|
108
|
+
- **Shapes**: AutoShape (rect, ellipse, roundRect, line, ~154 preset geometries), custom geometry (`a:custGeom`), connectors (straight/elbow/curved)
|
|
109
|
+
- **Text**: Paragraphs, runs, bullets (char/auto/image), fonts (Latin/EA/CS/Symbol), bold/italic/underline/strikethrough, superscript/subscript, character spacing, kerning, capitalization, hyperlinks, tabs, RTL
|
|
110
|
+
- **Text body**: Vertical alignment, margins, auto-fit, font scale, rotation, vertical text, multi-column, text warp (prstTxWarp)
|
|
111
|
+
- **Fill**: Solid color, gradient (linear/radial with stops), pattern (48 presets), image fill (stretch/tile/crop)
|
|
112
|
+
- **Stroke**: 11 dash patterns, 5 arrow types, line cap/join, compound lines, gradient/pattern stroke
|
|
113
|
+
- **Effects**: Outer shadow, inner shadow, glow, soft edge, reflection (all via SVG filters)
|
|
114
|
+
- **Images**: PNG/JPEG/GIF/SVG, crop, alpha, brightness/contrast, duotone, color change
|
|
115
|
+
- **Tables**: Cell merge (grid span, row span), borders (including diagonal), margins, anchoring, table styles, conditional formatting (banded rows/cols, first/last row/col)
|
|
116
|
+
- **Charts**: Bar, Line, Pie, Doughnut, Scatter, Area, Radar, Bubble, Stock, Surface, OfPie (13 types), data labels, data points, trendlines, error bars, composite charts
|
|
117
|
+
- **Group shapes**: Recursive nesting with coordinate transforms
|
|
118
|
+
- **Theme**: 12 theme colors, font scheme, all color modifiers (tint, shade, saturation, luminance, etc.)
|
|
119
|
+
- **Master/Layout inheritance**: Placeholder inheritance, `p:clrMapOvr`
|
|
120
|
+
- **Background**: Solid, gradient, image, pattern backgrounds
|
|
121
|
+
- **3D**: Data preservation for round-trip (bevel, extrusion, contour, material, camera, lighting)
|
|
122
|
+
- **Placeholder auto content**: Slide number, date, footer
|
|
123
|
+
|
|
124
|
+
### Not Yet Supported
|
|
125
|
+
|
|
126
|
+
- **SmartArt** (`dgm:*` DiagramML) - planned: fallback image display
|
|
127
|
+
- **OLE / Embedded objects** (`p:oleObj`) - planned: fallback image display
|
|
128
|
+
- **Media** (video/audio) - planned: poster frame display
|
|
129
|
+
- **EMF/WMF images** - cannot be decoded in browser
|
|
130
|
+
- **TIFF images** - not supported by browser `<img>`
|
|
131
|
+
- **Math equations** (OMML `m:oMath`) - planned: plain text fallback
|
|
132
|
+
- **Embedded fonts** - uses system font fallback
|
|
133
|
+
- **Speaker notes** (`p:notes`) - planned
|
|
134
|
+
- **Comments** (`p:cmAuthorLst` / `p:cmLst`) - planned
|
|
135
|
+
|
|
136
|
+
### Out of Scope
|
|
137
|
+
|
|
138
|
+
- **Animations** (`p:timing`) - static rendering only
|
|
139
|
+
- **Transitions** (`p:transition`) - static rendering only
|
|
140
|
+
- **Macros / VBA** - not supported for security reasons
|
|
141
|
+
|
|
142
|
+
## SVG Output Format
|
|
143
|
+
|
|
144
|
+
The generated SVG embeds `data-ooxml-*` attributes that preserve all OOXML metadata for round-trip conversion. See [`docs/svg-specification.md`](docs/svg-specification.md) for the complete attribute reference.
|
|
145
|
+
|
|
146
|
+
## Browser Compatibility
|
|
147
|
+
|
|
148
|
+
| Browser | Minimum Version | Notes |
|
|
149
|
+
|---------|----------------|-------|
|
|
150
|
+
| Chrome | 111+ | Full support (Tier 3 Wasm fallback) |
|
|
151
|
+
| Firefox | 120+ | Full support |
|
|
152
|
+
| Safari | 17+ | Full support |
|
|
153
|
+
| Edge | 111+ | Same as Chrome |
|
|
154
|
+
| Node.js | Not supported | Wasm-GC requires browser runtime |
|
|
155
|
+
|
|
156
|
+
## Architecture
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
[Browser]
|
|
160
|
+
PptxRenderer (TypeScript)
|
|
161
|
+
├── ZIP extraction (DecompressionStream)
|
|
162
|
+
├── ZIP building (CompressionStream + CRC-32)
|
|
163
|
+
└── FFI ─── WebAssembly GC (MoonBit)
|
|
164
|
+
├── XML parser
|
|
165
|
+
├── OOXML parser (types, theme, text, shapes, charts)
|
|
166
|
+
├── SVG renderer (shapes, text, fill, geometry, charts)
|
|
167
|
+
├── SVG parser (data-ooxml-* → SlideData)
|
|
168
|
+
└── OOXML serializer (SlideData → XML)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Development
|
|
172
|
+
|
|
173
|
+
### Prerequisites
|
|
174
|
+
|
|
175
|
+
- [MoonBit toolchain](https://moonbitlang.com/download/)
|
|
176
|
+
- Node.js 18+
|
|
177
|
+
|
|
178
|
+
### Build
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
npm run build # Wasm + TypeScript + copy wasm to dist/
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Test
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm test # Node.js test suite (ZIP + XML structure)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Browser Test
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
python3 -m http.server 8765 --directory .
|
|
194
|
+
# Open http://localhost:8765/web/index.html
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Release
|
|
198
|
+
|
|
199
|
+
Releases are published to npm via GitHub Actions when a version tag is pushed:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
# Update version in package.json, then:
|
|
203
|
+
git tag v0.1.0
|
|
204
|
+
git push origin v0.1.0
|
|
205
|
+
# GitHub Actions builds, tests, and publishes to npm
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Requires `NPM_TOKEN` secret configured in GitHub repository settings.
|
|
209
|
+
|
|
210
|
+
## Contributing
|
|
211
|
+
|
|
212
|
+
1. Fork the repository
|
|
213
|
+
2. Create a feature branch
|
|
214
|
+
3. Make changes following the existing code style
|
|
215
|
+
4. Add tests in `test_fixtures/gen_test_features.py` and `test_fixtures/test_node.mjs`
|
|
216
|
+
5. Run `npm run build && npm test` to verify
|
|
217
|
+
6. Submit a pull request
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
[MIT](LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pptx-svg — PPTX ↔ SVG conversion library
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { PptxRenderer } from 'pptx-svg';
|
|
7
|
+
*
|
|
8
|
+
* const renderer = new PptxRenderer();
|
|
9
|
+
* await renderer.init('./main.wasm');
|
|
10
|
+
* await renderer.loadPptx(pptxArrayBuffer);
|
|
11
|
+
*
|
|
12
|
+
* const svgString = renderer.renderSlideSvg(0);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { PptxRenderer } from './pptx-renderer.js';
|
|
16
|
+
export type { MeasureTextFn, PptxRendererOptions } from './pptx-renderer.js';
|
|
17
|
+
export { bytesToBase64, crc32 } from './utils.js';
|
|
18
|
+
export { extractZip, buildZip } from './zip.js';
|
|
19
|
+
export type { ZipContents } from './zip.js';
|
|
20
|
+
export { parseWasmStringConstants, instantiateWasmWithFallback } from './wasm-compat.js';
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,aAAa,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pptx-svg — PPTX ↔ SVG conversion library
|
|
3
|
+
*
|
|
4
|
+
* @example
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { PptxRenderer } from 'pptx-svg';
|
|
7
|
+
*
|
|
8
|
+
* const renderer = new PptxRenderer();
|
|
9
|
+
* await renderer.init('./main.wasm');
|
|
10
|
+
* await renderer.loadPptx(pptxArrayBuffer);
|
|
11
|
+
*
|
|
12
|
+
* const svgString = renderer.renderSlideSvg(0);
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export { PptxRenderer } from './pptx-renderer.js';
|
|
16
|
+
export { bytesToBase64, crc32 } from './utils.js';
|
|
17
|
+
export { extractZip, buildZip } from './zip.js';
|
|
18
|
+
export { parseWasmStringConstants, instantiateWasmWithFallback } from './wasm-compat.js';
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEhD,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/main.wasm
ADDED
|
Binary file
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PptxRenderer — main API class for rendering PPTX files.
|
|
3
|
+
*
|
|
4
|
+
* Handles Wasm lifecycle, PPTX loading, SVG rendering, and export.
|
|
5
|
+
*/
|
|
6
|
+
/** Options for text measurement callback. */
|
|
7
|
+
export interface MeasureTextFn {
|
|
8
|
+
(text: string, fontFace: string, fontSizePt: number): number;
|
|
9
|
+
}
|
|
10
|
+
/** Options for initializing PptxRenderer. */
|
|
11
|
+
export interface PptxRendererOptions {
|
|
12
|
+
/** Custom text measurement function. If not provided, uses Canvas 2D (browser only). */
|
|
13
|
+
measureText?: MeasureTextFn;
|
|
14
|
+
}
|
|
15
|
+
export declare class PptxRenderer {
|
|
16
|
+
private wasm;
|
|
17
|
+
/** Decompressed text ZIP entries (path → UTF-8 string) */
|
|
18
|
+
private files;
|
|
19
|
+
/** Raw binary ZIP entries (path → bytes) */
|
|
20
|
+
private rawFiles;
|
|
21
|
+
/** Original PPTX bytes for export */
|
|
22
|
+
private originalBuffer;
|
|
23
|
+
/** Canvas for text measurement (lazily created) */
|
|
24
|
+
private canvas;
|
|
25
|
+
private ctx;
|
|
26
|
+
/** Custom text measurement function */
|
|
27
|
+
private measureTextFn;
|
|
28
|
+
constructor(options?: PptxRendererOptions);
|
|
29
|
+
/** Get typed Wasm exports. */
|
|
30
|
+
private get exports();
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the renderer by loading the Wasm module.
|
|
33
|
+
*
|
|
34
|
+
* When called without arguments, the bundled Wasm binary is loaded
|
|
35
|
+
* automatically via `import.meta.url` resolution. This works with
|
|
36
|
+
* Vite, webpack, Rollup, and CDN imports (unpkg, jsdelivr).
|
|
37
|
+
*
|
|
38
|
+
* @param wasmSource - Optional URL string or ArrayBuffer of .wasm bytes.
|
|
39
|
+
* If omitted, the bundled Wasm is used.
|
|
40
|
+
*/
|
|
41
|
+
init(wasmSource?: string | ArrayBuffer): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Load a PPTX file from an ArrayBuffer.
|
|
44
|
+
* @returns Object with slideCount
|
|
45
|
+
*/
|
|
46
|
+
loadPptx(arrayBuffer: ArrayBuffer): Promise<{
|
|
47
|
+
slideCount: number;
|
|
48
|
+
}>;
|
|
49
|
+
/** Number of slides in the loaded presentation. */
|
|
50
|
+
getSlideCount(): number;
|
|
51
|
+
/** Get the raw XML of a slide (0-indexed). For debugging. */
|
|
52
|
+
getSlideXmlRaw(slideIdx: number): string;
|
|
53
|
+
/** Get all entry paths in the PPTX archive. For debugging. */
|
|
54
|
+
getEntryList(): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Render a slide as an SVG string (0-indexed).
|
|
57
|
+
* @returns SVG markup, or a string starting with "ERROR:" on failure
|
|
58
|
+
*/
|
|
59
|
+
renderSlideSvg(slideIdx: number): string;
|
|
60
|
+
/**
|
|
61
|
+
* Update a slide's internal data from an edited SVG string.
|
|
62
|
+
* Parses the SVG's data-ooxml-* attributes back into SlideData.
|
|
63
|
+
* @returns "OK" on success, "ERROR:..." on failure
|
|
64
|
+
*/
|
|
65
|
+
updateSlideFromSvg(slideIdx: number, svgString: string): string;
|
|
66
|
+
/**
|
|
67
|
+
* Get the OOXML slide XML for a slide (0-indexed).
|
|
68
|
+
* Returns modified XML if the slide was updated, otherwise original.
|
|
69
|
+
*/
|
|
70
|
+
getSlideOoxml(slideIdx: number): string;
|
|
71
|
+
/**
|
|
72
|
+
* Export the (possibly modified) presentation as a PPTX ArrayBuffer.
|
|
73
|
+
* Replaces modified slide XML entries in the original ZIP and rebuilds it.
|
|
74
|
+
*/
|
|
75
|
+
exportPptx(): Promise<ArrayBuffer>;
|
|
76
|
+
/** Build the Wasm import object that satisfies MoonBit's FFI declarations. */
|
|
77
|
+
private buildImportObject;
|
|
78
|
+
/** Measure the rendered pixel width of text. */
|
|
79
|
+
private measureText;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=pptx-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pptx-renderer.d.ts","sourceRoot":"","sources":["../lib/pptx-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkBH,6CAA6C;AAC7C,MAAM,WAAW,aAAa;IAC5B,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9D;AAED,6CAA6C;AAC7C,MAAM,WAAW,mBAAmB;IAClC,wFAAwF;IACxF,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B;AAKD,qBAAa,YAAY;IACvB,OAAO,CAAC,IAAI,CAAqC;IAEjD,0DAA0D;IAC1D,OAAO,CAAC,KAAK,CAA6B;IAE1C,4CAA4C;IAC5C,OAAO,CAAC,QAAQ,CAAiC;IAEjD,qCAAqC;IACrC,OAAO,CAAC,cAAc,CAA4B;IAElD,mDAAmD;IACnD,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,GAAG,CAAyC;IAEpD,uCAAuC;IACvC,OAAO,CAAC,aAAa,CAA8B;gBAEvC,OAAO,CAAC,EAAE,mBAAmB;IAMzC,8BAA8B;IAC9B,OAAO,KAAK,OAAO,GAGlB;IAED;;;;;;;;;OASG;IACG,IAAI,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAe5D;;;OAGG;IACG,QAAQ,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAoBzE,mDAAmD;IACnD,aAAa,IAAI,MAAM;IAIvB,6DAA6D;IAC7D,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIxC,8DAA8D;IAC9D,YAAY,IAAI,MAAM,EAAE;IAIxB;;;OAGG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIxC;;;;OAIG;IACH,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM;IAI/D;;;OAGG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAIvC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,CAAC;IA0BxC,8EAA8E;IAC9E,OAAO,CAAC,iBAAiB;IAuBzB,gDAAgD;IAChD,OAAO,CAAC,WAAW;CAgBpB"}
|