Files
craft-libs/crates/prc/README.md
Dylan M. Taylor 7db4645d1f Add craft-prc: the PRC 3D model reader from PdfCraft (#945)
PdfCraft's pdfcraft-prc crate (revision
80e26e674d1aa33078e83c8139875047f3289eb6), moved whole with its tests. It reads
PRC (ISO 14739-1), the model format of PDF 3D annotations: the container, the
bit-level primitives, the schema, tessellations and the product tree.

The code is unchanged. The package and its README are renamed, the doctests
and tests import craft_prc, and the Double code table taken from prc-rs (MIT)
has its row in ATTRIBUTION.md and its licence in licenses/prc-rs.
2026-11-11 18:55:20 -05:00

45 lines
3.9 KiB
Markdown

# craft-prc
A reader for PRC (ISO 14739-1), the 3D model format a PDF `/3D` stream of `/Subtype /PRC` carries (ISO 32000-2 §13.6.3).
- Standalone: no PDF code and no app code. The caller hands it the stream's bytes; drawing the model stays in the app.
- **Licence:** MIT OR Apache-2.0. Inflation through `flate2` with a pure-Rust backend (`miniz_oxide` unless the app's build selects `zlib-rs`).
- From PdfCraft's `pdfcraft-prc` crate (revision `80e26e674d1aa33078e83c8139875047f3289eb6`), moved whole. Issue numbers in comments (`pdf-issues #…`) are PdfCraft's.
- `#![forbid(unsafe_code)]`. Never panics on input: inflated bytes, decoded elements, schema steps and walk depth are capped, and damage returns `PrcError`.
## API
```rust
PrcFile::parse(data) -> Result<PrcFile, PrcError> // header, file structures, model file
PrcFile::parse_with_limit(data, max_inflated) -> Result<PrcFile, PrcError>
FileStructure::section(SectionKind) -> &[u8] // inflated globals / tree / tessellation / geometry / extra geometry
FileStructure::schema() -> Result<Schema, PrcError> // the globals section's leading schema
FileStructure::tessellations() -> Result<Vec<Tessellation>, PrcError> // meshes, wires, markups, compressed meshes
PrcFile::placements() / placements_with(StyleAlpha, EntityOverrides) -> Result<Vec<Placement>, PrcError>
PrcFile::model_tree() -> Result<Vec<ModelNode>, PrcError> // the assembly tree as a model-tree panel lists it
Placement::triangle_colours(&TriangleMesh) -> Option<Vec<Option<Rgba>>>
TriangleMesh::transformed(&Matrix) -> TriangleMesh
Schema::read(&mut BitReader) / Schema::skip_added_fields(entity_type, &mut BitReader)
BitReader: bit, bits, character, unsigned_integer, integer, integer_vbn, double_vbn, nbits_then_unsigned, string, float_as_bytes, double
```
- `MAX_INFLATED_BYTES` (512 MiB) bounds every section together; `TooLarge` reports the limit hit.
- `MAX_DECODED_ELEMENTS` (2^24) bounds the array elements one pass decodes (a tree walk, or one `tessellations` call), since a single bit can decode to a 4-8 byte element; `TooManyElements` reports it.
- Schema programs (how a newer producer describes fields it added) run under a nesting ceiling (64) and `MAX_SCHEMA_STEPS` (2^22), shared like `MAX_DECODED_ELEMENTS` by every program one pass runs.
- `Unsupported` names constructs the reader cannot step over (schema pointer fields, `Value_CurveIs3D`).
- `Tessellation::Mesh` is a `TriangleMesh`: positions, triangles, one triangle range per face, the stored normals and
texture coordinates with each triangle's corner indices into them, and per-triangle line-attribute styles.
`Wire` is polylines; `Markup` is read past.
- `Tessellation::Compressed` is read to its end so later entities decode; its triangles are not rebuilt yet.
- A face may carry at most 8 texture-coordinate sets; more is `Malformed`. Optimised vertex colours are `Unsupported`.
- The product tree: each drawable tessellation placed by its occurrence path's locations and the item's coordinate
systems (a 4x4 `Matrix`), coloured by the style inheritance rules, with occurrences' entity references applied
(`EntityOverrides`: subtree, everywhere or ignored) and style transparency combined with material alpha by `StyleAlpha`.
A prototype's part is coloured by its own file structure's styles. Each `ModelNode` lists its name, where the name
came from, its visibility and the range of placements it drew.
- Occurrence and prototype cycles are `Malformed`; the walk is capped at depth 64, 2^20 visits and `MAX_PLACEMENTS`.
- A tree's markups (PMI), views, scene lights and clipping planes are read past, not modelled; so are textures.
- Not yet in the crate: rebuilding compressed meshes, textures.
- The `Double` code table's rows come from [prc-rs](https://github.com/ralovich/prc-rs) (MIT); its notice is in `src/acof/table.rs`.
A few reading choices also follow prc-rs; each is marked `// prc-rs:` in the source.