Package-level declarations

Types

Link copied to clipboard
open class ImageDecodeException(message: String, cause: Throwable? = null) : Exception

Thrown when input claims to be an image but can't be decoded: truncated data, corrupt structures, failed checksums, dimension overflow, or no recognisable format at all.

Link copied to clipboard

Image container formats KiteImage can identify from magic bytes. Sniffing intentionally recognises more formats than KiteImage.decode currently handles: "that's a WebP we can't decode yet" is a far better error than "unknown format".

Link copied to clipboard
class ImageInfo(val format: ImageFormat, val width: Int, val height: Int, val bitDepth: Int, val hasAlpha: Boolean, val frameCount: Int, val loopCount: Int, val orientation: Orientation, val isDecodable: Boolean, val unsupportedReason: String? = null)

What a file says about itself, read from its header alone: no pixel decode, no multi-megabyte allocation. This is what you want for laying out a grid before the images arrive, rejecting an upload that's 20000 px wide, or deciding whether a decoder should claim a file at all.

Link copied to clipboard
class KiteAnimation(val width: Int, val height: Int, val frames: List<KiteFrame>, val loopCount: Int)

A decoded animation: GIF, APNG and animated WebP all arrive in this shape. Static images decode as a single frame, so KiteImage.decodeAnimation is total over every supported format.

Link copied to clipboard
class KiteBitmap(val width: Int, val height: Int, val argb: IntArray)

A decoded raster image: width × height pixels, packed as non-premultiplied ARGB_8888 in a row-major argb array (argb[y * width + x], alpha in the top byte). One layout for every source format: decoders normalise grayscale, palette, BGR and 16-bit inputs into this on the way out, so consumers and the Compose interop never branch on the source format.

Link copied to clipboard
class KiteFrame(val bitmap: KiteBitmap, val delayMillis: Int, val delayRawCentiseconds: Int)

One presented frame of an animation: the fully composited canvas (disposal methods, transparency overlay and frame offsets already applied), plus its display duration.

Link copied to clipboard
object 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.

Link copied to clipboard

How a decoded image relates to the scene it was captured from: the EXIF Orientation tag (TIFF tag 274), which phone cameras write instead of physically rotating pixels. A portrait photo is usually stored landscape with Rotate90 set, so anything that draws raw decoded pixels shows it sideways.

Link copied to clipboard

The input is a well-formed image in a format, or a format feature, KiteImage doesn't decode: lossy WebP, an arithmetic-coded JPEG, a CgBI PNG. The message always names the specific feature, and KiteImage.probe reports the same thing up front through ImageInfo.unsupportedReason, so a caller can route the file elsewhere instead of catching this.

Functions

Link copied to clipboard
fun KiteAnimation.cropped(x: Int, y: Int, width: Int, height: Int): KiteAnimation

cropped applied to every frame, preserving delays and loop count.

fun KiteBitmap.cropped(x: Int, y: Int, width: Int, height: Int): KiteBitmap

Copy the width×height region whose top-left corner is (x, y).

Link copied to clipboard

Mirror left-to-right.

Link copied to clipboard

Mirror top-to-bottom.

Link copied to clipboard

oriented applied to every frame, preserving delays and loop count.

Apply an EXIF orientation so the result is oriented the way the camera meant it to be seen. Orientation.Normal returns the same instance.

Link copied to clipboard

rotated180 applied to every frame.

Rotate a half turn. Dimensions are unchanged.

Link copied to clipboard

rotated270 applied to every frame.

Rotate a quarter turn counter-clockwise. Width and height swap.

Link copied to clipboard

rotated90 applied to every frame.

Rotate a quarter turn clockwise. Width and height swap.

Link copied to clipboard
fun KiteAnimation.scaled(maxWidth: Int, maxHeight: Int): KiteAnimation

Downscale every frame of an animation to fit inside maxWidth×maxHeight (same box filter and aspect handling as KiteBitmap.scaled), preserving delays and the loop count. This is where animated memory goes: a full-screen GIF shown as an avatar keeps W×H×4 bytes per frame unless scaled down.

fun KiteBitmap.scaled(maxWidth: Int, maxHeight: Int): KiteBitmap

Downscale to fit inside maxWidth×maxHeight, preserving aspect ratio, using box (area-average) filtering: each destination pixel averages every source pixel that maps into its bin, so thumbnails don't shimmer the way nearest-neighbor ones do.

Link copied to clipboard

Mirror across the main diagonal: dst(x, y) = src(y, x). Axes swap.

Link copied to clipboard

Mirror across the anti-diagonal. Axes swap.