mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-12 08:52:32 +00:00
* Add craft-drawingml: units, colours, preset shapes, custom geometry and text warps The parts of DrawingML that need no document model, moved from DeckCraft (60f91f78): crates/color, crates/geom (preset, warp, Xfrm and the EMU conversions) and crates/pptx/src/custgeom.rs with CustomPath from crates/model. The code is unchanged except that custgeom reads craft-xml trees and writes to a craft-xml Writer instead of DeckCraft's own XML helper, and matches elements by local name. The 59 tests of the moved code come with it; six more cover the custom geometry limits. * drawingml: evaluate a custom geometry's guide lists once per coordinate space read_cust_geom rebuilt Guides and evaluated avLst and gdLst again for every path: up to 1,000 paths times up to 10,000 guides, each name copied and hashed. Guides are now cached per path coordinate space (w, h). At most 16 spaces and 4 MiB of guide names are kept per geometry; paths in further spaces are left out. The first space is always kept, and a geometry without guides is not capped. Ported from storytold/deckcraft#1789. A list counts as having guides only when it has gd children, as that PR's review asked. * drawingml: the model types for fills, lines, text, tables, charts and diagrams Moved from DeckCraft (60f91f78) crates/model/src: style.rs, text.rs, table.rs, chart.rs, numfmt.rs and trendline.rs, plus Diagram, DiagramNode and the MediaId and SlideId newtypes from lib.rs. The files are unchanged except that deckcraft_color:: is crate::color:: and Fill and TableBorder allow clippy::large_enum_variant. Their 60 tests come with them. Readers and writers follow.
56 lines
3.7 KiB
Markdown
56 lines
3.7 KiB
Markdown
# craft-drawingml
|
|
|
|
The parts of DrawingML (ECMA-376 part 1, chapter 20) that presentations, word-processing
|
|
documents and spreadsheets share. A `.pptx` slide, a `.docx` drawing and an `.xlsx` drawing all
|
|
hold the same `a:` elements; this crate is the one place that knows what they mean.
|
|
|
|
Nothing here opens a package. Readers take a `craft_xml::El` and writers a `craft_xml::Writer`,
|
|
so the caller decides which part the markup comes from. Lengths are points (1/72 inch) as `f64`;
|
|
files store EMU (12 700 per point).
|
|
|
|
| Module | What | Markup |
|
|
|---|---|---|
|
|
| crate root | `emu_to_pt`, `pt_to_emu`, `Xfrm` (offset, extent, rotation, flips, as an affine), `group_child_affine` | `a:xfrm`, `a:chOff`, `a:chExt` |
|
|
| `color` | `Rgba`, `SchemeSlot` and `ColorScheme` (the twelve theme colours and their `bg1`/`tx1` aliases), `ColorTransform` with `apply`, the preset and system colour names | `a:srgbClr`, `a:schemeClr`, `a:prstClr`, `a:sysClr`, `a:lumMod`, `a:tint`, `a:alpha` … |
|
|
| `preset` | `build(name, w, h, adjusts)`: the outline of a preset shape as fill and stroke sub-paths, its text rectangle, adjust handles and connection sites; `CATALOG` with labels, categories and default adjusts | `a:prstGeom` |
|
|
| `custgeom` | `read_cust_geom` / `write_cust_geom` between `a:custGeom` and `CustomPath` (an `M L C Q Z` path string per sub-path), and `Guides`, the shape guide formula evaluator | `a:custGeom`, `a:gd` |
|
|
| `warp` | `warp(name, adjusts, rect)`: the bands and guide curves of a preset text warp, and the mapping of laid-out lines onto them | `a:prstTxWarp` |
|
|
|
|
## The model
|
|
|
|
These modules hold types only; their readers and writers are not here yet.
|
|
|
|
| Module | Types | Markup they stand for |
|
|
|---|---|---|
|
|
| `style` | `ColorRef` (a base colour plus transforms, resolved against a `ColorScheme`), `Fill`, `Gradient`, `PictureFill`, `Line`, `Effects`, `ShapeStyle` | `a:solidFill`, `a:gradFill`, `a:blipFill`, `a:pattFill`, `a:ln`, `a:effectLst`, `p:style` |
|
|
| `text` | `TextBody`, `Paragraph`, `ParaProps`, `Run`, `RunProps`, `ListStyle`, hyperlinks and actions | `a:txBody`, `a:bodyPr`, `a:lstStyle`, `a:p`, `a:r` |
|
|
| `table` | `Table`, `Row`, `Cell`, `TableStyleDef` and the built-in table styles | `a:tbl`, `a:tblStyleLst` |
|
|
| `chart` | `Chart`, `Series`, axes, data labels, trendlines and error bars, with the values they compute | `c:chartSpace`, `cx:chartSpace` |
|
|
| `numfmt` | `format(code, value, lang)`: number format codes as charts and cells use them | `c:numFmt` |
|
|
| `diagram` | `Diagram`, `DiagramNode` | `dgm:dataModel` |
|
|
|
|
A picture or sound is a `MediaId`; whoever owns the package keeps the bytes. Themes are not here yet.
|
|
|
|
## Preset shapes and text warps
|
|
|
|
Preset names are the file's (`roundRect`, `rightArrow`, `textArchUp`) so files round-trip. The
|
|
outlines are constructed in Rust from what each shape looks like and from the meaning of its
|
|
adjust values; no geometry table is copied. Adjust values use the file convention: ratios in
|
|
1/100 000 of the shorter side (or of the width or height), angles in 1/60 000 degree.
|
|
|
|
```rust
|
|
let g = craft_drawingml::preset::build("roundRect", 200.0, 100.0, &[25_000.0]).unwrap();
|
|
assert!(!g.paths.is_empty());
|
|
assert!(g.text_rect.width() < 200.0);
|
|
```
|
|
|
|
## Hostile input
|
|
|
|
`read_cust_geom` reads at most 1 000 paths per geometry, 100 000 commands per path and 5 000
|
|
guides per list, keeps at most 10 000 guide values, and evaluates the guide lists once per
|
|
coordinate space, for at most 16 spaces and 4 MiB of guide names. Every evaluated value is finite and within
|
|
±1e15; a division by zero is 0. An arc that sweeps a full turn or more draws one turn. `preset::build` and
|
|
`warp::warp` take any `f64` and return `None` or a finite outline. Each limit has a test.
|
|
|
|
The types derive `serde` traits with the field names the apps' own document files already use.
|