Files
craft-libs/crates/kra/README.md
Dylan M. Taylor 473fe09862 Add craft-kra: Krita archives, maindoc.xml and tiled pixel files, from PhotoCraft (#928)
* Add craft-kra: Krita archives, maindoc.xml and tiled pixel files, from PhotoCraft

The format half of PhotoCraft's Krita import (crates/io/src/kra.rs and kra/tiles.rs at
abeb16c96): the archive and its mimetype, maindoc.xml as a tree of nodes with the attributes
Krita writes, the tiled pixel files and their LZF compression. The mapping onto a document
(blend modes, surfaces, warnings) stays in the app.

maindoc.xml is read with craft-xml and the archive with the zip crate.

* craft-kra: a default pixel is read under a one-pixel limit

The .defaultpixel member (1 to 8 bytes) was inflated under the 1 GiB layer-file limit before
its size was checked.

Ported from storytold/photocraft#11138.

* craft-kra: the tile table is not reserved from the declared count

A tiled file may declare one record per eight bytes of its size. Reserving that many up front
is 3 GiB for a 1 GiB member that holds none of them. Reserve 65,536 records at first and grow
as records are read, never past the declared count.

Ported from storytold/photocraft#13309.
2026-11-11 18:42:26 -05:00

45 lines
2.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# craft-kra
Krita documents (`.kra`, `.krz`), read. Written from files Krita writes; no Krita code is used.
A Krita document is a ZIP whose first, stored entry is `mimetype` = `application/x-krita`. It
holds `maindoc.xml` (the node tree), one tiled pixel file per paint layer and mask under
`<image name>/layers/`, the ICC profile in `<image name>/annotations/icc`, and Krita's rendering
of the whole image in `mergedimage.png`.
- `is_kra`, `zip_mimetype`: recognise an archive by its first entry, without unzipping.
- `Archive::open`: checks the mimetype and reads `maindoc.xml` into an `Image` of `Node`s. Every
node kind is kept with the attributes the file has (`nodetype`, `compositeop`, `opacity`,
offsets, `colorspacename`, `filename`, masks, ...). No pixel is read.
- `Archive::layer_file`, `default_pixel`, `icc_profile`, `merged_image`: the other entries, each
with a size limit.
- `tiles::TileFile`: a tiled pixel file's header and tile table; `decode` gives one tile's
interleaved pixels. `tiles::lzf_decompress` is the LZF inside.
- `tiles::Space`: the pixel layouts read (`RGBA`, `RGBA16`, `GRAYA`, `GRAYAU16`, and one-byte
masks), with `rgba` and `samples` to turn Krita's B, G, R, A little-endian pixels into channel
order.
What a node kind, a composite operation or a colour space means to an application is not decided
here. There is no writer.
## Limits
| Limit | Value |
| --- | --- |
| Canvas side | 300,000 px (`MAX_SIDE`); offsets and tile positions up to four times that |
| Canvas area | 1 GiB at 8 bytes per pixel (`MAX_PIXEL_BYTES`) |
| `<layer>` nodes | 8192 (`MAX_NODES`) |
| `maindoc.xml` | 32 MiB, 512 levels of nesting, no internal DTD subset |
| A pixel file, inflated | 1 GiB (`MAX_LAYER_FILE`) |
| ICC profile | 16 MiB |
| Tile | 1024 × 1024 px, 64 bytes per pixel, header lines of 256 bytes |
A pixel file is decoded one tile at a time into a buffer the caller owns, so the memory a
document takes is the caller's to budget.
## ZIP
The archive is read with the `zip` crate directly. `zip_mimetype` (the leading stored `mimetype`
entry) and the bounded entry read are the same in every mimetype-first ZIP format and belong in a
shared ZIP crate once there is one.