image

Pure MoonBit image codecs and icon container encoders.

image
png
icon
ico
icns
moon add Nanaloveyuki/image@0.1.1
Download zip
Version
0.1.1
License
Apache-2.0
Last updated
18 days ago
Downloads
164

Dependencies

README

#image

Nanaloveyuki/image is Orbit's lightweight pure MoonBit image companion. It decodes PNG into RGBA8, resizes in premultiplied-alpha space, deterministically encodes PNG, and assembles ICO and ICNS containers. All APIs accept and return Bytes; the library has no filesystem or CLI surface and links no native image library. New capabilities are added only for a concrete Orbit requirement.

#Install

After the package is published to MoonCake, add it to a MoonBit module:

moon add Nanaloveyuki/image

Import the root package from the consuming package's moon.pkg:

import { "Nanaloveyuki/image", }

#Decode and Encode PNG

decode_png verifies every PNG chunk CRC and the zlib checksum before returning an Image. It applies limits before allocation and streams decompression into a bounded output buffer.

fn normalize_icon(source : Bytes) -> Bytes raise @image.ImageError {
let image = @image.decode_png(source)
let square = @image.square_image(image)
let resized = @image.resize_lanczos3(square, 256, 256)
@image.encode_png(resized, compression_level=6)
}

The decoder accepts non-interlaced 8-bit grayscale, palette, RGB, grayscale-alpha, and RGBA PNGs. Unsupported PNG layouts return ImageError; they are never partially decoded. Use default_decode_limits() as the baseline or pass a narrower DecodeLimits value to decode_png.

encode_png emits exactly IHDR, IDAT, and IEND, so output is stable for a fixed library version, source image, and compression level.

#Generate Icons

Icon encoders require a square source image by default. This makes source image requirements explicit; square_image(image, policy=CenterCrop) is available when the caller deliberately wants center cropping.

fn icon_artifacts(source : Bytes) -> (Bytes, Bytes, Array[@image.PngVariant]) raise @image.ImageError {
let image = @image.square_image(@image.decode_png(source))
let pngs = @image.encode_png_sizes(image, [16, 32, 64, 128, 256])
let ico = @image.encode_ico(image)
let icns = @image.encode_icns(image)
(ico, icns, pngs)
}

encode_ico defaults to 16/24/32/48/64/128/256 PNG entries. encode_icns defaults to 16 through 1024 and emits the matching Retina ICNS PNG chunk types. Writing returned bytes to project-specific paths is the caller's responsibility.

#SVG Wrapper

png_data_uri_svg(png, width, height) wraps an existing PNG as a base64 data URI inside SVG. It does not vectorize pixels and is not used by the icon encoders.

#Development

See docs/development.md for local validation, API-change requirements, and contribution review rules.

#
ImageError

pub suberror ImageError {
ImageError(ImageErrorKind, String)
}

#
DecodeLimits

pub(all) struct DecodeLimits {
max_input_bytes : Int
max_dimension : Int
max_pixels : Int
}

Limits applied before allocating decoded image buffers.

#
Image

pub(all) struct Image {
width : Int
height : Int
pixels : Bytes
} derive(Eq)

RGBA8 image data in row-major order.

#
Image::is_square

fn Image::is_square(self : Image) -> Bool

#
Image::new

fn Image::new(width : Int, height : Int, pixels : Bytes) -> Image raise ImageError

Construct a checked RGBA8 image.

#
ImageErrorKind

pub(all) enum ImageErrorKind {
InvalidInput
ResourceLimit
UnsupportedFormat
InvalidDimensions
NotSquare
} derive(Eq,
Debug
)

#
PngVariant

pub(all) struct PngVariant {
size : Int
png : Bytes
}

#
SquarePolicy

pub(all) enum SquarePolicy {
Strict
CenterCrop
} derive(Eq,
Debug
)

#
decode_png

fn decode_png(input : Bytes, limits? : DecodeLimits) -> Image raise ImageError

Decode a non-interlaced, 8-bit PNG into RGBA8. Every chunk checksum and the zlib Adler-32 checksum are verified before returning pixels.

#
default_decode_limits

fn default_decode_limits() -> DecodeLimits

Default limits: 64 MiB compressed input, 16,384 pixels per edge, 64 MiB RGBA.

#
default_icns_sizes

fn default_icns_sizes() -> Array[Int]

#
default_ico_sizes

fn default_ico_sizes() -> Array[Int]

#
encode_icns

fn encode_icns(image : Image, sizes? : Array[Int], compression_level? : Int) -> Bytes raise ImageError

Encode a deterministic ICNS containing PNG chunks for standard macOS icon sizes and their Retina chunk counterparts.

#
encode_ico

fn encode_ico(image : Image, sizes? : Array[Int], compression_level? : Int) -> Bytes raise ImageError

Encode an ICO whose directory entries point to PNG payloads.

#
encode_png

fn encode_png(image : Image, compression_level? : Int) -> Bytes raise ImageError

Encode image pixels as a deterministic RGBA PNG with no metadata chunks.

#
encode_png_sizes

fn encode_png_sizes(image : Image, sizes : Array[Int], compression_level? : Int) -> Array[PngVariant] raise ImageError

Encode caller-selected square PNG icon sizes in the requested order.

#
png_data_uri_svg

fn png_data_uri_svg(png : Bytes, width : Int, height : Int) -> String raise ImageError

Wrap a PNG byte sequence in a portable data-URI SVG image element.

#
resize_lanczos3

fn resize_lanczos3(image : Image, width : Int, height : Int) -> Image raise ImageError

Resize RGBA8 pixels with a Lanczos3 reconstruction filter in premultiplied alpha space. Premultiplication prevents transparent colors from producing dark fringes after resampling.

#
square_image

fn square_image(image : Image, policy? : SquarePolicy) -> Image raise ImageError

Return a square source image. Strict rejects a non-square input; the opt-in crop policy retains the centered square region.

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io