@file-viewer/ppt 0.2.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 ADDED
@@ -0,0 +1,196 @@
1
+ Flyfish Public Watermarked Binary License for @file-viewer/ppt
2
+ Version 1.2, July 2026
3
+ License policy identifier: flyfish-public-watermarked-binary-license-v1
4
+
5
+ Copyright (c) 2026 Flyfish. All rights reserved except as expressly granted in this License.
6
+
7
+ IMPORTANT: This is a proprietary binary-use license. It is not an open-source
8
+ license. By downloading, installing, copying, accessing, or using the Public
9
+ Package, You accept this License. If You do not accept it, do not use the Public
10
+ Package and delete every copy under Your control.
11
+
12
+ 1. Definitions
13
+
14
+ “Flyfish” means the copyright owner and licensor of the Public Package.
15
+
16
+ “Public Package” means the official, unmodified @file-viewer/ppt binary npm
17
+ package distributed by Flyfish under this License, including its JavaScript
18
+ loader, native WebAssembly rendering module, declarations, documentation, and
19
+ required Flyfish Viewer watermark.
20
+
21
+ “You” means an individual natural person acting solely in that person’s
22
+ personal capacity. A company, legal entity, government body, school, nonprofit,
23
+ team, employer, client, or other organization is not “You” under the free grant,
24
+ even when an individual accesses the Public Package on its behalf.
25
+
26
+ “Personal Non-Commercial Use” means learning, private research, private testing,
27
+ personal evaluation, or a personal non-revenue project that is not performed
28
+ for, on behalf of, or in connection with any organization, employment, client,
29
+ profession, trade, business, compensation, fee, fundraising, or commercial
30
+ advantage.
31
+
32
+ “Commercial Use” means every use that is not Personal Non-Commercial Use.
33
+
34
+ 2. Limited free grant
35
+
36
+ Subject to continuous compliance with this License, Flyfish grants You a
37
+ limited, non-exclusive, non-transferable, non-sublicensable, revocable right to:
38
+
39
+ - download and install the official Public Package;
40
+ - execute it on any normal HTTP or HTTPS browser origin solely for Personal
41
+ Non-Commercial Use; and
42
+ - serve unmodified Public Package assets only as an integrated component of
43
+ Your own Personal Non-Commercial Use project.
44
+
45
+ The grant is conditioned on the Flyfish Viewer watermark remaining visible,
46
+ complete, unobstructed, and unmodified in every rendered slide and preview.
47
+ The grant does not include source code, source-delivery rights, redistribution
48
+ rights, modification rights, derivative-work rights, or any commercial right.
49
+
50
+ 3. Commercial and organizational use
51
+
52
+ You must obtain a separate written commercial license from Flyfish before any
53
+ Commercial Use. Commercial Use includes, without limitation:
54
+
55
+ - any use by or for a company, organization, government body, school,
56
+ nonprofit, team, employer, customer, or client, including internal evaluation;
57
+ - production, intranet, extranet, SaaS, hosted, cloud, embedded, OEM, resale,
58
+ consulting, customer-delivery, revenue-generating, fee-supported, sponsored,
59
+ or professionally connected use;
60
+ - integration into any product, service, project, procurement, sales demo, or
61
+ workflow connected with business or compensated activity; and
62
+ - any removal, hiding, obstruction, weakening, alteration, or replacement of
63
+ the required Flyfish Viewer watermark or public-edition restrictions.
64
+
65
+ A separately purchased commercial or enterprise agreement applies only to the
66
+ features, deployments, origins, entities, term, and other scope expressly stated
67
+ in that agreement. A commercial agreement does not amend this Public Package.
68
+ Flyfish may instead provide a separately built commercial package.
69
+
70
+ Purchase and authorization information:
71
+ https://dev.flyfish.group/shop
72
+
73
+ 4. Restrictions
74
+
75
+ Except to the limited extent that mandatory law expressly permits despite this
76
+ restriction, You may not, and may not enable or assist another person to:
77
+
78
+ - redistribute, publish, mirror, sublicense, sell, rent, lease, transfer,
79
+ repackage, or make the Public Package available as a standalone download,
80
+ reusable dependency, CDN asset, hosted API, or service for third parties;
81
+ - modify, translate, adapt, patch, or create derivative works from the Public
82
+ Package, WebAssembly module, or watermark;
83
+ - reverse engineer, decrypt, decompile, disassemble, extract, dump, recover, or
84
+ otherwise attempt to derive source code, keys, protected modules, algorithms,
85
+ or non-public interfaces;
86
+ - bypass, forge, replace, disable, or interfere with any policy gate, integrity
87
+ check, encryption, feature restriction, watermark control, or other technical
88
+ protection measure;
89
+ - remove, hide, crop, cover, restyle, obscure, weaken, or interfere with the
90
+ Flyfish Viewer watermark in the viewer output;
91
+ - remove or alter copyright, license, attribution, provenance, trademark, or
92
+ commercial-use notices; or
93
+ - represent the Public Package as open source or as licensed under Apache-2.0,
94
+ MIT, BSD, GPL, or another open-source license.
95
+
96
+ Installing the official package through npm and making reasonable backup copies
97
+ solely for Your permitted use are not prohibited redistribution.
98
+
99
+ Technical bundling, minification, and static-asset deployment are permitted only
100
+ as necessary to operate Your own project within the Limited Free Grant, provided
101
+ that the Public Package is not exposed or supplied as a reusable library,
102
+ standalone dependency, mirror, download, API, or service, and provided that all
103
+ license notices, integrity controls, and required watermarks remain intact.
104
+
105
+ 5. Separate source deliveries and Apache-2.0 boundary
106
+
107
+ This License applies only to the Public Package and does not grant rights under
108
+ the Apache License 2.0 or any other open-source license.
109
+
110
+ Any Apache License 2.0 terms that Flyfish may separately provide to a specific
111
+ source-delivery customer apply only to the source files and scope expressly
112
+ identified in that separate delivery. Those terms are not incorporated into,
113
+ and do not extend to, this Public Package, its public WebAssembly distribution,
114
+ the Flyfish Viewer watermark, or Flyfish trademarks.
115
+ Nothing in this License changes rights already validly granted in a separate
116
+ written delivery or license agreement.
117
+
118
+ 6. Watermark and limited trademark permission
119
+
120
+ The Flyfish name and Flyfish Viewer watermark are protected marks of Flyfish.
121
+ Solely so You can comply with this License, Flyfish grants You a narrow,
122
+ non-transferable permission to display the unmodified mandatory watermark as
123
+ produced by the Public Package. No other trademark, branding, endorsement, or
124
+ merchandising right is granted.
125
+
126
+ Only a separately purchased and separately built commercial package may omit
127
+ the public watermark. Possession of a license file, source delivery, package
128
+ copy, or modified runtime does not by itself authorize watermark removal.
129
+
130
+ 7. Ownership and reservation of rights
131
+
132
+ Flyfish and its licensors retain all title, ownership, copyright, patent,
133
+ trade-secret, trademark, and other intellectual-property rights in the Public
134
+ Package. No right is granted by implication, estoppel, exhaustion, or otherwise.
135
+ All rights not expressly granted are reserved.
136
+
137
+ Third-party components, if expressly identified in accompanying notices, remain
138
+ subject to their respective licenses solely for those identified components.
139
+ No third-party notice expands the grant for Flyfish proprietary components.
140
+
141
+ 8. Updates and policy changes
142
+
143
+ Each version of the Public Package is governed by the LICENSE file shipped with
144
+ that version. Flyfish may offer later versions under revised terms. Continuing
145
+ to use an updated version constitutes acceptance of the terms shipped with that
146
+ updated version.
147
+
148
+ 9. Termination
149
+
150
+ This License terminates automatically and immediately upon breach. On
151
+ termination, You must stop all use and delete every copy under Your possession
152
+ or control. Sections 3 through 7 and 9 through 11 survive termination.
153
+ Termination does not limit any other remedy available to Flyfish.
154
+
155
+ 10. Disclaimer and limitation of liability
156
+
157
+ THE PUBLIC PACKAGE IS PROVIDED “AS IS” AND “AS AVAILABLE,” WITHOUT WARRANTIES OR
158
+ CONDITIONS OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING TITLE, NON-INFRINGEMENT,
159
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, ACCURACY, AVAILABILITY, OR
160
+ SECURITY. TO THE MAXIMUM EXTENT PERMITTED BY LAW, FLYFISH AND ITS LICENSORS WILL
161
+ NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY,
162
+ PUNITIVE, OR COMMERCIAL DAMAGES, OR FOR LOSS OF DATA, PROFITS, REVENUE, GOODWILL,
163
+ OR BUSINESS INTERRUPTION, ARISING FROM OR RELATED TO THE PUBLIC PACKAGE OR THIS
164
+ LICENSE.
165
+
166
+ 11. General
167
+
168
+ This License is the complete agreement for the Public Package unless You and
169
+ Flyfish have signed a separate written agreement that expressly governs the
170
+ same use. If a provision is unenforceable, it will be limited to the minimum
171
+ extent necessary and the remaining provisions will continue in effect. A waiver
172
+ must be in writing and applies only to the stated instance. You may not assign
173
+ this License. Headings are for convenience only.
174
+
175
+ 12. Contact
176
+
177
+ Commercial licensing: https://dev.flyfish.group/shop
178
+ Support email: wybaby168@gmail.com
179
+
180
+ 中文摘要(仅便于阅读;如与英文条款冲突,以英文条款为准)
181
+
182
+ - 本 npm 公网包是 Flyfish 专有二进制发行版,不是开源软件,也不适用
183
+ Apache-2.0。单独向特定源码客户交付的 Apache-2.0 条款,仅适用于该次交付中
184
+ 明确列出的源码和范围,不会扩展到本公网 npm 包。
185
+ - 免费授权对象仅为以个人身份行事的自然人,且仅限个人、非商用、非组织用途;
186
+ 公司、组织、政府、学校、非营利机构、团队、雇主或客户的内部评估也属于商用。
187
+ - 公网水印版不限制正常 HTTP/HTTPS origin,但每一页必须完整显示
188
+ Flyfish Viewer 水印。不得删除、遮挡、裁剪、弱化或替换水印。
189
+ - 不得再分发、镜像、转售、重打包、修改、反编译、解密、提取、伪造授权或绕过
190
+ WASM、完整性校验、功能限制及其他技术保护措施。
191
+ - 在免费授权范围内,仅为运行本人项目而进行必要的前端打包、压缩和静态资源部署
192
+ 是允许的,但不得将本包作为可复用依赖、镜像、独立下载、API 或服务向第三方
193
+ 提供,并且必须完整保留许可证声明、完整性保护和水印。
194
+ - 商业、生产、内网、SaaS、托管、嵌入、OEM、客户项目、收费或其他业务用途,
195
+ 必须先购买单独商业授权;只有单独构建的商业包可以不显示公网水印。
196
+ - 商业授权购买地址:https://dev.flyfish.group/shop
package/NOTICE ADDED
@@ -0,0 +1,232 @@
1
+ @file-viewer/ppt
2
+ Copyright 2026 Flyfish.
3
+
4
+ PROPRIETARY PUBLIC BINARY DISTRIBUTION — NOT OPEN SOURCE
5
+
6
+ This npm package is governed only by the included Flyfish Public Watermarked
7
+ Binary License. It is not licensed under Apache-2.0. Apache-2.0 terms supplied
8
+ under a separate written source-code delivery apply only to the files and scope
9
+ expressly identified in that separate delivery and do not extend to this npm
10
+ package.
11
+
12
+ Free use is limited to an individual natural person acting solely in a personal,
13
+ non-commercial, non-organizational capacity. Use by or for any company,
14
+ organization, government body, school, nonprofit, team, employer, customer, or
15
+ client requires a purchased commercial license.
16
+
17
+ Every public rendering must display the unmodified Flyfish Viewer watermark.
18
+ Only a separately purchased and separately built commercial package may omit
19
+ that watermark.
20
+
21
+ This package contains a native PPT parsing and Canvas rasterization WebAssembly
22
+ runtime plus generated public declarations. It does not include a customer
23
+ runtime license, license-signing secret, commercial watermark-removal
24
+ capability, source-delivery rights, or readable parser/renderer source.
25
+
26
+ Commercial licensing: https://dev.flyfish.group/shop
27
+
28
+ The native engine embeds deterministic fallback fonts. Their copyright notices
29
+ and full font licenses are appended to this NOTICE in the published package.
30
+
31
+ THIRD-PARTY FONT NOTICES
32
+
33
+ Liberation Sans Regular
34
+ Digitized data copyright (c) 2010 Google Corporation; Copyright (c) 2012 Red Hat, Inc.
35
+ Licensed under the SIL Open Font License 1.1:
36
+ Digitized data copyright (c) 2010 Google Corporation
37
+ with Reserved Font Arimo, Tinos and Cousine.
38
+ Copyright (c) 2012 Red Hat, Inc.
39
+ with Reserved Font Name Liberation.
40
+
41
+ This Font Software is licensed under the SIL Open Font License,
42
+ Version 1.1.
43
+
44
+ This license is copied below, and is also available with a FAQ at:
45
+ http://scripts.sil.org/OFL
46
+
47
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
48
+
49
+ PREAMBLE The goals of the Open Font License (OFL) are to stimulate
50
+ worldwide development of collaborative font projects, to support the font
51
+ creation efforts of academic and linguistic communities, and to provide
52
+ a free and open framework in which fonts may be shared and improved in
53
+ partnership with others.
54
+
55
+ The OFL allows the licensed fonts to be used, studied, modified and
56
+ redistributed freely as long as they are not sold by themselves.
57
+ The fonts, including any derivative works, can be bundled, embedded,
58
+ redistributed and/or sold with any software provided that any reserved
59
+ names are not used by derivative works. The fonts and derivatives,
60
+ however, cannot be released under any other type of license. The
61
+ requirement for fonts to remain under this license does not apply to
62
+ any document created using the fonts or their derivatives.
63
+
64
+
65
+
66
+ DEFINITIONS
67
+ "Font Software" refers to the set of files released by the Copyright
68
+ Holder(s) under this license and clearly marked as such.
69
+ This may include source files, build scripts and documentation.
70
+
71
+ "Reserved Font Name" refers to any names specified as such after the
72
+ copyright statement(s).
73
+
74
+ "Original Version" refers to the collection of Font Software components
75
+ as distributed by the Copyright Holder(s).
76
+
77
+ "Modified Version" refers to any derivative made by adding to, deleting,
78
+ or substituting ? in part or in whole ?
79
+ any of the components of the Original Version, by changing formats or
80
+ by porting the Font Software to a new environment.
81
+
82
+ "Author" refers to any designer, engineer, programmer, technical writer
83
+ or other person who contributed to the Font Software.
84
+
85
+
86
+ PERMISSION & CONDITIONS
87
+
88
+ Permission is hereby granted, free of charge, to any person obtaining a
89
+ copy of the Font Software, to use, study, copy, merge, embed, modify,
90
+ redistribute, and sell modified and unmodified copies of the Font
91
+ Software, subject to the following conditions:
92
+
93
+ 1) Neither the Font Software nor any of its individual components,in
94
+ Original or Modified Versions, may be sold by itself.
95
+
96
+ 2) Original or Modified Versions of the Font Software may be bundled,
97
+ redistributed and/or sold with any software, provided that each copy
98
+ contains the above copyright notice and this license. These can be
99
+ included either as stand-alone text files, human-readable headers or
100
+ in the appropriate machine-readable metadata fields within text or
101
+ binary files as long as those fields can be easily viewed by the user.
102
+
103
+ 3) No Modified Version of the Font Software may use the Reserved Font
104
+ Name(s) unless explicit written permission is granted by the
105
+ corresponding Copyright Holder. This restriction only applies to the
106
+ primary font name as presented to the users.
107
+
108
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
109
+ Software shall not be used to promote, endorse or advertise any
110
+ Modified Version, except to acknowledge the contribution(s) of the
111
+ Copyright Holder(s) and the Author(s) or with their explicit written
112
+ permission.
113
+
114
+ 5) The Font Software, modified or unmodified, in part or in whole, must
115
+ be distributed entirely under this license, and must not be distributed
116
+ under any other license. The requirement for fonts to remain under
117
+ this license does not apply to any document created using the Font
118
+ Software.
119
+
120
+
121
+
122
+ TERMINATION
123
+ This license becomes null and void if any of the above conditions are not met.
124
+
125
+
126
+
127
+ DISCLAIMER
128
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
129
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
130
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
131
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
132
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
133
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
134
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
135
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
136
+ DEALINGS IN THE FONT SOFTWARE.
137
+
138
+ Noto Sans CJK SC Regular
139
+ Copyright 2014-2021 Adobe. Noto is a trademark of Google Inc.
140
+ Licensed under the SIL Open Font License 1.1:
141
+ This Font Software is licensed under the SIL Open Font License,
142
+ Version 1.1.
143
+
144
+ This license is copied below, and is also available with a FAQ at:
145
+ http://scripts.sil.org/OFL
146
+
147
+ -----------------------------------------------------------
148
+ SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
149
+ -----------------------------------------------------------
150
+
151
+ PREAMBLE
152
+ The goals of the Open Font License (OFL) are to stimulate worldwide
153
+ development of collaborative font projects, to support the font
154
+ creation efforts of academic and linguistic communities, and to
155
+ provide a free and open framework in which fonts may be shared and
156
+ improved in partnership with others.
157
+
158
+ The OFL allows the licensed fonts to be used, studied, modified and
159
+ redistributed freely as long as they are not sold by themselves. The
160
+ fonts, including any derivative works, can be bundled, embedded,
161
+ redistributed and/or sold with any software provided that any reserved
162
+ names are not used by derivative works. The fonts and derivatives,
163
+ however, cannot be released under any other type of license. The
164
+ requirement for fonts to remain under this license does not apply to
165
+ any document created using the fonts or their derivatives.
166
+
167
+ DEFINITIONS
168
+ "Font Software" refers to the set of files released by the Copyright
169
+ Holder(s) under this license and clearly marked as such. This may
170
+ include source files, build scripts and documentation.
171
+
172
+ "Reserved Font Name" refers to any names specified as such after the
173
+ copyright statement(s).
174
+
175
+ "Original Version" refers to the collection of Font Software
176
+ components as distributed by the Copyright Holder(s).
177
+
178
+ "Modified Version" refers to any derivative made by adding to,
179
+ deleting, or substituting -- in part or in whole -- any of the
180
+ components of the Original Version, by changing formats or by porting
181
+ the Font Software to a new environment.
182
+
183
+ "Author" refers to any designer, engineer, programmer, technical
184
+ writer or other person who contributed to the Font Software.
185
+
186
+ PERMISSION & CONDITIONS
187
+ Permission is hereby granted, free of charge, to any person obtaining
188
+ a copy of the Font Software, to use, study, copy, merge, embed,
189
+ modify, redistribute, and sell modified and unmodified copies of the
190
+ Font Software, subject to the following conditions:
191
+
192
+ 1) Neither the Font Software nor any of its individual components, in
193
+ Original or Modified Versions, may be sold by itself.
194
+
195
+ 2) Original or Modified Versions of the Font Software may be bundled,
196
+ redistributed and/or sold with any software, provided that each copy
197
+ contains the above copyright notice and this license. These can be
198
+ included either as stand-alone text files, human-readable headers or
199
+ in the appropriate machine-readable metadata fields within text or
200
+ binary files as long as those fields can be easily viewed by the user.
201
+
202
+ 3) No Modified Version of the Font Software may use the Reserved Font
203
+ Name(s) unless explicit written permission is granted by the
204
+ corresponding Copyright Holder. This restriction only applies to the
205
+ primary font name as presented to the users.
206
+
207
+ 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
208
+ Software shall not be used to promote, endorse or advertise any
209
+ Modified Version, except to acknowledge the contribution(s) of the
210
+ Copyright Holder(s) and the Author(s) or with their explicit written
211
+ permission.
212
+
213
+ 5) The Font Software, modified or unmodified, in part or in whole,
214
+ must be distributed entirely under this license, and must not be
215
+ distributed under any other license. The requirement for fonts to
216
+ remain under this license does not apply to any document created using
217
+ the Font Software.
218
+
219
+ TERMINATION
220
+ This license becomes null and void if any of the above conditions are
221
+ not met.
222
+
223
+ DISCLAIMER
224
+ THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
225
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
226
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
227
+ OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
228
+ COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
229
+ INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
230
+ DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
231
+ FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
232
+ OTHER DEALINGS IN THE FONT SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # @file-viewer/ppt
2
+
3
+ > Professional browser preview for PowerPoint 97–2003 (`.ppt`), powered by native WebAssembly and Canvas.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/%40file-viewer%2Fppt.svg)](https://www.npmjs.com/package/@file-viewer/ppt)
6
+ [![format](https://img.shields.io/badge/format-PowerPoint%2097--2003-c43e1c.svg)](#format-scope)
7
+ [![license](https://img.shields.io/badge/license-proprietary-334155.svg)](./LICENSE)
8
+
9
+ [English](#english) · [简体中文](#简体中文)
10
+
11
+ ## English
12
+
13
+ ### A professional viewer for traditional PowerPoint files
14
+
15
+ `@file-viewer/ppt` is Flyfish's independently developed preview engine for the
16
+ PowerPoint 97–2003 binary (`.ppt`) format. It reconstructs slides directly in a
17
+ modern browser without Microsoft Office, LibreOffice, browser plug-ins, or a
18
+ server-side conversion service.
19
+
20
+ The product is designed for document platforms, archives, knowledge systems,
21
+ intranets, SaaS applications, and web products that still need dependable
22
+ access to traditional PowerPoint files.
23
+
24
+ ### Product highlights
25
+
26
+ - **Native `.ppt` understanding** — Reads the classic PowerPoint compound-file,
27
+ persist-record, text, drawing, and picture structures directly.
28
+ - **Professional slide reconstruction** — Handles slide size, masters,
29
+ backgrounds, color schemes, text formatting, adjustable OfficeArt shapes,
30
+ fills, gradients, bounded legacy 3-D extrusion, grouped objects, pictures,
31
+ transforms, and layer order.
32
+ - **Native WASM Canvas pipeline** — Parsing, layout, rasterization, and public
33
+ watermark composition run in one WebAssembly engine. JavaScript presents the
34
+ engine's final RGBA frames with Canvas.
35
+ - **Local document processing** — The public runtime does not require documents
36
+ to be uploaded to a conversion service.
37
+ - **Verified engine asset** — The loader validates the exact native WASM
38
+ SHA-256 before execution.
39
+ - **Straightforward integration** — ESM, TypeScript declarations, no runtime
40
+ JavaScript dependencies, and support for both complete-viewer mounting and
41
+ individual-slide rendering.
42
+
43
+ ### Format scope
44
+
45
+ This package previews PowerPoint 97–2003 binary `.ppt` files. For XML-based
46
+ `.pptx` files, use a dedicated PPTX viewer.
47
+
48
+ ### Installation
49
+
50
+ ```bash
51
+ npm install @file-viewer/ppt
52
+ ```
53
+
54
+ ### Quick start
55
+
56
+ ```html
57
+ <input id="ppt-file" type="file" accept=".ppt,application/vnd.ms-powerpoint">
58
+ <div id="ppt-viewer"></div>
59
+ ```
60
+
61
+ ```js
62
+ import { createPptViewer } from '@file-viewer/ppt';
63
+
64
+ const viewer = await createPptViewer();
65
+ const input = document.querySelector('#ppt-file');
66
+
67
+ input.addEventListener('change', async () => {
68
+ const file = input.files?.[0];
69
+ if (!file) return;
70
+
71
+ await viewer.mount('#ppt-viewer', await file.arrayBuffer(), {
72
+ scale: 1,
73
+ pixelRatio: window.devicePixelRatio
74
+ });
75
+ });
76
+ ```
77
+
78
+ `mount()` creates one Canvas per slide and renders progressively. No license
79
+ file or origin registration is required for the public watermarked edition.
80
+
81
+ ### Render one slide
82
+
83
+ ```js
84
+ const response = await fetch('/documents/presentation.ppt');
85
+ const pptDocument = viewer.open(await response.arrayBuffer());
86
+
87
+ const canvas = document.querySelector('canvas');
88
+ pptDocument.renderSlide(0, canvas, { scale: 1.25 });
89
+
90
+ console.log(pptDocument.slideCount, pptDocument.width, pptDocument.height);
91
+ pptDocument.close();
92
+ ```
93
+
94
+ Close documents when they are no longer needed so their native memory can be
95
+ released immediately.
96
+
97
+ ### Core API
98
+
99
+ | API | Purpose |
100
+ | --- | --- |
101
+ | `createPptViewer()` / `loadPptViewer()` | Loads and verifies the native viewer engine |
102
+ | `viewer.mount(target, input, options)` | Renders the complete presentation into Canvas elements |
103
+ | `viewer.open(input)` | Opens a `.ppt` document and returns an opaque document handle |
104
+ | `document.renderSlide(index, canvas, options)` | Renders one final RGBA slide frame to Canvas |
105
+ | `document.close()` | Releases native document memory |
106
+ | `getPptPackageManifest()` | Returns package and edition metadata |
107
+
108
+ All public APIs include TypeScript declarations. Parsed document models,
109
+ records, HTML, SVG, drawing command streams, and unwatermarked frames are not
110
+ part of the public API.
111
+
112
+ ### Browser and deployment requirements
113
+
114
+ - A current browser with ES modules, WebAssembly, Web Crypto, `fetch`, and Canvas 2D
115
+ - Static hosting or a bundler that emits `ppt-native.wasm` beside `index.mjs`
116
+ - `application/wasm` MIME type for `.wasm` assets
117
+ - CSP permission to load the package's own module and WASM asset, including
118
+ `'wasm-unsafe-eval'` where required by the browser
119
+ - Normal HTTP or HTTPS hosting; the public edition does not restrict origin
120
+
121
+ ### Compatibility notes
122
+
123
+ Traditional PowerPoint files may contain macros, ActiveX controls, OLE objects,
124
+ linked media, or host-specific behaviors that browsers cannot execute. These
125
+ features are treated as non-executable preview content. Font substitution may
126
+ be used when an original document font is not available in the viewer's
127
+ embedded fallback set.
128
+
129
+ ### Editions and licensing
130
+
131
+ | Edition | Permitted use | Watermark | Origin |
132
+ | --- | --- | --- | --- |
133
+ | Public npm edition | Individual personal, non-commercial, non-organizational use | Mandatory `Flyfish Viewer` on every slide | Any normal HTTP/HTTPS origin |
134
+ | Commercial edition | Licensed company, organization, customer project, intranet, SaaS, OEM, or production use | Watermark-free build available according to the purchased agreement | According to the commercial agreement |
135
+
136
+ **Commercial use requires a purchased license.** Use by or for a company,
137
+ organization, government body, school, nonprofit, team, employer, customer, or
138
+ client—including internal evaluation—is commercial use.
139
+
140
+ The public npm edition is proprietary software and is **not licensed under
141
+ Apache-2.0**. Removing, hiding, covering, replacing, or bypassing the required
142
+ watermark is prohibited. See [LICENSE](./LICENSE) for the binding terms.
143
+
144
+ Purchase a commercial license from the
145
+ [Flyfish Shop](https://dev.flyfish.group/shop).
146
+
147
+ ### Product links
148
+
149
+ - [Documentation](https://officejs-doc.pages.dev)
150
+ - [Commercial licensing](https://dev.flyfish.group/shop)
151
+ - [Issue tracker](https://github.com/flyfish-dev/office-preview-js/issues)
152
+
153
+ ## 简体中文
154
+
155
+ ### 专业传统 PPT 浏览器预览引擎
156
+
157
+ `@file-viewer/ppt` 是 Flyfish 纯自研的 PowerPoint 97–2003 二进制 `.ppt`
158
+ 专业预览引擎。它直接理解传统 PPT 文件结构,并在现代浏览器中重建幻灯片,无需
159
+ 安装 Microsoft Office、LibreOffice、浏览器插件,也不依赖服务端格式转换。
160
+
161
+ 产品适用于文件预览平台、档案与知识管理系统、企业内网、SaaS 产品,以及仍需
162
+ 稳定支持传统 PowerPoint 文档的 Web 应用。
163
+
164
+ ### 产品特点
165
+
166
+ - **原生理解 `.ppt`**:直接读取复合文件、持久化记录、文字、绘图和图片结构。
167
+ - **专业幻灯片还原**:支持页面尺寸、母版、背景、配色、文字格式、可调节
168
+ OfficeArt 形状、填充、渐变、受限的传统 3D 挤出、组合对象、图片、旋转变换
169
+ 和图层顺序。
170
+ - **原生 WASM Canvas 链路**:解析、布局、光栅化和公网水印合成全部在同一个
171
+ WebAssembly 引擎内完成;JavaScript 只将最终 RGBA 画面提交给 Canvas。
172
+ - **文档本地处理**:公网运行时不要求将文档上传到第三方转换服务。
173
+ - **引擎完整性校验**:执行前自动校验原生 WASM 的精确 SHA-256。
174
+ - **易于集成**:提供 ESM、TypeScript 类型,无 JavaScript 运行时依赖;既可
175
+ 挂载完整预览器,也可单独渲染指定页。
176
+
177
+ ### 格式范围
178
+
179
+ 本包专门预览 PowerPoint 97–2003 二进制 `.ppt` 文件。XML 格式的 `.pptx`
180
+ 应使用专用 PPTX 预览器。
181
+
182
+ ### 安装
183
+
184
+ ```bash
185
+ npm install @file-viewer/ppt
186
+ ```
187
+
188
+ ### 快速开始
189
+
190
+ ```html
191
+ <input id="ppt-file" type="file" accept=".ppt,application/vnd.ms-powerpoint">
192
+ <div id="ppt-viewer"></div>
193
+ ```
194
+
195
+ ```js
196
+ import { createPptViewer } from '@file-viewer/ppt';
197
+
198
+ const viewer = await createPptViewer();
199
+ const input = document.querySelector('#ppt-file');
200
+
201
+ input.addEventListener('change', async () => {
202
+ const file = input.files?.[0];
203
+ if (!file) return;
204
+
205
+ await viewer.mount('#ppt-viewer', await file.arrayBuffer(), {
206
+ scale: 1,
207
+ pixelRatio: window.devicePixelRatio
208
+ });
209
+ });
210
+ ```
211
+
212
+ `mount()` 会为每一页创建 Canvas 并渐进渲染。公网水印版不需要 license 文件,
213
+ 也不限制正常 HTTP/HTTPS origin。
214
+
215
+ ### 单页渲染
216
+
217
+ ```js
218
+ const response = await fetch('/documents/presentation.ppt');
219
+ const pptDocument = viewer.open(await response.arrayBuffer());
220
+
221
+ const canvas = document.querySelector('canvas');
222
+ pptDocument.renderSlide(0, canvas, { scale: 1.25 });
223
+
224
+ console.log(pptDocument.slideCount, pptDocument.width, pptDocument.height);
225
+ pptDocument.close();
226
+ ```
227
+
228
+ 文档不再使用时请调用 `close()`,以便立即释放原生内存。
229
+
230
+ ### 核心 API
231
+
232
+ | API | 用途 |
233
+ | --- | --- |
234
+ | `createPptViewer()` / `loadPptViewer()` | 加载并校验原生预览引擎 |
235
+ | `viewer.mount(target, input, options)` | 将完整演示文稿渲染为 Canvas 列表 |
236
+ | `viewer.open(input)` | 打开 `.ppt` 并返回不透明文档句柄 |
237
+ | `document.renderSlide(index, canvas, options)` | 将单页最终 RGBA 画面渲染到 Canvas |
238
+ | `document.close()` | 释放原生文档内存 |
239
+ | `getPptPackageManifest()` | 返回包与版本信息 |
240
+
241
+ 所有公开 API 均提供 TypeScript 类型。解析后的文档模型、记录、HTML、SVG、
242
+ 绘图指令流和无水印画面均不属于公开 API。
243
+
244
+ ### 浏览器与部署要求
245
+
246
+ - 支持 ES Modules、WebAssembly、Web Crypto、`fetch` 和 Canvas 2D 的现代浏览器
247
+ - 能将 `ppt-native.wasm` 与 `index.mjs` 一同发布的静态服务器或打包工具
248
+ - 为 `.wasm` 配置 `application/wasm` MIME 类型
249
+ - CSP 允许加载包自身的模块和 WASM 资源;浏览器要求时需允许
250
+ `'wasm-unsafe-eval'`
251
+ - 使用正常 HTTP 或 HTTPS 部署;公网版不限制 origin
252
+
253
+ ### 兼容性说明
254
+
255
+ 传统 PPT 可能包含宏、ActiveX、OLE、链接媒体或依赖桌面宿主的行为,浏览器无法
256
+ 执行这些能力;预览器会把它们作为不可执行内容安全处理。原始字体不在内置回退
257
+ 字体集时,会使用确定性的字体替代。
258
+
259
+ ### 版本与授权
260
+
261
+ | 版本 | 允许用途 | 水印 | Origin |
262
+ | --- | --- | --- | --- |
263
+ | 公网 npm 版 | 自然人个人、非商业、非组织用途 | 每页强制显示 `Flyfish Viewer` | 任意正常 HTTP/HTTPS origin |
264
+ | 商业版 | 已授权的公司、组织、客户项目、内网、SaaS、OEM 或生产用途 | 按商业协议提供无公网水印构建 | 按商业协议执行 |
265
+
266
+ **任何商业用途均需购买授权。** 公司、组织、政府、学校、非营利机构、团队、
267
+ 雇主、客户或委托项目的使用,包括内部评估,均属于商业用途。
268
+
269
+ 公网 npm 版是专有软件,**不适用 Apache-2.0**。禁止删除、隐藏、遮挡、替换或
270
+ 绕过强制水印。具有法律约束力的完整条款见 [LICENSE](./LICENSE)。
271
+
272
+ 商业授权请前往 [Flyfish 商店](https://dev.flyfish.group/shop)购买。
273
+
274
+ ### 产品链接
275
+
276
+ - [产品文档](https://officejs-doc.pages.dev)
277
+ - [商业授权](https://dev.flyfish.group/shop)
278
+ - [问题反馈](https://github.com/flyfish-dev/office-preview-js/issues)
package/index.d.ts ADDED
@@ -0,0 +1,110 @@
1
+ export interface PptPackageManifest {
2
+ kind: 'flyfish-ppt-public-native-wasm-v1';
3
+ product: 'Flyfish PPT Viewer';
4
+ format: 'PowerPoint 97-2003 (.ppt)';
5
+ packageName: '@file-viewer/ppt';
6
+ packageVersion: string;
7
+ engine: 'flyfish-classic-ppt-native-engine';
8
+ engineBuild: string;
9
+ id: 'FV-PPT-PUBLIC-WATERMARKED-V2';
10
+ feature: 'ppt';
11
+ edition: 'public-watermarked';
12
+ holder: 'Individual Personal Non-Commercial Use';
13
+ distribution: 'proprietary-public-binary';
14
+ commercialUse: false;
15
+ publicAnyOrigin: true;
16
+ watermarkRequired: true;
17
+ watermarkText: 'Flyfish Viewer';
18
+ usePolicy: 'public-individual-noncommercial-watermarked';
19
+ licensePolicy: 'flyfish-public-watermarked-binary-license-v1';
20
+ sourceCodeRights: false;
21
+ sourceDeliveryRights: false;
22
+ apacheLicenseApplies: false;
23
+ redistributionAllowed: false;
24
+ runtimeLicenseRequired: false;
25
+ renderer: 'native-wasm-rgba-canvas';
26
+ integrity: 'native-wasm-sha256-v1';
27
+ wasmFile: 'ppt-native.wasm';
28
+ watermarkEnforcement: 'native-final-frame';
29
+ wasmSha256: string;
30
+ }
31
+
32
+ export interface PptRuntimeLicenseSummary {
33
+ readonly id: 'FV-PPT-PUBLIC-WATERMARKED-V2';
34
+ readonly edition: 'public-watermarked';
35
+ readonly holder: 'Individual Personal Non-Commercial Use';
36
+ readonly policy: 'flyfish-public-watermarked-binary-license-v1';
37
+ readonly commercialUse: false;
38
+ readonly sourceCodeRights: false;
39
+ readonly sourceDeliveryRights: false;
40
+ readonly apacheLicenseApplies: false;
41
+ readonly redistributionAllowed: false;
42
+ }
43
+
44
+ export interface PptWatermarkSummary {
45
+ readonly required: true;
46
+ readonly text: 'Flyfish Viewer';
47
+ }
48
+
49
+ export interface PptRenderOptions {
50
+ /** CSS size multiplier. Defaults to 1. */
51
+ scale?: number;
52
+ /** Raster density. Defaults to devicePixelRatio in browsers and 1 elsewhere. */
53
+ pixelRatio?: number;
54
+ }
55
+
56
+ export interface PptMountOptions extends PptRenderOptions {
57
+ /** Replace existing children of the target. Defaults to true. */
58
+ replace?: boolean;
59
+ /** Optional class name for the generated viewer root. */
60
+ className?: string;
61
+ }
62
+
63
+ export interface PptRenderResult {
64
+ readonly slideIndex: number;
65
+ readonly width: number;
66
+ readonly height: number;
67
+ readonly logicalWidth: number;
68
+ readonly logicalHeight: number;
69
+ readonly scale: number;
70
+ readonly pixelRatio: number;
71
+ }
72
+
73
+ export interface PptDocument {
74
+ readonly slideCount: number;
75
+ readonly width: number;
76
+ readonly height: number;
77
+ readonly closed: boolean;
78
+ renderSlide(
79
+ slideIndex: number,
80
+ canvas: HTMLCanvasElement | OffscreenCanvas,
81
+ options?: PptRenderOptions
82
+ ): PptRenderResult;
83
+ close(): void;
84
+ }
85
+
86
+ export interface MountedPptViewer {
87
+ readonly document: PptDocument;
88
+ readonly root: HTMLElement;
89
+ readonly canvases: readonly HTMLCanvasElement[];
90
+ close(): void;
91
+ }
92
+
93
+ export interface LoadPptViewerOptions {
94
+ wasmUrl?: string | URL | Response | ArrayBuffer | Uint8Array;
95
+ }
96
+
97
+ export interface PptViewerRuntime {
98
+ readonly license: Readonly<PptRuntimeLicenseSummary>;
99
+ readonly watermark: Readonly<PptWatermarkSummary>;
100
+ open(input: ArrayBuffer | Uint8Array): PptDocument;
101
+ mount(
102
+ target: string | HTMLElement,
103
+ input: ArrayBuffer | Uint8Array,
104
+ options?: PptMountOptions
105
+ ): Promise<MountedPptViewer>;
106
+ }
107
+
108
+ export declare function getPptPackageManifest(): PptPackageManifest;
109
+ export declare function loadPptViewer(options?: LoadPptViewerOptions): Promise<PptViewerRuntime>;
110
+ export declare const createPptViewer: typeof loadPptViewer;
package/index.mjs ADDED
@@ -0,0 +1,325 @@
1
+ const MANIFEST = Object.freeze({"kind":"flyfish-ppt-public-native-wasm-v1","product":"Flyfish PPT Viewer","format":"PowerPoint 97-2003 (.ppt)","packageName":"@file-viewer/ppt","packageVersion":"0.2.0","engine":"flyfish-classic-ppt-native-engine","engineBuild":"ef5987a0a85b6103","id":"FV-PPT-PUBLIC-WATERMARKED-V2","feature":"ppt","edition":"public-watermarked","holder":"Individual Personal Non-Commercial Use","distribution":"proprietary-public-binary","commercialUse":false,"publicAnyOrigin":true,"watermarkRequired":true,"watermarkText":"Flyfish Viewer","usePolicy":"public-individual-noncommercial-watermarked","licensePolicy":"flyfish-public-watermarked-binary-license-v1","sourceCodeRights":false,"sourceDeliveryRights":false,"apacheLicenseApplies":false,"redistributionAllowed":false,"runtimeLicenseRequired":false,"renderer":"native-wasm-rgba-canvas","integrity":"native-wasm-sha256-v1","wasmFile":"ppt-native.wasm","watermarkEnforcement":"native-final-frame","wasmSha256":"ef5987a0a85b61034ea651a02a28d4582ad19a09610e9a5637dcf01136815a2e"});
2
+ const DEFAULT_WASM_URL = new URL('./ppt-native.wasm', import.meta.url);
3
+ const WASM_EXPORTS = Object.freeze([
4
+ 'memory',
5
+ 'ppt_input_alloc',
6
+ 'ppt_input_free',
7
+ 'ppt_document_open',
8
+ 'ppt_document_close',
9
+ 'ppt_slide_count',
10
+ 'ppt_slide_width',
11
+ 'ppt_slide_height',
12
+ 'ppt_render_slide_rgba',
13
+ 'ppt_frame_ptr',
14
+ 'ppt_frame_len',
15
+ 'ppt_frame_width',
16
+ 'ppt_frame_height',
17
+ 'ppt_frame_stride',
18
+ 'ppt_frame_free',
19
+ 'ppt_last_error_code'
20
+ ]);
21
+
22
+ const LICENSE = Object.freeze({
23
+ id: 'FV-PPT-PUBLIC-WATERMARKED-V2',
24
+ edition: 'public-watermarked',
25
+ holder: 'Individual Personal Non-Commercial Use',
26
+ policy: 'flyfish-public-watermarked-binary-license-v1',
27
+ commercialUse: false,
28
+ sourceCodeRights: false,
29
+ sourceDeliveryRights: false,
30
+ apacheLicenseApplies: false,
31
+ redistributionAllowed: false
32
+ });
33
+
34
+ const WATERMARK = Object.freeze({ required: true, text: 'Flyfish Viewer' });
35
+ let enginePromise;
36
+
37
+ export function getPptPackageManifest() {
38
+ return { ...MANIFEST };
39
+ }
40
+
41
+ export async function loadPptViewer(options = {}) {
42
+ const engine = await loadEngine(options.wasmUrl);
43
+ return createRuntime(engine);
44
+ }
45
+
46
+ export const createPptViewer = loadPptViewer;
47
+
48
+ async function loadEngine(wasmSource) {
49
+ if (wasmSource !== undefined) return instantiateEngine(wasmSource);
50
+ if (!enginePromise) {
51
+ enginePromise = instantiateEngine(DEFAULT_WASM_URL).catch((error) => {
52
+ enginePromise = undefined;
53
+ throw error;
54
+ });
55
+ }
56
+ return enginePromise;
57
+ }
58
+
59
+ async function instantiateEngine(source) {
60
+ const bytes = await loadWasmBytes(source);
61
+ await verifyWasmIntegrity(bytes);
62
+ const module = await WebAssembly.compile(bytes);
63
+ const imports = WebAssembly.Module.imports(module);
64
+ if (imports.length !== 0) {
65
+ throw packageError('wasm-imports-rejected', 'The PPT rendering engine must not import browser or host functions.');
66
+ }
67
+ const instance = await WebAssembly.instantiate(module, {});
68
+ validateEngine(instance.exports);
69
+ return Object.freeze({ module, exports: instance.exports });
70
+ }
71
+
72
+ async function verifyWasmIntegrity(bytes) {
73
+ const subtle = globalThis.crypto?.subtle;
74
+ if (!subtle || typeof subtle.digest !== 'function') {
75
+ throw packageError('wasm-integrity-unavailable', 'Web Crypto SHA-256 support is required to verify the PPT rendering engine.');
76
+ }
77
+ const digest = new Uint8Array(await subtle.digest('SHA-256', bytes));
78
+ const actual = Array.from(digest, (byte) => byte.toString(16).padStart(2, '0')).join('');
79
+ if (actual !== MANIFEST.wasmSha256) {
80
+ throw packageError('wasm-integrity-invalid', 'The PPT rendering engine failed its SHA-256 integrity check.');
81
+ }
82
+ }
83
+
84
+ async function loadWasmBytes(source) {
85
+ if (source instanceof WebAssembly.Module) {
86
+ throw packageError('wasm-module-unsupported', 'Pass a URL, Response, ArrayBuffer, or Uint8Array so the engine can be verified before use.');
87
+ }
88
+ if (source instanceof Uint8Array) return source.slice();
89
+ if (source instanceof ArrayBuffer) return new Uint8Array(source.slice(0));
90
+ if (typeof Response !== 'undefined' && source instanceof Response) {
91
+ if (!source.ok) throw packageError('wasm-request-failed', `The PPT rendering engine request failed with HTTP ${source.status}.`);
92
+ return new Uint8Array(await source.arrayBuffer());
93
+ }
94
+ const response = await fetch(source instanceof URL || typeof source === 'string' ? source : DEFAULT_WASM_URL);
95
+ if (!response.ok) throw packageError('wasm-request-failed', `The PPT rendering engine request failed with HTTP ${response.status}.`);
96
+ return new Uint8Array(await response.arrayBuffer());
97
+ }
98
+
99
+ function validateEngine(api) {
100
+ const actual = Object.keys(api).sort();
101
+ const expected = [...WASM_EXPORTS].sort();
102
+ if (actual.length !== expected.length || actual.some((name, index) => name !== expected[index])) {
103
+ throw packageError('wasm-abi-invalid', 'The PPT rendering engine has an unexpected public ABI.');
104
+ }
105
+ if (!(api.memory instanceof WebAssembly.Memory)) {
106
+ throw packageError('wasm-memory-invalid', 'The PPT rendering engine did not provide its bounded working memory.');
107
+ }
108
+ for (const name of WASM_EXPORTS) {
109
+ if (name !== 'memory' && typeof api[name] !== 'function') {
110
+ throw packageError('wasm-abi-invalid', `The PPT rendering engine is missing ${name}.`);
111
+ }
112
+ }
113
+ }
114
+
115
+ function createRuntime(engine) {
116
+ const api = engine.exports;
117
+ return Object.freeze({
118
+ license: LICENSE,
119
+ watermark: WATERMARK,
120
+ open(input) {
121
+ return openDocument(api, input);
122
+ },
123
+ async mount(target, input, options = {}) {
124
+ const document = openDocument(api, input);
125
+ try {
126
+ return await mountDocument(document, target, options);
127
+ } catch (error) {
128
+ document.close();
129
+ throw error;
130
+ }
131
+ }
132
+ });
133
+ }
134
+
135
+ function openDocument(api, input) {
136
+ const bytes = normalizeInput(input);
137
+ if (bytes.byteLength < 8 || !hasCfbSignature(bytes)) {
138
+ throw packageError('ppt-signature-invalid', 'Input is not a PowerPoint 97-2003 (.ppt) compound document.');
139
+ }
140
+ const pointer = Number(api.ppt_input_alloc(bytes.byteLength));
141
+ if (!pointer) throw engineError(api, 'Unable to allocate native input memory.');
142
+ let handle = 0;
143
+ try {
144
+ new Uint8Array(api.memory.buffer, pointer, bytes.byteLength).set(bytes);
145
+ handle = Number(api.ppt_document_open(pointer, bytes.byteLength));
146
+ } finally {
147
+ api.ppt_input_free(pointer, bytes.byteLength);
148
+ }
149
+ if (!handle) throw engineError(api, 'The native PPT parser rejected the document.');
150
+
151
+ const slideCount = Number(api.ppt_slide_count(handle));
152
+ const slideWidth = Number(api.ppt_slide_width(handle, 1000));
153
+ const slideHeight = Number(api.ppt_slide_height(handle, 1000));
154
+ if (!Number.isInteger(slideCount) || slideCount < 1 || slideCount > 10000
155
+ || !Number.isFinite(slideWidth) || slideWidth <= 0
156
+ || !Number.isFinite(slideHeight) || slideHeight <= 0) {
157
+ api.ppt_document_close(handle);
158
+ throw engineError(api, 'The native PPT parser returned invalid presentation dimensions.');
159
+ }
160
+
161
+ let closed = false;
162
+ const document = {
163
+ get slideCount() { return slideCount; },
164
+ get width() { return slideWidth; },
165
+ get height() { return slideHeight; },
166
+ get closed() { return closed; },
167
+ renderSlide(slideIndex, canvas, options = {}) {
168
+ if (closed) throw packageError('document-closed', 'The PPT document is already closed.');
169
+ return renderSlide(api, handle, slideCount, slideWidth, slideHeight, slideIndex, canvas, options);
170
+ },
171
+ close() {
172
+ if (!closed) {
173
+ closed = true;
174
+ if (Number(api.ppt_document_close(handle)) !== 1) throw engineError(api, 'Unable to close the native PPT document.');
175
+ }
176
+ }
177
+ };
178
+ return Object.freeze(document);
179
+ }
180
+
181
+ function renderSlide(api, documentHandle, slideCount, logicalWidth, logicalHeight, slideIndex, canvas, options) {
182
+ if (!Number.isInteger(slideIndex) || slideIndex < 0 || slideIndex >= slideCount) {
183
+ throw new RangeError(`slideIndex must be between 0 and ${slideCount - 1}.`);
184
+ }
185
+ if (!canvas || typeof canvas.getContext !== 'function') {
186
+ throw new TypeError('renderSlide requires an HTMLCanvasElement or OffscreenCanvas.');
187
+ }
188
+ const scale = finitePositive(options.scale, 1);
189
+ const pixelRatio = finitePositive(options.pixelRatio, defaultPixelRatio());
190
+ const nativeScale = scale * pixelRatio;
191
+ if (nativeScale < 0.1 || nativeScale > 8) {
192
+ throw new RangeError('scale * pixelRatio must be between 0.1 and 8.');
193
+ }
194
+ const scaleMilli = Math.round(nativeScale * 1000);
195
+ const pixelWidth = Number(api.ppt_slide_width(documentHandle, scaleMilli));
196
+ const pixelHeight = Number(api.ppt_slide_height(documentHandle, scaleMilli));
197
+ const frame = Number(api.ppt_render_slide_rgba(documentHandle, slideIndex, scaleMilli));
198
+ if (!frame) throw engineError(api, `Unable to render slide ${slideIndex + 1}.`);
199
+ try {
200
+ const width = Number(api.ppt_frame_width(frame));
201
+ const height = Number(api.ppt_frame_height(frame));
202
+ const stride = Number(api.ppt_frame_stride(frame));
203
+ const length = Number(api.ppt_frame_len(frame));
204
+ const pointer = Number(api.ppt_frame_ptr(frame));
205
+ if (width !== pixelWidth || height !== pixelHeight || stride !== width * 4 || length !== stride * height || !pointer) {
206
+ throw packageError('wasm-frame-invalid', 'The native PPT engine returned an invalid RGBA frame.');
207
+ }
208
+ const pixels = new Uint8ClampedArray(api.memory.buffer, pointer, length).slice();
209
+ canvas.width = width;
210
+ canvas.height = height;
211
+ if ('style' in canvas && canvas.style) {
212
+ canvas.style.width = `${Math.round(logicalWidth * scale)}px`;
213
+ canvas.style.maxWidth = '100%';
214
+ canvas.style.height = 'auto';
215
+ canvas.style.aspectRatio = `${width} / ${height}`;
216
+ canvas.style.display = 'block';
217
+ }
218
+ const context = canvas.getContext('2d', { alpha: false, desynchronized: false });
219
+ if (!context || typeof context.putImageData !== 'function') {
220
+ throw packageError('canvas-context-unavailable', 'A 2D Canvas context is required to display PPT slides.');
221
+ }
222
+ let imageData;
223
+ if (typeof ImageData === 'function') {
224
+ imageData = new ImageData(pixels, width, height);
225
+ } else {
226
+ imageData = context.createImageData(width, height);
227
+ imageData.data.set(pixels);
228
+ }
229
+ context.putImageData(imageData, 0, 0);
230
+ return Object.freeze({ slideIndex, width, height, logicalWidth, logicalHeight, scale, pixelRatio });
231
+ } finally {
232
+ api.ppt_frame_free(frame);
233
+ }
234
+ }
235
+
236
+ async function mountDocument(document, target, options) {
237
+ const container = resolveElement(target);
238
+ const root = documentRoot(container, options);
239
+ const canvases = [];
240
+ for (let slideIndex = 0; slideIndex < document.slideCount; slideIndex += 1) {
241
+ const canvas = documentCanvas(root, slideIndex);
242
+ document.renderSlide(slideIndex, canvas, options);
243
+ canvases.push(canvas);
244
+ if (slideIndex + 1 < document.slideCount) await yieldToBrowser();
245
+ }
246
+ return Object.freeze({
247
+ document,
248
+ root,
249
+ canvases: Object.freeze(canvases),
250
+ close() {
251
+ document.close();
252
+ root.remove();
253
+ }
254
+ });
255
+ }
256
+
257
+ function resolveElement(target) {
258
+ const element = typeof target === 'string' ? document.querySelector(target) : target;
259
+ if (!element || typeof element.append !== 'function') {
260
+ throw new TypeError('mount requires a DOM element or a selector that resolves to one.');
261
+ }
262
+ return element;
263
+ }
264
+
265
+ function documentRoot(container, options) {
266
+ if (options.replace !== false) container.replaceChildren();
267
+ const root = document.createElement('div');
268
+ root.className = options.className || 'flyfish-ppt-viewer';
269
+ root.dataset.flyfishPptEdition = 'public-watermarked';
270
+ root.style.cssText = 'display:grid;width:100%;min-width:0;justify-content:center;gap:20px;padding:20px;box-sizing:border-box;background:#eef1f5;';
271
+ container.append(root);
272
+ return root;
273
+ }
274
+
275
+ function documentCanvas(root, slideIndex) {
276
+ const shell = document.createElement('section');
277
+ shell.dataset.slideIndex = String(slideIndex);
278
+ shell.style.cssText = 'max-width:100%;min-width:0;overflow:hidden;background:#fff;box-shadow:0 8px 28px rgba(15,23,42,.14);';
279
+ const canvas = document.createElement('canvas');
280
+ canvas.setAttribute('role', 'img');
281
+ canvas.setAttribute('aria-label', `Slide ${slideIndex + 1}`);
282
+ shell.append(canvas);
283
+ root.append(shell);
284
+ return canvas;
285
+ }
286
+
287
+ function normalizeInput(input) {
288
+ if (input instanceof Uint8Array) return input;
289
+ if (input instanceof ArrayBuffer) return new Uint8Array(input);
290
+ if (ArrayBuffer.isView(input)) return new Uint8Array(input.buffer, input.byteOffset, input.byteLength);
291
+ throw new TypeError('PPT input must be an ArrayBuffer or Uint8Array.');
292
+ }
293
+
294
+ function hasCfbSignature(bytes) {
295
+ const signature = [0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1];
296
+ return signature.every((value, index) => bytes[index] === value);
297
+ }
298
+
299
+ function finitePositive(value, fallback) {
300
+ if (value === undefined) return fallback;
301
+ const number = Number(value);
302
+ if (!Number.isFinite(number) || number <= 0) throw new RangeError('Render scale and pixelRatio must be finite positive numbers.');
303
+ return number;
304
+ }
305
+
306
+ function defaultPixelRatio() {
307
+ return typeof devicePixelRatio === 'number' && Number.isFinite(devicePixelRatio) ? Math.max(1, devicePixelRatio) : 1;
308
+ }
309
+
310
+ function yieldToBrowser() {
311
+ if (typeof requestAnimationFrame === 'function') return new Promise((resolve) => requestAnimationFrame(() => resolve()));
312
+ return Promise.resolve();
313
+ }
314
+
315
+ function engineError(api, fallback) {
316
+ const code = Number(api.ppt_last_error_code()) || 0;
317
+ return packageError(`native-${code || 'unknown'}`, `${fallback} (native error ${code || 'unknown'})`);
318
+ }
319
+
320
+ function packageError(code, message) {
321
+ const error = new Error(message);
322
+ error.name = 'FlyfishPptError';
323
+ Object.defineProperty(error, 'code', { value: code, enumerable: true });
324
+ return error;
325
+ }
package/manifest.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "kind": "flyfish-ppt-public-native-wasm-v1",
3
+ "product": "Flyfish PPT Viewer",
4
+ "format": "PowerPoint 97-2003 (.ppt)",
5
+ "packageName": "@file-viewer/ppt",
6
+ "packageVersion": "0.2.0",
7
+ "engine": "flyfish-classic-ppt-native-engine",
8
+ "engineBuild": "ef5987a0a85b6103",
9
+ "id": "FV-PPT-PUBLIC-WATERMARKED-V2",
10
+ "feature": "ppt",
11
+ "edition": "public-watermarked",
12
+ "holder": "Individual Personal Non-Commercial Use",
13
+ "distribution": "proprietary-public-binary",
14
+ "commercialUse": false,
15
+ "publicAnyOrigin": true,
16
+ "watermarkRequired": true,
17
+ "watermarkText": "Flyfish Viewer",
18
+ "usePolicy": "public-individual-noncommercial-watermarked",
19
+ "licensePolicy": "flyfish-public-watermarked-binary-license-v1",
20
+ "sourceCodeRights": false,
21
+ "sourceDeliveryRights": false,
22
+ "apacheLicenseApplies": false,
23
+ "redistributionAllowed": false,
24
+ "runtimeLicenseRequired": false,
25
+ "renderer": "native-wasm-rgba-canvas",
26
+ "integrity": "native-wasm-sha256-v1",
27
+ "wasmFile": "ppt-native.wasm",
28
+ "watermarkEnforcement": "native-final-frame",
29
+ "wasmSha256": "ef5987a0a85b61034ea651a02a28d4582ad19a09610e9a5637dcf01136815a2e"
30
+ }
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@file-viewer/ppt",
3
+ "version": "0.2.0",
4
+ "description": "Professional native WebAssembly canvas viewer for PowerPoint 97-2003 (.ppt) files.",
5
+ "type": "module",
6
+ "main": "./index.mjs",
7
+ "module": "./index.mjs",
8
+ "types": "./index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./index.d.ts",
12
+ "import": "./index.mjs",
13
+ "default": "./index.mjs"
14
+ },
15
+ "./manifest.json": "./manifest.json",
16
+ "./ppt-native.wasm": "./ppt-native.wasm",
17
+ "./LICENSE": "./LICENSE"
18
+ },
19
+ "files": [
20
+ "LICENSE",
21
+ "NOTICE",
22
+ "README.md",
23
+ "index.d.ts",
24
+ "index.mjs",
25
+ "manifest.json",
26
+ "ppt-native.wasm"
27
+ ],
28
+ "sideEffects": false,
29
+ "license": "SEE LICENSE IN LICENSE",
30
+ "keywords": [
31
+ "ppt",
32
+ "powerpoint",
33
+ "viewer",
34
+ "preview",
35
+ "canvas",
36
+ "wasm",
37
+ "document"
38
+ ],
39
+ "homepage": "https://officejs-doc.pages.dev",
40
+ "bugs": {
41
+ "url": "https://github.com/flyfish-dev/office-preview-js/issues"
42
+ },
43
+ "engines": {
44
+ "node": ">=18"
45
+ },
46
+ "publishConfig": {
47
+ "access": "public",
48
+ "registry": "https://registry.npmjs.org/"
49
+ }
50
+ }
Binary file