KiteImage
The KiteImage facade. Everything is pure computation on byte arrays: no I/O, no threads, no platform types: so it behaves identically on every KMP target.
val bitmap = KiteImage.decode(bytes) // sniffs the format, dispatches
val anim = KiteImage.decodeAnimation(bytes) // frames + delays + loop count
val format = KiteImage.detect(bytes) // just the sniff
val info = KiteImage.probe(bytes) // size + depth + frames, no decodeFunctions
Decode data into a KiteBitmap, sniffing the format first. Animated inputs yield their first frame (composited); use decodeAnimation for the full sequence.
Identify data's format from its magic bytes, or null if unrecognised.
Encode bitmap as a BMP: 24-bit BI_RGB when it is opaque, or 32-bit BI_BITFIELDS under a V4 header when it carries alpha (plain 32-bit BMP alpha is officially "reserved", and half the world's readers discard it). Uncompressed and lossless either way.
Encode animation as an animated GIF89a: one shared colour table, per-frame delays, and the NETSCAPE2.0 loop count. Frames must all be canvas-sized, which is exactly what decodeAnimation produces.
Encode bitmap as a GIF89a. Colours are quantised to the format's 256-entry limit; images that already fit encode losslessly. Alpha is reduced to GIF's single transparent index at a 50% threshold.
Encode bitmap as a PNG: 8-bit RGB, or RGBA when any pixel carries alpha. Lossless: decoding the result returns the exact same pixels.
probe, but null instead of throwing on unrecognised or malformed input.