Skip to content

std/image ​

The 8-bit Image that std/png and std/jpeg both decode to and encode from, and the operations that make it useful between them: crop, resize, quarter-turn rotations, flips, and oriented for applying a JPEG's EXIF orientation tag.

Pixels are row-major and top-down with channels interleaved bytes each (1 gray, 3 RGB, 4 RGBA) and no row padding, so pixels[(y * width + x) * channels + c] is one sample.

milo
from "std/image" import { Image, ResizeFilter }

Example ​

milo
from "std/fs" import { readFile, writeFile }

// Image.decode picks PNG or JPEG from the file's signature.
let img = Image.decode(readFile("in.jpg")!)!
let square = img.crop(0, 0, img.height, img.height)!
let small = square.resize(256, 256, ResizeFilter.Lanczos3)!
writeFile("out.png", small.rotate90().encodePng()!)!

resize is separable and computes its taps the way Pillow does: when shrinking, the kernel widens with the scale so every source pixel contributes, which makes ResizeFilter.Area an exact area average and keeps Bilinear and Lanczos3 from aliasing. Channels are filtered independently, so RGBA is not premultiplied.

API reference ​

Image ​

milo
pub struct Image

An 8-bit image. The methods below assume it is well formed: pixels.len == width * height * channels, which every decoder and method here guarantees for the images it returns.

Fields:

  • width: i64
  • height: i64
  • channels: i64: 1 (gray), 3 (RGB) or 4 (RGBA)
  • pixels: string: row-major, top-down, channels bytes per pixel, no row padding

Image.crop ​

milo
fn Image.crop(self: &Image, x: i64, y: i64, w: i64, h: i64): Result<Image, string>

The w x h rectangle whose top-left corner is (x, y). Err when the rectangle is empty or reaches outside the image.

Image.decode ​

milo
fn Image.decode(src: &string): Result<Image, string>

Decode a PNG or JPEG, chosen by the file's signature bytes. JPEG EXIF orientation is not applied; see Jpeg.orientation and Image.oriented.

Image.encodePng ​

milo
fn Image.encodePng(self: &Image): Result<string, string>

Encode as PNG (8-bit gray, RGB or RGBA by channel count).

Image.flipHorizontal ​

milo
fn Image.flipHorizontal(self: &Image): Image

Mirrored left to right.

Image.flipVertical ​

milo
fn Image.flipVertical(self: &Image): Image

Mirrored top to bottom.

Image.oriented ​

milo
fn Image.oriented(self: &Image, orientation: i64): Image

The image as it should be displayed given an EXIF orientation tag (1-8, as Jpeg.orientation returns): 6 is a camera held upright, stored rotated, and comes back turned 90 degrees clockwise. Values outside 2..8 return an unchanged copy.

Image.resize ​

milo
fn Image.resize(self: &Image, width: i64, height: i64, filter: ResizeFilter): Result<Image, string>

Resample to width x height with filter, separably (rows, then columns). Channels are filtered independently; RGBA is not premultiplied, so a hard alpha edge can pick up the colour of fully transparent neighbours. Err when either target side is not positive.

Image.rotate180 ​

milo
fn Image.rotate180(self: &Image): Image

Rotated half a turn.

Image.rotate270 ​

milo
fn Image.rotate270(self: &Image): Image

Rotated three quarter turns clockwise, i.e. a quarter turn counter-clockwise.

Image.rotate90 ​

milo
fn Image.rotate90(self: &Image): Image

Rotated a quarter turn clockwise (width and height swap).

ResizeFilter ​

milo
pub enum ResizeFilter

The resampling kernel for Image.resize.

Variants:

  • Area: Box filter: each output pixel is the area-weighted mean of the source pixels it covers. The right choice for downscaling; upscaling with it is nearest-neighbour.
  • Bilinear: Triangle filter over the 2x2 nearest source pixels (widened to the covered area when downscaling).
  • Lanczos3: Windowed sinc with 3 lobes: sharpest, at the cost of slight ringing on hard edges.