# gizlang:image

JPEG, PNG and WebP pictures decoded at the smallest scale that a use needs, scaled, turned upright and coded again, written in Gizlang. A JPEG is decoded at 1/8, 1/4, 1/2 or full scale: the inverse DCT runs on the low n × n coefficients of each block only (n = 1 is the DC term, the block's mean), and a progressive file at 1/8 reads its DC scans and skips the others. A PNG streams through inflate, and each pixel is added into its box of a power-of-two downscale, so a full-size picture is never in memory. A lossy WebP decodes whole, bit for bit as libwebp decodes it. fit scales by area averaging, resize as Pillow's LANCZOS does; jpeg writes a baseline JPEG with the Annex K tables, png an RGB or RGBA PNG, webp a lossy WebP that libwebp decodes to the same pixels.

```gizlang
import * as Image from "gizlang:image";
```

## Types

### `Image`

```gizlang
type Image = { width: i64; height: i64; channels: i64; pixels: bytes; }
```

Pixels, rows top to bottom, `channels` bytes each: 3 is RGB, 4 is RGBA (alpha not premultiplied).

- `width`: `i64`
- `height`: `i64`
- `channels`: `i64`
- `pixels`: `bytes`

## Functions

### `format`

```gizlang
function format(data: bytes): string
```

The picture format of `data` that decode reads: "jpeg", "png", "webp", or "" for any other.

Effects: fail.

### `decode`

```gizlang
function decode(data: bytes, least: i64): Image throws string requires least> = 1 { const kind = format(data)
```

The JPEG, PNG or WebP picture `data`, decoded at the smallest scale (1/2^k) whose longer side is at least `least`
(whole when it is smaller; a WebP always whole) and turned upright by its EXIF orientation. A file cut short decodes
as far as it goes.

Effects: fail.

### `resize`

```gizlang
function resize(image: Image, width: i64, height: i64): Image requires width> = 1 && height> = 1 { const ch = image.channels
```

`image` at width x height by a Lanczos filter of 3 lobes, each channel alone, as Pillow's resize with LANCZOS
makes it, bit for bit: the rows first, then the columns, each pass with its weights in 22-bit fixed point and its
bytes rounded.

Effects: fail.

### `rgb`

```gizlang
function rgb(image: Image): Image
```

`image` as 3 channels: gray as RGB, an alpha channel over white.

Effects: fail.

### `planes`

```gizlang
function planes(image: Image): Vec<f32>
```

The channel planes of `image` (each channel's rows, a channel after another) in [0, 1]: a pixel's byte / 255.

Effects: fail.

### `bilinear`

```gizlang
function bilinear(image: Image, x: i64, y: i64, w: i64, h: i64, width: i64, height: i64): Vec<f32> requires width> = 1 && height> = 1 && x> = 0 && y> = 0 && x + w <= image.width && y + h <= image.height { const ch = image.channels
```

The RGB planes (as planes() gives them; gray as RGB, alpha dropped, as Pillow's convert("RGB")) of the part of
`image` at x, y of w x h pixels, resized to width x height as torch's bilinear interpolate makes it (align_corners
false, no antialiasing), in f32.

Effects: fail.

### `fit`

```gizlang
function fit(image: Image, side: i64): Image requires side> = 1 { const longer = maxI64(image.width, image.height)
```

`image` scaled down by area averaging so that its longer side is at most `side`; a smaller one is returned as is.

Effects: fail.

### `jpeg`

```gizlang
function jpeg(image: Image, quality: i64): bytes requires quality> = 1 && quality <= 100
```

`image` as a baseline JPEG of `quality` (1 to 100, the IJG scale of the Annex K tables), with full-resolution color;
alpha is dropped.

Effects: fail.

### `png`

```gizlang
function png(image: Image): bytes
```

`image` as a PNG: 8-bit RGB, or RGBA for 4 channels; each row Paeth-filtered, then deflated.

Effects: fail.

### `webp`

```gizlang
function webp(image: Image, quality: i64): bytes requires quality> = 1 && quality <= 100
```

`image` as a lossy WebP of `quality` (1 to 100, as cwebp's -q); alpha is dropped.

Effects: fail.

