Skip to content

Image Decoders

kazah-png edited this page Jul 26, 2026 · 3 revisions

Image Decoders

NyxOS decodes PNG, BMP and GIF into RGBA in the kernel, on top of a from-scratch DEFLATE implementation. The whole pipeline exists so Selene Browser can draw the pictures on a real web page.

See also: Selene Browser, GUI Subsystem, Shell

The common format

Every decoder produces the same thing, so callers stay format-agnostic:

typedef struct {
    uint32_t width, height;
    uint8_t* pixels;        // RGBA, 4 bytes per pixel, width*height*4, kmalloc'd
} image_t;

Selene picks a decoder from the content, holds an image_t, and draws it without caring which format it came from.

DEFLATE and zlib (inflate.c)

The decompression core PNG's IDAT stream needs, implemented against RFC 1951 and RFC 1950.

int inflate_raw (const uint8_t* src, uint32_t srclen,
                 uint8_t* dst, uint32_t dstcap, uint32_t* outlen);
int zlib_inflate(const uint8_t* src, uint32_t srclen,
                 uint8_t* dst, uint32_t dstcap, uint32_t* outlen);
Function Handles
inflate_raw Raw DEFLATE — stored, fixed-Huffman and dynamic-Huffman blocks
zlib_inflate The zlib wrapper: 2-byte header, DEFLATE body, and a verified trailing Adler-32

Both return 0 on success and a negative code on a corrupt stream or an output overflow.

Self-test: deflatetest — fixed, dynamic and stored blocks, plus a zlib case with Adler-32.

PNG (png.c)

int  png_decode(const uint8_t* src, uint32_t srclen, image_t* img);
void png_free(image_t* img);
Supported Not supported
8-bit depth 16-bit depth
Colour types: grayscale, RGB, palette, gray+alpha, RGBA Interlaced (Adam7) images
All five scanline filters: None, Sub, Up, Average, Paeth

Self-test: pngtest — an embedded PNG of each colour type, exercising every filter type.

BMP (bmp.c)

int bmp_decode(const uint8_t* src, uint32_t srclen, image_t* img);

Uncompressed (BI_RGB) BITMAPINFOHEADER bitmaps — the shapes still found on the web:

  • 24-bit BGR
  • 32-bit BGRX
  • 8-bit palette
  • Bottom-up and top-down row order

Self-test: bmptest — 24/32/8-bit plus a top-down image, against expected RGBA.

GIF (gif.c)

int gif_decode(const uint8_t* src, uint32_t srclen, image_t* img);

Decodes the first frame of a GIF87a or GIF89a, including a real LZW decompressor:

  • Global and local colour tables
  • LZW decompression with dictionary growth and clear codes
  • Interlaced images
  • A transparent colour index

Animation is not supported — subsequent frames are ignored.

Self-test: giftest — a basic palette image, transparency, an interlaced image, and one that grows the LZW dictionary.

Memory

Every decoder kmallocs img->pixels. Release it with png_free(&img) (or kfree(img.pixels)). Selene frees decoded images when a page is replaced or a tab closes.

Selene caps a per-image download at 512 KB and decodes at most 8 images per page load, which bounds what a hostile or merely enormous page can allocate.

Testing them all

deflatetest
pngtest
bmptest
giftest

Each prints a per-case pass/fail line and returns non-zero on failure.

History

v5.9.81 added inflate, v5.9.82 PNG, v5.9.83 wired real images into Selene, v5.9.84 made loading lazy and progressive, v5.9.85 added BMP and generalised the pipeline behind image_t, and v5.9.86 added GIF. See Version History.

See also

External resources

Clone this wiki locally