Image codecs for MoonBit: PNG, QOI, BMP, TGA, JPEG, GIF and WebP, and the pixel arithmetic between them.
let image = @moonimage.decode(bytes) // whichever format the bytes are
image.width // 640
image.height // 480
image.format // @moonimage.PixelFormat::Rgba8
let small = image.scale(160, 120, sampling=@moonimage.Sampling::Bilinear)
let file = @moonimage.encode(small, @moonimage.Format::Png)let image = @moonimage.decode(bytes, limits=@moonimage.Limits::strict())let refused : @moonimage.Refused = try {
ignore(@moonimage.decode(b"not an image"))
abort("unreachable")
} catch {
error => error
}
println("\{refused}") // at 0: 6e 6f 74 20 61 6e is not a format this library reads| Format | Read | Write | Animation | Package |
|---|---|---|---|---|
| PNG | every colour type and depth, palette and tRNS, Adam7, five filters, CRC, gAMA cHRM sRGB iCCP tEXt zTXt iTXt | 8 and 16 bits, palette when it is smaller, adaptive filtering, interlaced on request, metadata | APNG | @moonimage/png |
| QOI | all six opcodes | the reference encoder's choices, byte for byte | — | @moonimage/qoi |
| BMP | every header version, 1/4/8/16/24/32 bits, BI_RGB BI_RLE4 BI_RLE8 BI_BITFIELDS, both row orders | 24 and 32 bits | — | @moonimage/bmp |
| TGA | colour mapped, true colour and grey, run lengths, 8/15/16/24/32 bits, both row orders | 24 and 32 bits, run lengths on request | — | @moonimage/tga |
| JPEG | baseline and progressive, every subsampling, greyscale, EXIF orientation | baseline, quality 1–100 | — | @moonimage/jpeg |
| GIF | palettes, transparency, interlace, run lengths | palette by exact colours or median cut, dithering | yes | @moonimage/gif |
| WebP | lossless (VP8L) with its four transforms, colour cache and prefix code groups, and lossy (VP8) with its boolean coder, fourteen predictors, loop filter and chroma upsampling; alpha in either; animated files | lossless, with a predictor transform and LZ77 | yes | @moonimage/webp |
pub(all) struct Image {
width : Int
height : Int
format : PixelFormat
stride : Int
pixels : Bytes
premultiplied : Bool
metadata : Metadata
}| Pixel format | Samples | Bytes a pixel |
|---|---|---|
| Gray8, GrayAlpha8, Rgb8, Rgba8 | 8-bit | 1, 2, 3, 4 |
| Gray16, GrayAlpha16, Rgb16, Rgba16 | 16-bit, big-endian | 2, 4, 6, 8 |
| RgbaF32 | floats, 0–1, little-endian | 16 |
let grey = image.convert(@moonimage.PixelFormat::Gray8)
let wide = image.convert(@moonimage.PixelFormat::Rgba16)
let flat = image.to_premultiplied() // colour × alpha
let back = flat.to_straight()image.flip_horizontal()
image.flip_vertical()
image.rotate(quarters=1) // clockwise, and it wraps
image.crop(16, 16, 64, 64) // raises if it does not fitlet thumb = image.scale(160, 120, sampling=@moonimage.Sampling::Lanczos)pub(all) struct Metadata {
gamma : Double?
chromaticities : Chromaticities?
intent : Intent?
icc : Icc?
texts : Array[Text]
}let animation = @moonimage.decode_animation(bytes)
animation.width // the canvas
animation.frames.length() // 12
animation.frames[3].delay // milliseconds
animation.frames[3].dispose // Keep, Background or Previous
animation.frames[3].blend // Source or Over
animation.compose() // every frame as a full canvas@moonimage.Limits::default() // 1 Mpx a side, 256 megapixels, 1 GiB
@moonimage.Limits::strict() // 8192 a side, 64 megapixels, 256 MiB| Call | What it does |
|---|---|
| decode(bytes, limits?) | read an image, whichever format the bytes are |
| decode_animation(bytes, limits?) | read every frame; a still image is one frame |
| encode(image, format) | write an image, with that format's defaults |
| encode_animation(animation, format) | write the frames, or the first one where the format has no animation |
| Format::of(bytes), Format::extension, Format::mime | what the bytes are, and how they are named |
| Image::new, Image::of | an image, blank or over bytes that already exist |
| Image::row, Image::pixel | one row, one pixel |
| Image::convert | the same image in another sample format |
| Image::to_premultiplied, Image::to_straight | colour × alpha, and back |
| Image::flip_horizontal, Image::flip_vertical, Image::rotate, Image::crop | moving pixels without reading them |
| Image::scale | a new size, by nearest, bilinear or Lanczos |
| Animation::new, Animation::compose | frames, and every frame as a full canvas |
| png.encode, png.decode, png.EncodeOptions, png.Filter | PNG, with its compression level and row filter |
| qoi.encode, qoi.decode | QOI |
| bmp.encode, bmp.decode, bmp.EncodeOptions, bmp.Depth | BMP, 24 or 32 bits |
| tga.encode, tga.decode, tga.EncodeOptions, tga.Depth | TGA, with run lengths |
| jpeg.encode, jpeg.decode, jpeg.EncodeOptions, jpeg.Subsampling, jpeg.exif_orientation | JPEG, and the orientation a camera wrote |
| gif.encode, gif.encode_animation, gif.decode, gif.decode_animation, gif.EncodeOptions | GIF, with dithering and transparency |
| webp.decode, webp.decode_animation, webp.encode, webp.encode_animation | WebP: lossless and lossy read, lossless written |
| webp.decode_lossy, webp.decode_alpha, webp.decode_lossless_stream | one chunk at a time, for a caller that has already split the container |
Install
Download zipImage codecs for MoonBit: PNG, QOI, BMP, TGA, JPEG, GIF and WebP, and the pixel arithmetic between them.