+10 3540cf0a7f craft-metadata: read the Extended XMP a JPEG links, from LightCraft (#1046)
* craft-metadata: EXIF, IPTC-IIM, XMP and GPX from LightCraft

lightcraft-meta at 5b61ce1e, as one crate with a module per format: exif
(read, write, maker-note lens, focus point, tag listing), iptc, xmp (parse,
write, merge), gpx, and the JPEG, PNG, WebP, TIFF, RAF and CR3 containers.
They share Metadata, DateTime, Gps and Orientation.

Changed in the move:
- TIFF comes from craft-tiff; Point, Rect and Orientation are the crate's own.
- The app namespace is a parameter: parse_xmp_with, write_xmp_with and
  MergeRules::namespaces take it, and XmpData no longer has lc_settings.
- The HEIF, PSD and MRW readers stay out, since craft-heif, craft-psd and
  craft-raw read those containers; from_embedded takes the blocks they find.

* craft-metadata: a RW2 reads ISO and the rest of its Exif from the JpgFromRaw

A RW2's own Exif IFD is a short subset. What it lacks is filled from the Exif
of the embedded JpgFromRaw, then from the ISO tags of the Panasonic IFD0
(0x0017, 0x0037), each only in its recorded field type. 65535 in a SHORT
ISOSpeedRatings is the overflow marker and states no ISO. The private tags
are read only in a RW2 stream, under the caller's parse options.

Ported from storytold/lightcraft#3518.

* craft-metadata: the Exif rating is written, and 65535 reads as rejected

write_exif writes Rating (0x4746), with 0xFFFF for a rejected photo, and
from_tiff reads 65535 as -1 instead of clamping it to 5.

Ported from storytold/lightcraft#1995.

* craft-metadata: one shutter-speed formatter, exact to four digits

format_exposure_time shows a duration within 0.1% of 1/n second as 1/n and
anything else to four significant digits, so 0.3 s, 1/2.8 s and 0.625 s are
no longer rounded to a reciprocal or one decimal. Metadata::exposure_display
and the ExposureTime tag row both use it.

Ported from storytold/lightcraft#1692.

* craft-metadata: JPEG XL containers give their Exif and xml boxes

The first Exif and xml box of a JPEG XL container, plain or Brotli-wrapped
in brob, honouring the Exif box's TIFF header offset. A brob payload is
capped at 32 MiB. A bare codestream has no metadata.

Ported from storytold/lightcraft#3756.

* craft-metadata: XMP Resource structs flatten their attribute fields

A property with rdf:parseType="Resource" may give its fields as attributes
as well as child elements. Only the children were flattened into
XmpData::properties; the attributes now are too, as for a nested
rdf:Description.

Ported from storytold/lightcraft#1226 (the XMP part).

* craft-metadata: a capture date of just a year or a month stays as stated

XMP dates may stop at the year (1983) or the month (1983-04). DateTime now
has a DatePrecision; such a date writes back to XMP as stated and only in
photoshop:DateCreated, and write_exif leaves it out, since an Exif date
cannot say it.

Ported from storytold/lightcraft#3502.

* craft-metadata: Fujifilm in-camera recipes from the maker note

fuji module: the film simulation and the rest of the in-camera recipe (grain,
colour chrome, tone, dynamic range, white balance and its shift, sharpness,
noise reduction, clarity) from a Fujifilm maker note. recipe_from_exif,
recipe_from_bytes (TIFF, JPEG, RAF) and read_recipe_file, which reads only
as far as the metadata. from_embedded fills Metadata::fuji_recipe and
file_tag_rows lists the recipe under Fujifilm.

Ported from storytold/lightcraft#1209.

* craft-metadata: the linear-time scan test compares times, not a fixed bound

The test asserted that 200 000 attributes scan in under 5 s, which failed on
a loaded machine. It now scans 25 000 and 100 000 attributes, takes the best
of three runs of each, and asserts that four times the attributes take less
than ten times as long. Linear scans give about 4; a quadratic duplicate
check gave 18.6 and fails.

* craft-metadata: interleave the linear-time scan test's runs

The best-of-three ratio still failed once under load. The test now alternates
five runs of 50 000 and 200 000 attributes and compares the fastest of each,
so a burst of load slows both sizes. Six runs at load average 55 gave ratios
of 3.9 to 5.4 against the bound of 10.

* craft-metadata: XmpData::toolkit, the x:xmptk of the packet

The name of the program that wrote a packet, from x:xmptk on x:xmpmeta (or
x:xaptk on the older x:xapmeta), whatever prefix the packet binds to
adobe:ns:meta/. write_xmp_with writes XmpWrite::toolkit there, and the test
reads it back, escaped characters included.

* craft-metadata: mpf, the Multi-Picture index of a JPEG

mpf::images lists the images an APP2 MPF index (CIPA DC-007) puts after the
primary image, with their file offsets; the index is read with craft-tiff,
in either byte order, up to 16 entries. mpf::write inserts an index after
the primary's leading APPn segments and appends the other images, with the
primary listed as the representative baseline image: the layout LightCraft's
gain map JPEG writer uses, for any number of images. mpf::markers lists the
marker segments before the first scan, for APPn payloads such as ISO 21496-1
gain map metadata.

* craft-metadata: edit, byte-preserving Exif and XMP edits from PhotoCraft

PhotoCraft's orientation, resolution and Exif colour-space code (codecs
orientation.rs without the pixel transforms, resolution.rs, exif_color.rs),
at photocraft f1b5e7d72, as the edit module:

- upright_exif and upright_xmp set Orientation to 1 in place, in the entry's
  own type and width, every well-formed duplicate included.
