Skip to content

Latest commit

 

History

17 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Zig PPM Viewer

A small PPM image viewer written in Zig using raylib via raylib-zig.

Requirements

  • Zig 0.16.0 or newer

Dependencies are fetched automatically by the Zig package manager on first build.

Running

The viewer takes the path to a PPM file as its only argument:

zig build run -- images/p6.ppm

The -- separates Zig's own arguments from the program's. Two sample images are included:

File Format Size on disk
images/p3.ppm P3 (ASCII) 2.9 MB
images/p6.ppm P6 (binary) 733 KB

Both are the same 500 × 500 image — the P3 encoding is roughly 4× larger because every channel is written out as decimal text.

To just build the executable (output lands in zig-out/bin/):

zig build

Paths are resolved relative to the current working directory, so run from the project root or pass an absolute path.

Controls

Key Action
Esc Close the window

How it works

The window is sized to the image, and the image is drawn at 1:1 into it — there is no zoom, pan, or scaling.

Reading happens in three stages:

  1. parseHeader reads the magic number and dimensions, and records the byte offset where pixel data begins. That offset is what makes binary P6 work: after the maxval there is exactly one whitespace byte, and everything past it is raw data that must never be treated as text.
  2. decode turns the raster into tightly packed RGB bytes — three per pixel. P6 is a straight copy; P3 is parsed from decimal text. This runs once, before the window opens.
  3. drawImage walks the decoded buffer each frame and draws one rectangle per pixel.

Decoding up front is what keeps the P3 path cheap. Parsing 750,000 decimal numbers per frame at 30 fps would be 22.5 million parseInt calls a second; doing it once means the render loop is identical for both formats.

Project layout

src/main.zig
├── Header       # dimensions, format, raster byte offset
├── parseHeader  # magic number, dimensions, where pixel data starts
├── decode       # P3 text or P6 binary -> packed RGB bytes
├── drawImage    # per-pixel draw from the decoded buffer
└── main         # args, file read, window setup, render loop

Limitations

  • maxval is assumed to be 255. The header field is skipped rather than read. Files using a smaller maximum render too dark, and 16-bit files (maxval above 255) are not supported at all.
  • Only whole-line header comments are skipped. A comment that follows a value on the same line, like 500 500 # dimensions, will fail to parse.
  • The format field is not validated. Anything that isn't exactly P6 is decoded as P3.
  • Files are capped at 4 MB. A larger image is rejected rather than read.
  • Every pixel is redrawn every frame as an individual rectangle. Uploading the decoded buffer to a texture once would be far faster, at the cost of not driving the pixels directly.

About

PPM Image Viewer built with Zig

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages