-
-
Notifications
You must be signed in to change notification settings - Fork 5
Image Decoders
NyxOS decodes PNG, BMP, GIF (static and animated) and baseline JPEG 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.
| Format | File | Magic | Self-test |
|---|---|---|---|
| PNG | png.c |
89 50 4E 47 |
pngtest |
| BMP | bmp.c |
42 4D (BM) |
bmptest |
| GIF | gif.c |
GIF87a / GIF89a
|
giftest |
| JPEG | jpeg.c |
FF D8 |
jpegtest |
Selene dispatches on those magic bytes, so a format is just another branch in one <img> pipeline.
See also: Selene-Browser, GUI-Subsystem, Shell
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.
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.
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.
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.
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
typedef struct { uint8_t* pixels; uint16_t delay_cs; } gif_frame_t;
typedef struct { uint32_t width, height; int nframes; gif_frame_t* frames; int loop_count; } gif_anim_t;
int gif_decode_anim(const uint8_t* src, uint32_t srclen, gif_anim_t* out);
void gif_anim_free(gif_anim_t* a);gif_decode_anim walks every image descriptor and composites each onto a logical-screen canvas, honouring the per-frame sub-rectangle, transparent index and disposal method. Every frame therefore comes out as a ready-to-blit full-size image, rather than a delta the caller has to apply. A static GIF yields nframes == 1.
Delays are in centiseconds (1/100 s). Selene drives playback from the compositor's per-frame tick.
Loop count (v5.9.93). gif_decode_anim parses the NETSCAPE2.0 Application Extension (21 FF 0B "NETSCAPE2.0" 03 01 LL HH) into gif_anim_t.loop_count: 0 = infinite, N = play N times. A GIF without the extension defaults to 0, so nothing that used to loop regresses — only an explicit finite count stops. Selene counts completed loops and freezes on the last frame once a finite count is reached (a finished animation stops ticking, so it costs no CPU).
Self-test: giftest — a basic palette image, transparency, an interlaced image, one that grows the LZW dictionary, and a multi-frame animation checked for frame count, per-frame RGBA and delays.
int jpeg_decode(const uint8_t* src, uint32_t srclen, image_t* img);Baseline only: sequential DCT, Huffman-coded, 8-bit — the format of essentially every web photo.
| Supported | Rejected cleanly |
|---|---|
| Greyscale | Progressive (SOF2) |
| YCbCr 4:4:4 | Arithmetic coding |
| YCbCr 4:2:2 (h2v1) | 12-bit precision |
| YCbCr 4:2:0 (h2v2) | 4-component CMYK / YCCK |
Restart markers (DRI, RSTn) |
The decoder walks the marker segments — SOI, APPn, DQT, SOF0, DHT, DRI, SOS, EOI — builds canonical Huffman tables, and runs an integer IDCT.
Important
Unsupported variants fail rather than mis-decode. A progressive JPEG returns an error instead of producing garbage pixels.
Subsampled chroma uses libjpeg's triangle-filter ("fancy") upsampling for the two common photo layouts, 4:2:2 and 4:2:0. The original implementation used nearest-neighbour — replicating each chroma sample across its block — which is visibly blocky at colour edges.
Self-test: jpegtest — greyscale, 4:4:4 and 4:2:0 images, each compared to a reference decode within a tolerance.
Note
Exact equality is impossible here. libjpeg's integer IDCT differs from any other implementation by a rounding step, so a byte-exact comparison would fail for a correct decoder. This is the one self-test in the project that is not an exact known-answer check.
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, one per compositor frame, which bounds what a hostile or merely enormous page can allocate.
nyx> deflatetest
nyx> pngtest
nyx> bmptest
nyx> giftest
nyx> jpegtest
Each prints a per-case pass/fail line and returns non-zero on failure.
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, v5.9.86 added GIF, v5.9.87 made loading cooperative, v5.9.88 added animated GIF playback, v5.9.89–v5.9.90 added JPEG and wired it into Selene, v5.9.91 improved JPEG chroma upsampling, and v5.9.93 honoured the GIF loop count. See Version-History.
- Format-Reference - byte layout of each format
- Selene-Browser - the consumer of these decoders
- GUI-Subsystem - how decoded images reach the screen
- Shell - the self-test commands
- RFC 1950 - zlib format - IETF
- RFC 1951 - DEFLATE - IETF
- PNG Specification (Third Edition) - W3C
- GIF89a Specification - CompuServe
NyxOS v6.4.363 · GPL v2 · GitHub · uselessalter on Discord · nyxos@inbox.lv
NyxOS Wiki
Getting started
Kernel
Storage & network
Graphics & apps
Userspace
HOWTO
- HOWTO-Add-a-system-call
- HOWTO-Write-a-userspace-program
- HOWTO-Add-a-shell-command
- HOWTO-Add-a-GUI-application
Reference
- Syscall-Reference
- Command-Reference
- Hardware-Reference
- Format-Reference
- Kernel-Data-Structures
- Source-Tree-Reference
Project