- exif_with_resolution and xmp_with_resolution set the resolution in place
  and remove entries that cannot be rewritten; the _adding_missing variant
  appends a new IFD0 when there are none.
- export_exif and export_xmp do both and drop the source Exif thumbnail,
  with the overlap scan bounded.
- exif_orientation, exif_resolution, xmp_resolution, photoshop_resolution,
  exif_color_space and resolution read the same values with the editors'
  rules (first entry wins, SHORT or LONG only, BigTIFF accepted).

The tests that call these functions directly move with them (the codec
round trips stay in PhotoCraft): the orientation, resolution, thumbnail and
compaction tests, the comparison-counting complexity test and the colour
space tests.

* craft-metadata: exif_with_pixel_size, the written size in PixelX/YDimension

A camera records its sensor's size in the Exif IFD's PixelXDimension and
PixelYDimension, which after a crop, resize or rotation names a size the
exported file does not have. exif_with_pixel_size rewrites each one that
holds one SHORT or LONG, in place and as a LONG, in classic and BigTIFF
blocks, with the JPEG Exif prefix kept.

Ported from storytold/photocraft#12407 (the format part).

* craft-metadata: an ISO 8601 clock needs two-digit hours and minutes

Ported from storytold/lightcraft#3523.

* craft-metadata: a UTC offset needs a two-digit minute field

Ported from storytold/lightcraft#3467.

* craft-metadata: tiff:Orientation is read only as an integral code 1 to 8

A fractional or out-of-range value stays a raw property and does not
become the photo's orientation.

Ported from storytold/lightcraft#3495.

* craft-metadata: an XMP ISO is read only when it is a whole number in range

A fractional, non-positive or out-of-range ISO is not truncated or
saturated into one; the next candidate property is tried instead.

Ported from storytold/lightcraft#3633.

* craft-metadata: XMP pixel dimensions are read only as exact whole numbers

A malformed, fractional, negative or out-of-range tiff:ImageWidth or
ImageLength is no longer truncated or saturated, and lets the exif:Pixel
dimension take its place. Numbers are compared as exact decimal digits, so
wide rationals stay exact. The ISO reader now uses the same exact reader
(both PRs added one).

Ported from storytold/lightcraft#3690.

* craft-metadata: XMP GPS minutes and seconds must be under 60; tell when a read was cut short

A coordinate such as 45,60N is no longer normalised to a plausible point;
the raw property stays. XmpData::properties_truncated says the flattened
property map ran past its key budget, Embedded::chunk_walk_incomplete says a
PNG or WebP chunk walk stopped early, and jpeg_segments_with_all_xmp returns
every ordinary XMP packet of a JPEG, so a caller that must prove a file
carries no location can refuse what it could not inspect.

Ported from storytold/lightcraft#3054.

* craft-metadata: IPTC Time Created counts only when it is a whole, valid time

A date with a six-digit clock and no zone stays date-only; HHMMSS±HHMM
carries an offset; clocks and offsets are range-checked. A partial offset,
extra digits, a leap second or trailing text no longer becomes a capture
time, so it cannot block valid XMP or Exif.

Ported from storytold/lightcraft#3448.

* craft-metadata: test hostile XMP attribute references

The one-pass reference scan (entity_end) already covers the bug that
storytold/lightcraft#3007 fixed another way; its test is added here and
passes on this implementation: unknown, unterminated and far-away
references stay verbatim, a value of a million ampersands or of a million
zeros is read once, and multi-byte text around a reference stays whole.

Test from storytold/lightcraft#3007.

* craft-metadata: parse_gps_position; an XMP coordinate's sign comes from its letter

parse_gps_position reads an exif:GPSLatitude and GPSLongitude pair and
checks both axes. A negative degree, minute or second part, or a letter of
the other axis (10,30E as a latitude), is malformed; the letter may be
either case.

Ported from storytold/lightcraft#2088 (the format part).

* craft-metadata: bound the XMP namespace declarations in scope; merge into an empty rdf:RDF

Prefix lookup scans every declaration in scope, so one start tag with
thousands of xmlns declarations made parsing and merging quadratic. More
than 512 declarations in scope is now TooComplex, in parse_xmp and in
merge_xmp's scan. merge_xmp also opens a self-closing <rdf:RDF/> around the
new description instead of failing.

Ported from storytold/lightcraft#3696.

* craft-metadata: XmpData::has_location_metadata, every embedded XMP location

has_location_metadata answers whether a packet names any Exif GPS property or
a non-blank place (IPTC Core location fields, photoshop City/State/Country,
IPTC Extension LocationShown and LocationCreated with a place or coordinates),
including inside array items and repeated structs that the flattened map and
the structured values keep only once (XmpData::names_location, from the parsed
tree). The IPTC Extension namespace is now canonicalised and written.
extended_xmp_guid reports the announced Extended XMP GUID. A caller that must
prove a file has no location checks properties_truncated first.

The source also listed LightCraft's own lc:location; a caller with its own
namespace checks that itself.

Ported from storytold/lightcraft#4121 (the format part).

* craft-metadata: is_lens_spec_name, the inverse check of lens_spec_name

Whether a lens name has the '<focal> mm f/<aperture>' shape lens_spec_name
writes, so a caller can tell a made-up name from a camera's. The test is new.

Ported from storytold/lightcraft#2644 (the format part).

* craft-metadata: Sony focus points for 44 bodies

SONY_MODELS grows from the alpha 1 and A7S III to the 44 bodies whose focus
tags were checked on the public raw.pixls.us samples against ExifTool's
reading; bodies whose 0x201b is not the focus mode stay out. This also covers
the ILCE-6400 and ILCE-7M3 that storytold/lightcraft#3109 adds.

Ported from storytold/lightcraft#1891 (the focus part).

