@pptx-studio/cli 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/CHANGELOG.md +29 -0
- package/LICENSE +202 -0
- package/NOTICE +43 -0
- package/README.md +263 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +16 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +232 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/main-DLx2onii.js +1570 -0
- package/dist/main-DLx2onii.js.map +1 -0
- package/package.json +73 -0
- package/scripts/powerpoint-oracle.ps1 +162 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @pptx-studio/cli
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 7d905f4: First release.
|
|
8
|
+
|
|
9
|
+
`@pptx-studio/render-svg` turns a slide into an SVG string, and `pptx-studio render`
|
|
10
|
+
does it from the command line with no browser and no LibreOffice — text included,
|
|
11
|
+
measured out of the font's own tables. The other nine packages are what those two
|
|
12
|
+
are built on and are published because they have to be, not because their surface
|
|
13
|
+
is settled.
|
|
14
|
+
|
|
15
|
+
Everything here is pre-1.0 and the API will change. What will not change without a
|
|
16
|
+
very good reason is what the writer does to a package it was not asked to edit: a
|
|
17
|
+
part nobody touched is re-emitted byte for byte, across all 54 decks in the corpus.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [7d905f4]
|
|
22
|
+
- @pptx-studio/census@0.1.0
|
|
23
|
+
- @pptx-studio/model@0.1.0
|
|
24
|
+
- @pptx-studio/opc@0.1.0
|
|
25
|
+
- @pptx-studio/render-svg@0.1.0
|
|
26
|
+
- @pptx-studio/text@0.1.0
|
|
27
|
+
- @pptx-studio/validate@0.1.0
|
|
28
|
+
- @pptx-studio/writer@0.1.0
|
|
29
|
+
- @pptx-studio/xml@0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright 2026 Dewiride Technologies
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
PPTX Studio
|
|
2
|
+
Copyright 2026 Dewiride Technologies
|
|
3
|
+
|
|
4
|
+
This product includes software developed at Dewiride Technologies
|
|
5
|
+
(https://github.com/Dewiride-Open-Source/Dewiride-PPTX-Studio).
|
|
6
|
+
|
|
7
|
+
--------------------------------------------------------------------------------
|
|
8
|
+
Third-party material redistributed in this repository
|
|
9
|
+
--------------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
Entries are added here at the moment the material lands, not at release time.
|
|
12
|
+
|
|
13
|
+
* Apache POI
|
|
14
|
+
Copyright The Apache Software Foundation
|
|
15
|
+
Licensed under the Apache License, Version 2.0.
|
|
16
|
+
https://poi.apache.org/
|
|
17
|
+
|
|
18
|
+
@pptx-studio/geometry contains the 187 DrawingML preset shape definitions,
|
|
19
|
+
transcoded at build time from POI's presetShapeDefinitions.xml by
|
|
20
|
+
tools/geometry-codegen. The transcoded form is a re-encoding of that file's
|
|
21
|
+
content and carries POI's copyright.
|
|
22
|
+
|
|
23
|
+
The file itself is not redistributed in this repository. The generated
|
|
24
|
+
modules in packages/geometry/src/presets record the SHA-256 of the exact
|
|
25
|
+
input they were produced from:
|
|
26
|
+
|
|
27
|
+
presetShapeDefinitions.xml, 538970 bytes
|
|
28
|
+
sha256 4a762444d8d85876881c02a5b1dedf6f73006fcd8acb7b4e393435615b37c780
|
|
29
|
+
|
|
30
|
+
--------------------------------------------------------------------------------
|
|
31
|
+
Attributions the plan commits us to, listed so the obligation is visible before
|
|
32
|
+
the code arrives
|
|
33
|
+
--------------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
* Pattern fill tiles (sub-phase 2.7) are generated from Mono libgdiplus.
|
|
36
|
+
libgdiplus - Copyright Novell, Inc. and contributors - MIT
|
|
37
|
+
|
|
38
|
+
* Metric-compatible substitute fonts ship in a separate package,
|
|
39
|
+
@pptx-studio/fonts-metric-compat, under SIL OFL 1.1 with its own
|
|
40
|
+
OFL.txt and reserved-font-name handling. They are deliberately kept out
|
|
41
|
+
of this Apache-2.0 tree so the licence boundary is a package boundary.
|
|
42
|
+
|
|
43
|
+
See LEGAL.md for the clean-room record and the reimplementation basis.
|
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# @pptx-studio/cli
|
|
2
|
+
|
|
3
|
+
**Command line tools for PPTX packages.** As of sub-phase 3.10 that is five
|
|
4
|
+
verbs: `render`, which draws slides as SVG with no browser and no LibreOffice;
|
|
5
|
+
`inspect`, which reads a deck and tells you what is in it; `validate`, which
|
|
6
|
+
checks it against the twenty-nine rules a `.pptx` must not break; `roundtrip`,
|
|
7
|
+
which reads a deck, writes it back, and proves nothing moved; and `bisect`,
|
|
8
|
+
which narrows a broken deck down to the change that breaks it.
|
|
9
|
+
|
|
10
|
+
Apache-2.0 · part of
|
|
11
|
+
[PPTX Studio](https://github.com/Dewiride-Open-Source/Dewiride-PPTX-Studio).
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx @pptx-studio/cli render deck.pptx --out slides/
|
|
15
|
+
npx @pptx-studio/cli render deck.pptx --slide 1 --width 640 --out thumb.svg
|
|
16
|
+
npx @pptx-studio/cli render deck.pptx --json --font-dir ./fonts
|
|
17
|
+
|
|
18
|
+
npx @pptx-studio/cli inspect deck.pptx
|
|
19
|
+
npx @pptx-studio/cli inspect deck.pptx --parts --namespaces
|
|
20
|
+
npx @pptx-studio/cli inspect deck.pptx --json --out census.json
|
|
21
|
+
|
|
22
|
+
npx @pptx-studio/cli validate deck.pptx
|
|
23
|
+
npx @pptx-studio/cli validate deck.pptx --explain
|
|
24
|
+
|
|
25
|
+
npx @pptx-studio/cli roundtrip deck.pptx
|
|
26
|
+
npx @pptx-studio/cli roundtrip deck.pptx --write out.pptx
|
|
27
|
+
|
|
28
|
+
npx @pptx-studio/cli bisect deck.pptx
|
|
29
|
+
npx @pptx-studio/cli bisect original.pptx broken.pptx --oracle powerpoint
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
PACKAGE
|
|
34
|
+
=======
|
|
35
|
+
archive 188.5 MiB in 1616 entries
|
|
36
|
+
parts 995 (192.0 MiB inflated, 1.0:1 overall)
|
|
37
|
+
compression 1303 deflated, 313 stored
|
|
38
|
+
largest part /ppt/media/image1.png (639.5 KiB)
|
|
39
|
+
|
|
40
|
+
PRESENTATION
|
|
41
|
+
------------
|
|
42
|
+
slide size 13.33 x 7.50 in (screen16x9)
|
|
43
|
+
sheets 300 slides, 4 layouts, 1 masters
|
|
44
|
+
notes 300 notes slides, 1 notes masters, 0 handout masters
|
|
45
|
+
structure 6 sections, 2 custom shows
|
|
46
|
+
fonts embedTrueTypeFonts=true saveSubsetFonts=true
|
|
47
|
+
ProbeAlpha regular charset 0
|
|
48
|
+
|
|
49
|
+
FEATURES
|
|
50
|
+
--------
|
|
51
|
+
5194 Shapes phase 2.10
|
|
52
|
+
30 Tables phase 4.1
|
|
53
|
+
12 Charts phase 9.1
|
|
54
|
+
60 Animation timelines carried across, never rendered
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Exit status is **1** when the census found a structural error and **0**
|
|
58
|
+
otherwise. Warnings and notes never fail the command, so `inspect` answers
|
|
59
|
+
"did this deck load, and is anything in it structurally broken" as a yes/no
|
|
60
|
+
question a script can branch on.
|
|
61
|
+
|
|
62
|
+
## `validate`
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
/ppt/slides/slide1.xml
|
|
66
|
+
V022 fatal
|
|
67
|
+
/p:sld/p:cSld/p:spTree/p:sp/p:nvSpPr/p:nvPr/p:ph/@type
|
|
68
|
+
type="hdr" is a whole-package refusal here, alone and with no other change. …
|
|
69
|
+
|
|
70
|
+
V027 did not run: it compares against the package as it was opened, and none was supplied. …
|
|
71
|
+
|
|
72
|
+
validate: 26 rule(s), 1 finding(s), 1 blocking
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Exit status is **1** when anything fatal was found and **0** otherwise; a
|
|
76
|
+
warning never fails the command.
|
|
77
|
+
|
|
78
|
+
Three of the twenty-nine rules compare a package against the package **as it was
|
|
79
|
+
opened**, and a file on the command line has no such history. They are skipped,
|
|
80
|
+
and the report names them rather than counting them as passes. That makes
|
|
81
|
+
`validate` a diagnostic; the export gate is `assertValid`, which the writer calls
|
|
82
|
+
with both packages in hand.
|
|
83
|
+
|
|
84
|
+
| flag | what it does |
|
|
85
|
+
| ----------- | ---------------------------------------------- |
|
|
86
|
+
| `--json` | the report as JSON |
|
|
87
|
+
| `--explain` | append the rationale for every rule that fired |
|
|
88
|
+
| `--quiet` | fatal findings only |
|
|
89
|
+
| `--out` | write to a file instead of stdout |
|
|
90
|
+
|
|
91
|
+
## `roundtrip`
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
roundtrip deck.pptx
|
|
95
|
+
|
|
96
|
+
read 47048 bytes, 29 entries
|
|
97
|
+
written 47048 bytes, 29 entries
|
|
98
|
+
export 0 part(s) re-serialized, 28 streamed
|
|
99
|
+
compared 28/28 parts identical (19 xml, 9 rels, 0 binary)
|
|
100
|
+
|
|
101
|
+
no differences
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Exit status is **1** when the two packages differ — and also when the export was
|
|
105
|
+
refused, or the file would not open at all, because CI wants one bit. The three
|
|
106
|
+
are distinguished on stderr, since each needs completely different work next.
|
|
107
|
+
|
|
108
|
+
**It is not a byte comparison, and it must not become one.** Entry order,
|
|
109
|
+
deflate level, timestamps and attribute order all differ legitimately between two
|
|
110
|
+
archives holding the same document. Nine of the corpus's PowerPoint-authored
|
|
111
|
+
decks come out exactly 1832 bytes smaller than they went in — every stored byte
|
|
112
|
+
of every entry identical — because Office writes a `0xA220` growth-hint extra
|
|
113
|
+
field on five of their entries and we do not. A byte-equality gate would have
|
|
114
|
+
been red on ten of fifty-one decks before a line of the renderer existed, over
|
|
115
|
+
padding.
|
|
116
|
+
|
|
117
|
+
What is compared instead: the canonical XML of every XML part, the relationship
|
|
118
|
+
graph with ids treated as opaque labels, and the SHA-256 of everything else. So a
|
|
119
|
+
deck PowerPoint has re-saved — which renumbers every `rId` — still compares
|
|
120
|
+
equal, while one where two `r:embed` values swapped what they point at does not.
|
|
121
|
+
|
|
122
|
+
| flag | what it does |
|
|
123
|
+
| ---------------- | ---------------------------------------------- |
|
|
124
|
+
| `--json` | the comparison as JSON, with a digest per part |
|
|
125
|
+
| `--quiet` | the differences only, without the tally |
|
|
126
|
+
| `--write <file>` | also save the package that was written |
|
|
127
|
+
| `--out <file>` | write the report to a file instead of stdout |
|
|
128
|
+
|
|
129
|
+
`--write` is there for the check nothing in this repository can make: open the
|
|
130
|
+
result in real PowerPoint. `bisect --oracle powerpoint` scripts it.
|
|
131
|
+
|
|
132
|
+
## `bisect`
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
bisect deck.pptx # against our own export of it
|
|
136
|
+
bisect original.pptx broken.pptx # against a package from somewhere else
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The debugger for this project. PowerPoint's whole diagnostic channel is one
|
|
140
|
+
sentence naming no part, no element and no reason, so the only way to find out
|
|
141
|
+
what it objects to is to ask again with less of the change present, and keep
|
|
142
|
+
asking. This is delta debugging — Zeller's `ddmin` over the set of changes
|
|
143
|
+
between the two packages, applied level by level down the tree.
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
delta 135 change(s) in 7 entry(s)
|
|
147
|
+
oracle powerpoint, 5 run(s)
|
|
148
|
+
|
|
149
|
+
1 change(s) in 1 entry(s), from a delta of 135, in 5 oracle run(s)
|
|
150
|
+
|
|
151
|
+
removed /[Content_Types].xml /Types/Default[3]
|
|
152
|
+
- <Default Extension="fntdata" ContentType="application/x-fontdata"/>
|
|
153
|
+
+ (nothing)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
| flag | what it does |
|
|
157
|
+
| ----------------- | -------------------------------------------------- |
|
|
158
|
+
| `--oracle <name>` | `validate` (default), `powerpoint`, or `command` |
|
|
159
|
+
| `--command <cmd>` | for `--oracle command`; `{}` becomes the candidate |
|
|
160
|
+
| `--max-runs <n>` | ceiling on oracle runs (default 2000) |
|
|
161
|
+
| `--timeout <ms>` | per run, for the oracles that spawn something |
|
|
162
|
+
| `--progress` | a line per oracle run; a bisection is not quick |
|
|
163
|
+
| `--write <file>` | save the smallest package that still fails |
|
|
164
|
+
| `--json` | the result as JSON |
|
|
165
|
+
| `--out <file>` | write the report to a file instead of stdout |
|
|
166
|
+
|
|
167
|
+
**`--oracle powerpoint` opens each candidate with `OpenAndRepair` switched off,
|
|
168
|
+
and that is not a detail.** `Presentations.Open` has no repair parameter and
|
|
169
|
+
`Open2007` documents the default as on, while `DisplayAlerts` is documented to
|
|
170
|
+
answer a message box with its default — which for "PowerPoint found a problem
|
|
171
|
+
with content" is Repair. So the obvious script reports success on precisely the
|
|
172
|
+
files this project exists to avoid producing. Measured on one deck: with repair
|
|
173
|
+
off it fails with `0x80CB8002`; with repair on it opens, all three slides
|
|
174
|
+
intact.
|
|
175
|
+
|
|
176
|
+
The harness opens read-only with no window, writes nothing back, and disables
|
|
177
|
+
macros — `AutomationSecurity` defaults to _enabling_ them. If PowerPoint is
|
|
178
|
+
already running it attaches to that instance and never quits it.
|
|
179
|
+
|
|
180
|
+
## `inspect` options
|
|
181
|
+
|
|
182
|
+
| flag | what it does |
|
|
183
|
+
| -------------- | --------------------------------------------------------------- |
|
|
184
|
+
| `--json` | the census as JSON, for a script or for committing as a fixture |
|
|
185
|
+
| `--parts` | the per-part table: bytes, elements, depth, relationships |
|
|
186
|
+
| `--namespaces` | every namespace, with the prefixes it was spelled with |
|
|
187
|
+
| `--top <n>` | rows per histogram before truncating (default 15) |
|
|
188
|
+
| `--out <file>` | write to a file instead of stdout |
|
|
189
|
+
|
|
190
|
+
## Everything it knows lives somewhere else
|
|
191
|
+
|
|
192
|
+
`@pptx-studio/census` does the reading, `@pptx-studio/validate` does the judging
|
|
193
|
+
and `@pptx-studio/writer` does the writing and the comparing, and not one of the
|
|
194
|
+
three has any Node in it at all — it runs in a browser tab and in a Web Worker. This package supplies the
|
|
195
|
+
two things a browser cannot: a path off the filesystem and a stream to write to.
|
|
196
|
+
|
|
197
|
+
That split is the point. The drop-a-deck explorer in `apps/studio` computes
|
|
198
|
+
exactly the same object in a Worker, so an answer here and an answer in a tab
|
|
199
|
+
cannot drift apart.
|
|
200
|
+
|
|
201
|
+
## Not built yet
|
|
202
|
+
|
|
203
|
+
The plan gives this package three more verbs. Asking for one says which sub-phase
|
|
204
|
+
brings it rather than "unknown command":
|
|
205
|
+
|
|
206
|
+
| verb | what it will do | sub-phase |
|
|
207
|
+
| ---------- | --------------------------------------------- | --------- |
|
|
208
|
+
| `fidelity` | score a render against a reference | 3.9 |
|
|
209
|
+
| `render` | render slides to SVG or PNG without a browser | 3.10 |
|
|
210
|
+
| `resolve` | show where a resolved property came from | 7.x |
|
|
211
|
+
|
|
212
|
+
## `render`
|
|
213
|
+
|
|
214
|
+
Server-side thumbnailing with nothing installed but Node. The SVG stands alone:
|
|
215
|
+
pictures are embedded as `data:` URIs, gradients and patterns are `<defs>` in
|
|
216
|
+
the same document, and there is no external reference of any kind to resolve.
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
1 slide(s) at 1920x1080 -> thumb.svg
|
|
220
|
+
3 typeface(s) from 412 indexed face(s), 1 substituted
|
|
221
|
+
Aptos -> Carlito
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**Text is measured, not guessed.** The browser renderer measures with
|
|
225
|
+
`OffscreenCanvas.measureText`; there is no canvas in Node, so this reads the
|
|
226
|
+
face's own `cmap`, `hmtx`, `GPOS` and `OS/2` tables instead. That is a second
|
|
227
|
+
measurement engine, and the risk of a second engine is that it quietly disagrees
|
|
228
|
+
with the first. Experiment T13 settled the arithmetic rather than assuming it:
|
|
229
|
+
seven fonts built so their tables disagree on purpose, 252 widths measured in
|
|
230
|
+
Chromium, and the reader reproduces **all 252 exactly**. The rules it found are
|
|
231
|
+
in [`corpus/ground-truth/font-metrics.json`](../../corpus/ground-truth/font-metrics.json)
|
|
232
|
+
and the reasoning is in
|
|
233
|
+
[ADR 0042](../../docs/adr/phase-3-text/0042-rendering-without-a-browser.md).
|
|
234
|
+
|
|
235
|
+
Fonts are found in this platform's own directories, plus any `--font-dir` you
|
|
236
|
+
name, which are searched first so you can override a face without installing
|
|
237
|
+
one. `--no-system-fonts` limits it to what you named; `--no-text` draws geometry
|
|
238
|
+
only and asks no font questions at all.
|
|
239
|
+
|
|
240
|
+
A typeface the machine does not have is substituted through the same table
|
|
241
|
+
`@pptx-studio/text` uses in the browser, so the two renderers cannot fall back
|
|
242
|
+
differently, and the substitution is reported rather than hidden. A code point
|
|
243
|
+
no indexed face can draw is reported too.
|
|
244
|
+
|
|
245
|
+
| flag | |
|
|
246
|
+
| ------------------- | ------------------------------------------------------------------- |
|
|
247
|
+
| `--slide <n>` | one slide, 1-based; every slide by default |
|
|
248
|
+
| `--width <px>` | the `width` attribute; the height follows the deck's aspect |
|
|
249
|
+
| `--out <path>` | a directory, or a file when rendering one slide; stdout when absent |
|
|
250
|
+
| `--font-dir <d>` | look here first, repeatable |
|
|
251
|
+
| `--no-system-fonts` | do not look in this platform's own font directories |
|
|
252
|
+
| `--no-text` | geometry only |
|
|
253
|
+
| `--json` | what was drawn, and which face drew each typeface |
|
|
254
|
+
|
|
255
|
+
### What it does not do
|
|
256
|
+
|
|
257
|
+
No PNG. Rasterising would mean shipping a rasteriser, and the point of this verb
|
|
258
|
+
is that it needs nothing but Node — pipe the SVG to whatever you already have.
|
|
259
|
+
|
|
260
|
+
No shaping. Latin, Greek and Cyrillic measure correctly, and so does CJK, whose
|
|
261
|
+
advances do not depend on context. Arabic, Devanagari and the other scripts that
|
|
262
|
+
need a shaper will measure wide, because the reader sums unshaped advances. The
|
|
263
|
+
browser renderer has a real shaper and does not have this limit.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as main } from "./main-DLx2onii.js";
|
|
3
|
+
//#region src/cli.ts
|
|
4
|
+
/**
|
|
5
|
+
* The bin.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately three lines. Everything testable lives in `main`, which takes
|
|
8
|
+
* its streams as an argument and returns an exit code instead of calling
|
|
9
|
+
* `process.exit` - so the whole command line is exercised in-process by the
|
|
10
|
+
* test suite, with no child processes and no captured stdout.
|
|
11
|
+
*/
|
|
12
|
+
process.exitCode = main(process.argv.slice(2));
|
|
13
|
+
//#endregion
|
|
14
|
+
export {};
|
|
15
|
+
|
|
16
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { main } from './main.js';\n\n/**\n * The bin.\n *\n * Deliberately three lines. Everything testable lives in `main`, which takes\n * its streams as an argument and returns an exit code instead of calling\n * `process.exit` - so the whole command line is exercised in-process by the\n * test suite, with no child processes and no captured stdout.\n */\nprocess.exitCode = main(process.argv.slice(2));\n"],"mappings":";;;;;;;;;;;AAWA,QAAQ,WAAW,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC"}
|