* craft-metadata: GPX points say which track they are on; tracks keep their names

TrackPoint::track counts the <trk> a point came from, Tracklog::names holds
each track's <name> (trimmed, at most 200 characters), and only_track gives
one track's points, so a map can draw a file's tracks apart and tag from one.
At most 10 000 tracks per file (TooComplex past that); a non-finite elevation
is dropped.

Ported from storytold/lightcraft#921 (the GPX part; #916 carries the same).

* craft-metadata: test that from_embedded keeps the EXIF, IPTC, XMP precedence

storytold/lightcraft#2211 adds the same function as extract_embedded; this
crate already has it as from_embedded. Its tests are added: EXIF camera
fields stay, IPTC fills gaps, XMP overrides the user fields, and damaged
blocks read as nothing.

Tests from storytold/lightcraft#2211.

* craft-metadata: the XMP writer keeps a carriage return as &#13;

XML end-of-line handling turns a literal CR into a line feed when a packet is
read, so text with one did not round-trip through other readers. Element
text now writes it as a character reference.

Ported from storytold/lightcraft#4119 (the writer fix only; that PR also
moves LightCraft to quick-xml 0.42, which this crate does not take here, as
craft-xml uses 0.41).

* craft-metadata: README rows for the ported validation and location checks

* craft-metadata: read the Extended XMP a JPEG's standard packet links

A JPEG whose XMP is too large for one APP1 segment puts the rest in Extended
XMP chunks, linked by xmpNote:HasExtendedXMP. When the standard packet links
a GUID, only that GUID's chunks are read: they must be complete segments,
declare one full length of at most 16 MiB, number at most 4096, and cover
that length exactly once (Embedded::xmp_extended_error says why not).
parse_xmp_pair reads the two packets as one (standard properties win; arrays
and structs stated in both are combined), so extract and from_embedded now
see the extension's GPS, caption and other fields. embedded_xmp reports a
missing, malformed or unlinked extension as an EmbeddedXmpError that keeps
the standard packet, for a caller that must see all of a file's metadata.

An extension the standard packet does not link stays visible in
Embedded::xmp_extended as before, and is not merged.

Ported from storytold/lightcraft#2581, onto the current JPEG walker.

---------

Co-authored-by: radialmonster <radial@gmail.com>
Co-authored-by: Sebastian Berschneider <berschi@gmail.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
Co-authored-by: Michael Anderson <1427851+endthestart@users.noreply.github.com>
Co-authored-by: Ilya Dorman <ilya@codeforhumans.dev>
Co-authored-by: Clyde C Brown <clyde.c.brown@pm.me>
Co-authored-by: MohammadTeimori <teimori.mohammad@gmail.com>
Co-authored-by: vangel76 <vangel1976@googlemail.com>
Co-authored-by: Max Mittelstädt <62167861+TheGalitube@users.noreply.github.com>
Co-authored-by: NetterSilver <133535268+Silvertree2010@users.noreply.github.com>
Co-authored-by: ronibalthazar <61232335+ronibalthazar@users.noreply.github.com>
Co-authored-by: Andrew Frahn <andrew@emmertex.com>
Co-authored-by: jkalkstein <76634771+jkalkstein@users.noreply.github.com>
Co-authored-by: d-rouge <d-rouge@users.noreply.github.com>
Co-authored-by: espoon <espoon@users.noreply.github.com>
Co-authored-by: Yoann Laissus <yoann.laissus@gmail.com>
Co-authored-by: Jason Baldwin <33934381+bitshiftza@users.noreply.github.com>
Co-authored-by: ingolfteetz <iteetz@me.com>
Co-authored-by: smi-leonivkovic <leon.ivkovic@smi-digital.com>
2026-11-11 21:06:06 -05:00

Craft App Libraries

Scanned by SonarCloud

This repo contains libraries used by the various Craft Apps. It's a Rust monorepo workspace, and the libraries can be included by any Craft Apps that need them.

In the future this may grow to include non-Rust library code.

If any libraries grow beyond Craft App usage, eg. RAW format support, they may be promoted out and into their own libraries for the broader ecosystem to take advantage of.

Layout

A Cargo workspace (edition 2024, resolver 3). Each library is a crate under crates/<name>, named craft-<name>, with version, edition, license and repository inherited from the workspace (license.workspace = true, and so on) and [lints] workspace = true. Register each crate in [workspace.dependencies] in the root Cargo.toml.

Apps depend on a crate by git:

craft-<name> = { git = "https://github.com/storytold/craft-libs", rev = "<commit>" }

Libraries

  • craft-platform: optional native dialog lifecycle, Linux/BSD desktop appearance observation and browser download ownership; application policy stays in the apps.

  • craft-aep: After Effects projects: the .aep (RIFX) and .aepx container as a lossless chunk tree that writes back byte for byte, and a typed, read-only view of compositions, layers, properties, keyframes, effects, masks, shapes, text and footage. Clean room, from EffectCraft. Mapping onto an app's document stays in the app.

  • craft-ai-core: the data model and contract for AI in the Craft Apps (connections, models, tools, requests, jobs, consent, history, route spec). Pure, no I/O, wasm-safe. Contract in docs/ai-shared-layer.md.

  • craft-pdf: independently optional PDF parsing, interpretation, rasterization and guarded authoring. Apps retain layout, fonts, editing and export policy; writer-only consumers do not enable the shared reader.

  • craft-pdn: Paint.NET documents (.pdn, PDN3), read: the layer list, blend modes and chunked gzip pixel blocks, with a data-only MS-NRBF (.NET binary serialization) reader. From PhotoCraft.

  • craft-aaf: clean-room AAF (Edit Protocol, structured storage) and OMF Interchange 2.0 (Bento) readers and writers over one mob-style composition model with exact times, clip gain, markers, nested compositions and embedded PCM essence. From FilmCraft.

  • craft-assuan: the Assuan protocol and gpg-agent's operations (key lookup, signing a digest, decrypting a session key) over any Read + Write stream, with a bounded canonical S-expression reader. No sockets; everything the agent sends is capped.

  • craft-affinity: bounded reader for native Affinity documents (.af, .afdesign, .afphoto, .afpub): archive, object stream and a neutral document model with layers, artboards, vectors, text, tables, images and masks. Read only; mapping onto an app's document stays in the app.

  • craft-atomic: Crash-safe atomic file writing and replacement with same-directory staging, directory fsync, Apple F_FULLFSYNC fallback, transient lock backoff, and fault injection for the Craft suite.

  • craft-captions: caption and subtitle files behind one neutral model (cues with exact tick times): SubRip, WebVTT, Scenarist SCC, MacCaption MCC, EBU STL and TTML / IMSC1 / DFXP readers and writers, and CEA-608 / CEA-708 byte-pair coding. Carved from FilmCraft.

  • craft-cfb: clean-room Compound File Binary ([MS-CFB], OLE structured storage) reader and writer: the container of legacy Office files, Outlook messages, encrypted OOXML packages and AAF. Bounded on hostile input; what the streams hold stays with each format.

  • craft-dav: WebDAV multistatus documents (RFC 4918) with the CalDAV and CardDAV namespaces, from MailCraft: read fail-closed into a bounded craft-xml tree with fixed prefixes, and the successful properties of each response. No I/O.

  • craft-cms: pure-Rust ICC v2/v4 colour management: profile parsing and writing, transforms, rendering intents, black point compensation, soft proofing, gamut checks, 3D LUTs and built-in profiles (sRGB, Display P3, synthetic coated CMYK and others).

  • craft-crs: Adobe Camera Raw settings (the crs: namespace of an XMP packet or .xmp sidecar, read through craft-metadata): the settings by name, numbers, tone curve points, local corrections and the crop, read and written. From PhotoCraft.

  • craft-codepage: legacy 8-bit code pages, one table each: the single-byte Windows pages, Mac OS Roman and fifteen DOS pages, keyed by Windows code page number, with the RTF/Word font charsets. craft-rtf, craft-dxf and craft-mime decode through it.

  • craft-crw: clean-room Canon CRW (CIFF) raw decoder, from LightCraft: the heap container, the entropy coding derived by black-box analysis (frozen code tables), sensor black and white levels and as-shot white balance. The complete derivation record (plan, sources log, scripts, verification) is in crates/crw/clean-room/. Colour stays in each app.

  • craft-csv: delimited text (CSV, TSV) and SYLK: encoding detection (UTF-8, UTF-16, Windows-1252 or Windows-1256), delimiter sniffing, a record parser with a cap on fields per record, field quoting for writers, and a SYLK (.slk) reader with R1C1 formulas rewritten to A1.

  • craft-dialogs: native file and message dialogs that never block the event loop: queued requests shown at the end of the frame and answered on a later frame, free-standing Open and Folder panels and Save sheets on macOS, case-insensitive filters. What to do with the answer stays in each app.

  • craft-doc: reads PhotoCraft .pcraft, VectorCraft .vectorcraft and EffectCraft .ecproj documents without the apps: the kind and version, the previews and PDF they carry, and their pages and layers. Rendering and editing stay in each app.

  • craft-docpath: decides whether a path or file: URL stored in a document may be opened. Paths stored in documents are followed only when they are local or on the document's own network share; other network paths, device paths and non-file URLs are refused.

  • craft-dpx: DPX (SMPTE ST 268) and Kodak Cineon frames, from PhotoCraft, FilmCraft and EffectCraft: header fields and code values at 8, 10, 12 and 16 bits in both byte orders, filled and packed, RGB, RGBA, ABGR, luma and Y'CbCr descriptors, and a writer for both formats. Bounded on hostile input. Colour conversion and orientation stay in each app.

  • craft-drawingml: the DrawingML that PPTX, DOCX and XLSX share: EMU units and a:xfrm, colours with theme slots and colour transforms, preset shape outlines (a:prstGeom), custom geometry with guide formulas (a:custGeom) and preset text warps (a:prstTxWarp). From DeckCraft. Takes craft-xml trees; packages stay with each format.

  • craft-eps: Encapsulated PostScript files as a container: the binary preview header (read and write), the DSC header comments and bounding boxes (also (atend)), the EPSI preview bitmap, ASCII85 data, and telling EPS, PostScript and Illustrator files (PostScript- or PDF-based) apart. No PostScript interpreter.

  • craft-docx: DOCX (WordprocessingML) read and written on craft-wordmodel, with Word XML (Flat OPC) and Word 2003 XML, password-protected packages and Restrict Editing hashes. WordCraft's DOCX crate on craft-opc, craft-xml and craft-offcrypto.

  • craft-dxf: DXF tag reader and writer, from CADCraft: ASCII and binary DXF as (group code, value) tags, split into sections and entities, with pre-2007 code pages and version detection, and written back; and model, the drawing above the tags (header variables, tables, blocks, layouts, entities) and its writer (R12 to 2018), merged from CADCraft's and VectorCraft's readers. Bounded on hostile input. Mapping the model onto a document stays in each app.

  • craft-ecproj-format: the envelope of EffectCraft .ecproj project files: savedBy, the schema version and its check, and the file object with the project and its saved view as type parameters. The project model stays in EffectCraft.

  • craft-fig: clean-room reader and writer for the .fig container (Figma Design and FigJam local copies): the ZIP archive, the chunked canvas with its kiwi schema and message, images, and the vector network and geometry blobs. Bounded on hostile input. Carved from FigCraft.

  • craft-epub: EPUB packages: the OCF ZIP container, the package document (metadata, manifest, spine) and the navigation document, written as EPUB 3 (reflowable and fixed layout) and read (EPUB 2 and 3) with bounded entry sizes. Content documents are the caller's.

  • craft-figma-rest: typed model of the Figma REST API file JSON (document tree, paints, effects, text styles, layout, component metadata), read and written with serde without losing fields it has no name for. The neutral model the .fig and .sketch readers map onto, with their extensions documented.

  • craft-ews: the SOAP layer of Exchange Web Services, from MailCraft, without sockets: the request envelope and an escaping element builder, and the answer envelope, faults and response messages with their codes, read with craft-xml. The operations and everything over HTTP stay in each app.

  • craft-exr: OpenEXR pieces shared by PhotoCraft and EffectCraft: layer and channel names, the channels that make a colour picture, and Cryptomatte IDs, metadata keys, manifests and rank channels. The optional decode feature adds bounded part listing, flat decoding (scan lines, tiles, every compression of the exr crate) and writing.

  • craft-flow: the flow model every text format maps to (paragraphs with a kind, lists and formatted spans; tables; pictures, fields, notes, equations), converted to and from a craft-wordmodel Document.

  • craft-font-catalog: the installed fonts on every platform (font folders, fontconfig and Flatpak host folders, CoreText, DirectWrite, the font store), lookup by family, style, localized, legacy, full and PostScript names, family loads shared between threads, and rescans when fonts are installed or removed.

  • craft-font-manager: Craft Font Manager as a library: search and filters over the Google Fonts index, installed fonts by family, the font store interface, and (egui feature) FontsPanel, the whole interface as one panel for the launcher's Fonts tab and the standalone app.

  • craft-font-store: the suite's font store: the pinned Google Fonts and Noto indexes plus indexes the user adds (never curated), exact lookup by family and style or PostScript name, and installs from each source's URLs (jsDelivr, then raw GitHub) checked by size, sha256 and parsing, with the licence, a manifest, and removal. Off until the user turns downloading on; agents can't.

  • craft-fonts-build: embeds the optional craft-fonts faces from an app's build.rs (CRAFT_FONTS_DIR, CRAFT_FONTS_REQUIRED, script filters) as a table of EmbeddedFaces. No dependencies; the app picks the faces.

  • craft-gainmap: HDR gain maps, from LightCraft: the ISO 21496-1 metadata and Adobe hdrgm XMP (read and write), measuring a gain map from SDR and HDR renditions, applying one, and Apple's legacy maps. Encoding and the container stay in each app.

  • craft-gcode: Grbl-style G-code writer: polylines in millimetres to G0/G1 moves with laser power and feed, for cutting lasers and plotters, as a commented file or as bare lines for streaming. Its grbl module has the real-time command bytes and the status and acknowledgement parsers.

  • craft-gif: GIF block reader, from PhotoCraft: the logical screen, every frame's position, delay, disposal and transparent colour, the loop count and the first frame's colour table, without decompressing pixels. Tells an animation from a still and whether a file can hold the picture it declares before a decoder runs.

  • craft-hdr: Radiance HDR (RGBE) picture reader, from FilmCraft: flat, old and new run-length scan lines and all eight axis orders, to linear float RGB. Scan lines are validated before the picture is allocated.

  • craft-heif: optional HEIF/HEIC still-image decoder, from LightCraft: heic-rs reads the container and HEVC pictures, and this crate converts to 16-bit RGB to match libheif (VUI range and matrix, chroma upsampling, imir, ICC on grid tiles). Also orientation, alpha, EXIF/XMP and thumbnails. It never panics, and apps put it behind a non-default feature.

  • craft-html: the bottom layer of reading and writing HTML: a tolerant tokenizer (text, start tags, end tags; elements to drop or to read as raw text are options), character references with the legacy names browsers accept without ;, escaping, and the character set a page declares. No tree, no CSS, no rendering.

  • craft-i18n: translations over the embedded craft-i18n catalogs: lookup with fallback (pt-br → pt → English), plurals, language names, the system locale and a pseudo locale. The catalogs stay a fully optional build input; apps keep tl! and their language setting.

  • craft-raw: camera raw files, the file-format layer, from LightCraft with what PhotoCraft's and FilmCraft's readers added: container parsing and decompression to a neutral raw image (samples, CFA, black and white levels, active area, crop, orientation, colour tags, opcode lists, embedded previews), one Cargo feature per format. DNG reading and writing, Hasselblad 3FR/FFF, Minolta MRW, Epson ERF, Mamiya MEF, Kodak DCS, Pentax PEF, Samsung SRW, Canon CR2, Nikon NEF/NRW, Panasonic RW2, Fujifilm RAF, Olympus ORF (uncompressed) and Canon CRW (through Hasselblad 3FR/FFF, Minolta MRW, Epson ERF, Mamiya MEF, Kodak DCS, Pentax PEF, Samsung SRW, Canon CR2, Nikon NEF/NRW, Panasonic RW2, Fujifilm RAF and Canon CRW (through Hasselblad 3FR/FFF, Minolta MRW, Epson ERF, Mamiya MEF, Kodak DCS, Pentax PEF, Samsung SRW, Canon CR2, Nikon NEF/NRW, Panasonic RW2 and Canon CRW (through Hasselblad 3FR/FFF, Minolta MRW, Epson ERF, Mamiya MEF, Kodak DCS, Pentax PEF, Samsung SRW, Canon CR2, Nikon NEF/NRW and Canon CRW (through craft-crw) so far; demosaicing and everything after stay with the develop pipeline.

  • craft-tga: Truevision Targa, from FilmCraft (reader) and PhotoCraft (writer): true-colour, grayscale and colour-mapped pictures, raw or run-length encoded, any origin, to RGBA8, and a run-length writer whose packets end with their scan line. Bounded on hostile input.

  • craft-idml: IDML (InDesign Markup Language) packages: the ZIP container read with bounded part sizes and lenient part names, designmap.xml with its includes in place, the <Properties> form on craft-xml elements, value codecs and the package writer; and InDesign Tagged Text, read and written.

  • craft-ical: iCalendar (RFC 5545) building blocks, from MailCraft: content lines, DATE/DATE-TIME values, durations, TEXT escaping, the common subset of recurrence rules, and VTIMEZONE definitions read and written. No time-zone database; what events and to-dos mean stays in each app. Bounded and panic-free on hostile input.

  • craft-stream-codecs: byte-stream and bi-level image codecs that PDF, PostScript and TIFF share: LZW, ASCII85, ASCIIHex, RunLength, TIFF and PNG predictors, CCITT Group 3 and 4 decoding and Group 4 encoding, JBIG2 decoding and lossless encoding. Every decoder is bounded and returns its partial output on damage. From PdfCraft; a PDF filter chain is built on it in craft-pdf.

  • craft-timeline: editorial timeline interchange: exact media time and SMPTE timecode, import/export reports, media path and file:// URL handling, Avid Log Exchange (ALE) and CMX 3600 EDL documents, format detection. From FilmCraft.

  • craft-metadata: photo metadata, from LightCraft: EXIF (read and write, maker-note lens and focus point, every tag by name), IPTC-IIM, XMP packets (read, write, and a merge that keeps what another program wrote), GPX track logs, and the blocks that carry them in JPEG, PNG, WebP, TIFF-based, RAF and CR3 files. One Metadata model for all of them. Built on craft-tiff.

  • craft-tiff: TIFF and BigTIFF IFD reader and writer, from LightCraft: every field type, the IFD chain, SubIFDs and Exif/GPS/Interop pointer IFDs, maker-note IFDs (Canon, Nikon, Sony, Fujifilm, Olympus, Panasonic, Pentax), strip and tile layout. Bounded and panic-free on hostile input. Pixel decompression stays with the callers.

  • craft-metafile: Windows metafiles, from DeckCraft, WordCraft and VectorCraft: a WMF, EMF and EMF+ reader into a neutral picture (paths with line styles, pattern fills, bitmaps, text, clip regions and clip paths) and, behind write, EMF and WMF writers. Bounded and panic-free on hostile input. Mapping the picture onto a document stays in each app.

  • craft-psd: Adobe Photoshop PSD and PSB reader and writer, from PhotoCraft: a lossless format-level model (layers, masks, tagged blocks, image resources, descriptors, all four compressions, lazy reading from a file) that writes an unmodified file back byte for byte, a builder for new files, and the Photoshop resource files that share its primitives (.abr, .asl, .aco, .act, .ase, .grd, .pat, .atn, .csh, .shc) and the Photoshop blocks of a layered TIFF. Bounded and panic-free on hostile input. Compositing and the mapping onto a document stay in each app.

  • craft-jmap: the JMAP protocol core (RFC 8620), from MailCraft, without sockets: session, requests of method calls with back-references, responses, ids, address templates, credentials and the judgement of HTTP answers, over any HTTP implementation. Bounded on hostile answers; what a program asks and makes of the answers stays in it.

  • craft-jpeg: clean-room decoder for 12-bit and arithmetic-coded JPEG (T.81 SOF0/SOF1 at 12 bits, SOF9, SOF10), from PhotoCraft, and a frame probe for routing. Metadata stays in each app.

  • craft-raster-codecs: small raster formats, one module each, from PhotoCraft: DDS (BC1 to BC3, read and write), DICOM, FITS (read and write), IFF/ILBM (read and write), PCX, PNM/PAM/PFM (read and write) and XPM, into one flat image type. Bounded and panic-free on hostile input. Colour, orientation and the document mapping stay in each app.

  • craft-kiwi: clean-room decoder and encoder for the kiwi binary schema format (the encoding inside .fig files): a schema of enums, structs and messages, and messages decoded with it into a tree keyed by field name. Bounded on hostile input. Carved from FigCraft.

  • craft-keymap: keyboard bindings: chords and their text forms, scopes, conflicts, user overrides stored through craft-settings and import of other applications' shortcut sets. Command catalogs, file readers and the shortcut editor UI stay in each app.

  • craft-audio: audio file I/O and codecs (WAV, AIFF, FLAC, AAC, Opus, AC-3/E-AC-3, MP1/MP2, MP3 encoding), streaming and seeking, and packet decoding for any demuxer. See its README for formats and features.

  • craft-latex: LaTeX documents read (the everyday subset) and written (a standalone article), to and from the craft-flow model.

  • craft-markdown: Markdown read and written (a CommonMark subset with GitHub tables and strikethrough), to and from the craft-flow model.

  • craft-math: equations as one tree (the Office Math object model) with its syntaxes, read and written: OMML, presentation MathML, LaTeX math and the UnicodeMath linear format.

  • craft-media: bit-level I/O (bitstream), clean-room MP4/MOV (isobmff), Matroska/WebM (matroska) and MXF (mxf) demuxers and muxers, Ogg (ogg), AVI (avi) and MPEG-TS/PS (mpegts) demuxers, from FilmCraft, and an ISO BMFF box reader. Containers only; codecs are in craft-audio, and video codecs will go in a separate crate.

  • craft-lottie: Lottie (Bodymovin) JSON: the document model of lottie-spec 1.0 (animation, assets, layers by type, shape items, masks, effects, text, markers) with a bounded reader and a writer that keep what they do not know, and the encodings of its values (keyframes, ease tangents, bezier paths, gradients, data URIs). From EffectCraft; mapping onto an app's document stays in the app.

  • craft-menu: an app's menus as a macOS menu bar: the Mac layout (app menu, Window, Help, system-key clashes), a platform backend trait, and key equivalents fed back to egui as the input egui-winit would have made. Commands and their enabled state stay in each app.

  • craft-mesh: 3D mesh file formats behind one neutral model (meshes of polygons with per-corner indices, materials, a node hierarchy): STL, OBJ with MTL, PLY, glTF 2.0 / GLB and 3MF, one feature each. Readers are bounded by Limits, never open a file themselves glTF 2.0 / GLB and FBX, one feature each. Readers are bounded by Limits, never open a file themselves and never panic. Carved from EffectCraft, SolidCraft, TextureCraft and MaterialCraft.

  • craft-midi: Standard MIDI Files: a bounded reader for formats 0, 1 and 2 and a format-1 writer, over a neutral model of notes and channel events in ticks at 960 per quarter note. From SoundCraft.

  • craft-mime: Internet messages and MIME, read and written: RFC 5322 header fields, MIME parts and multiparts, encoded-words, RFC 2231 parameters, base64 and quoted-printable, character sets, address lists, dates, mbox files and the multipart/related lookups of MHT web archives. What a message means (body, attachments, flags) stays in each app.

  • craft-odf: OpenDocument packages (ODF 1.3 Part 2), read and written: the ZIP container with its mimetype and manifest within limits, password protection (AES-256-CBC with PBKDF2, as LibreOffice writes it) and flat single-file documents. The container only: what the XML inside means belongs to the readers of each document type.

  • craft-prc: a reader for PRC (ISO 14739-1), the 3D model format of PDF 3D annotations: container, bit-level primitives, schema, tessellations and the product tree as placed, coloured triangle meshes and a model tree. Bounded on hostile input. From PdfCraft; rendering stays in the app.

  • craft-offcrypto: clean-room Office document cryptography ([MS-OFFCRYPTO]): password-encrypted OOXML packages on craft-cfb (agile and standard encryption read, with the integrity check enforced; agile written), unsupported schemes named, and the password hashes of document and sheet protection.

  • craft-ods: OpenDocument spreadsheets (.ods, .ots) on craft-odf: the tables of content.xml with typed values, displayed text, formulas as text, style names, repeats expanded and merged cells, with dates and durations as serial numbers. Bounded cells, merges and text; strict XML.

  • craft-opc: Open Packaging Conventions, the ZIP container of DOCX, XLSX and PPTX files: bounded readers (every part up front, or on demand), part names, relationships, content types and a deterministic package writer. What the parts hold stays with each format's crate.

  • craft-pcraft-format: the envelope of PhotoCraft's .pcraft bundle: Manifest<D> with the document as a type parameter, TileRef, the entry paths, the manifest decode limits and the migration runner. The document model stays in PhotoCraft.

  • craft-penpot: clean-room reader and writer for the Penpot 2.x export container (.penpot): the ZIP archive, its manifest, the per-file, per-page and per-shape JSON members and media objects, as the JSON the file holds. Bounded on hostile input. Carved from FigCraft.

  • craft-plotter: cutter and pen-plotter command languages: HP-GL, DMPL and GP-GL (plain and the Silhouette dialect, three generations, registration marks) from a job in millimetres, plus the Silhouette device queries and reply parsers. No I/O.

  • craft-pptx: PresentationML, the model of a .pptx presentation: masters, layouts, slides, shapes, placeholders and their inheritance, transitions and animations, comments, sections, media and kept parts. From DeckCraft. DrawingML comes from craft-drawingml.

  • craft-print: PDF submission to CUPS and Windows, printer discovery, duplex/copies/colour and driver preferences. PDF generation stays in each app.

  • craft-proof: proofing per language (spelling, suggestions, grammar, hyphenation, a Hunspell reader, user words, Language packs). The word lists and patterns are craft-i18n's language-data/, embedded at build time from CRAFT_I18N_DIR: English and the carry-over locales by default, the set CRAFT_PROOF_EMBED names otherwise (en for English only); other languages come from installed Language packs.

  • craft-pst: Outlook personal folders files (.pst, [MS-PST]) read over any Read + Seek, from MailCraft: the node database, property and table contexts, folders, messages, recipients, attachments, attached messages and named properties, ANSI and Unicode, encoded or not, with a password. Salvages damaged files. Bounded and panic-free on hostile input. What an item means stays in each app.

  • craft-quit: native macOS quit, egui close handling and an optional app menu. Unsaved-document decisions and save prompts stay in each app.

  • craft-rtf: Rich Text Format: a tokenizer, text decoding in the file's code pages (\uN, \'hh, single-byte and East Asian multibyte pages), escaping and dates, and a reader and writer for a small neutral model (paragraphs, character formatting, outline levels, tables).

  • craft-settings: config.toml settings storage for every app: platform folders, portable mode and overrides, atomic saves while running, backup, damaged-file recovery and schema migrations. Policy in docs/settings-storage.md.

  • craft-sheet: spreadsheet vocabulary shared by craft-xls, craft-xlsx and craft-ods: cell positions and A1 text, cell values and error values, sheet-name quoting, Excel's built-in number formats and indexed colour palette. Not a file format; no dependencies.

  • craft-silhouette-studio: bounded, fail-closed reader for Silhouette Studio .studio and .studio3 documents: outlines, line colours and page size in millimetres. Protected designs are refused.

  • craft-sketch: clean-room reader for the .sketch container (Sketch 48 and newer): the ZIP archive, the version cut, document.json, the pages in document order and images, as the JSON the file holds. Bounded on hostile input. Carved from FigCraft.

  • craft-svg: SVG. sniff recognises SVG and SVGZ data; svgz unpacks SVGZ within a byte limit, decodes UTF-8, UTF-16 and ISO 8859-1, and compresses; guard bounds element nesting and entity expansion before any XML reader sees the text; paths reads geometry (shapes, transforms, <use>/<symbol> instances and the CSS cascade as Bézier paths in millimetres, each tagged by the caller); color parses CSS colours; write writes documents (elements with escaping, path data, numbers). Feature tree: the full parser, usvg at the one version every Craft app uses, re-exported behind an entry point that runs those checks first (plus nesting with references followed, attribute counts, bounded embedded SVGs), and a budget check for drawing a tree with resvg. Apps take usvg from here, not as their own dependency.

  • craft-svg-paths: the former name of craft-svg's paths, color and write; re-exports them for existing users.

  • craft-text: text processing below the composer. Its hyphen module finds hyphenation points, with a bundled US English dictionary and patterns and optional hypher patterns for 47 more languages (one cargo feature each).

  • craft-ui: SVG catalogs, icon buttons, tabs, pane controls, transactional docking, print settings and theme helpers for egui frontends; assets, themes, localization and command handling stay in each app. Requires Rust 1.95 or later.

  • craft-vcard: vCard contacts, from MailCraft: vCard 2.1, 3.0 and 4.0 read (legacy character sets, quoted-printable, labels and Apple label groups, KEY certificates and OpenPGP public keys), vCard 3.0 written. Bounded and panic-free on hostile input. The mapping onto an app's contact type stays in each app.

  • craft-vectorcraft-format: the envelope of VectorCraft's .vectorcraft file: its members, versions, embedded images and the data after the JSON, with the document as a type parameter. The document and its migrations stay in VectorCraft.

  • craft-vectordrawable: Android Vector Drawable writer: a model of paths, groups, clip outlines, strokes and linear, radial and sweep gradients; the XML as Android Studio formats it; and the mapping of a gradient on any affine frame to what a drawable can say. What a drawable cannot draw is the caller's to bake in or leave out. No reader.

  • craft-web-api: the page command API every Craft web build offers its page — one window.<app> shape (request, execute, commands, docInspect, uiInspect, screenshot) over the app's JSON control channel.

  • craft-web-host: the host messages between a Craft app's web build and the page that hosts it (?host=parent or data-host="page"): one contract and one bridge for every app.

  • craft-webp: the WebP container, from EffectCraft (reader) and PhotoCraft (writer): canvas size, alpha and every animation frame's timing from the chunk headers without decoding, and the RIFF container around an encoded VP8 frame with alpha, ICC, EXIF and XMP chunks. The VP8 and VP8L codecs are not part of it.

  • craft-xls: clean-room Excel 97-2003 workbook (.xls, BIFF8) reader: worksheets, cell values, formulas as A1 text (shared and array formulas included), cell formats with resolved palette colours, merged cells, column and row records, defined names, print areas and calculation settings, with limits on records, cells and text.

  • craft-wordmodel: a word-processing document model (stories, paragraphs, runs, tables, sections, styles, numbering, fields, notes, comments, revisions, drawings, math): what the text-format crates read into and write from. WordCraft's model without its editing code.

  • craft-xlsx: Excel workbooks (.xlsx, .xlsm, SpreadsheetML, transitional and strict) and binary workbooks (.xlsb) on craft-opc: the workbook part, shared strings, the styles tables and worksheet rows streamed one at a time, with limits on the package, the XML and the binary records.

  • craft-ora: OpenRaster documents (.ora): the ZIP archive and the stack.xml layer tree as written, read with bounded sizes and written. From PhotoCraft.

  • craft-y4m: YUV4MPEG2 (.y4m) reader, from FilmCraft: the stream header, colour space layouts at 8 to 16 bits, a frame index built from the FRAME lines without loading the file, and plane access. Bounded on hostile input.

  • craft-kra: Krita documents (.kra, .krz), read: the ZIP archive, the maindoc.xml node tree as written, and the tiled pixel files with their LZF compression, a tile at a time. From PhotoCraft.

  • craft-xcf: GIMP XCF images (.xcf, .xcf.gz), read: header, properties, parasites, layers with their item paths, channels, and tiled pixels (uncompressed, RLE, zlib) at every precision, under a caller's byte budget. From PhotoCraft.

  • craft-xml: bounded XML for hostile input: an owned element tree with limits on size, depth, nodes and attributes, streaming of repeated elements, namespace handling (as written, by local name, or canonical prefixes by URI), escaping and a writer. No DTDs and no entity expansion.

  • craft-zip: ZIP archives from untrusted files: an entry-count check before the archive is indexed (ZIP64 included), entry reads within per-entry and total budgets that count real bytes, duplicate-name detection, a strict structure preflight, and a deterministic stored/deflate writer. The shared ZIP layer for the package formats.

  • Shared UI component audit: source inventory, extraction priorities and compatibility boundaries across the Craft suite.

  • Theme infrastructure: eight-app comparison and the small shared widget-state styling boundary.

  • Panel docking: validated panel moves, floating groups, workspace adapters and an optional egui docking surface.

License and credits

craft-libs is dual-licensed under MIT or Apache-2.0, at your option. Copyright (c) 2026 ArtCraft Team and the craft-libs contributors. Required notices are in NOTICE.

Bundled fonts, icons, images and other assets keep their own open licenses; each one is listed with its author, source and license in ATTRIBUTION.md.

S
Description
Readme
123 MiB
Languages
Rust 99.3%
Max 0.3%
Python 0.2%
RenderScript 0.2%