zigimg: a Zig image library whose format table is honest about what is partial
Zig library for reading and writing different image formats
At a glance
- What is it?
- zigimg reads and writes image formats in pure Zig, and its README is unusually candid about the gaps: BMP, JPEG, PGM, PNG, PPM and TIFF are marked partial, TIFF cannot be written at all, and the animated GIF support still lacks the plain text extension. It is a work in progress on Zig 0.17.0.
- Who is it for?
- zigimg fits a Zig project that needs to read or write the simple raster formats without pulling in a C toolchain, and that can live with the documented gaps in TIFF, interlaced PNG and 48-bit PPM. It does not fit a pipeline that needs JPEG with the full feature set, tiled TIFF, or any format marked unreadable such as ICO and XPM.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Zig, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A format table where Partial is the common answer
zigimg is a library for reading and writing different image formats in Zig, and the README calls it a work in progress library to create, process, read and write them. What makes it useful to read is that the format table is precise about what works.
The table lists twenty formats with read and write columns. Fully supported for both directions are BMP with caveats, Farbfeld, GIF, PAM, PBM, PCX, QOI and TGA, with BMP, PGM, PNG and PPM marked partial. IFF, SGI, SUN, XBM and TIFF are read only, and ANIM, ICO and XPM are not supported in either direction. TIFF in particular is listed as a partial read with no write at all, and that single cell tells you more about the library than any marketing sentence would.
The partial labels are not vague, because the per-format sections say what they mean. BMP covers version 4 and version 5 files, 24-bit RGB and 32-bit RGBA, and does not support any compression. PGM supports 8-bit and 16-bit grayscale, and the README notes that 16-bit ASCII grayscale loading is not tested. PPM supports 24-bit RGB with 8 bits per channel and is missing 48-bit RGB.
The distinction between a full row and a partial row is exactly where the surprises live for anyone embedding this in a pipeline, so read the format section for your file type, not just the table.
Two ways to wire it in, and one depends on the package manager
The install section covers two setups. The first is as a submodule, where you clone the repository or add it as a submodule and then point your build at the root source file. The build.zig snippet is three lines:
pub fn build(b: *std.Build) void {
exe.root_module.addAnonymousModule("zigimg", .{ .root_source_file = b.path("zigimg.zig") });
}The second route uses the package manager, which adds zigimg to your build.zig.zon:
zig fetch --save git+https://github.com/zigimg/zigimg.gitand then a dependency block in build.zig:
const zigimg_dependency = b.dependency("zigimg", .{
.target = target,
.optimize = optimize,
});
exe.root_module.addImport("zigimg", zigimg_dependency.module("zigimg"));The target and optimize values are passed through from your own build, so the library inherits the same optimisation mode as the rest of your program rather than imposing its own.
The library currently uses Zig 0.17.0, and the releases follow the compiler rather than the library. The tagged versions are zigimg_zig_0.17.0 on 2026-10-08, zigimg_zig_0.16.0 on 2026-04-19 and zigimg_zig_0.15.1 on 2025-09-22. That naming is a useful signal about the upgrade cost, since the library is released per compiler version and a Zig upgrade means a new library release.
The root of the repository also carries build.zig, build.zig.zon, zig.mod and gyro.zzz, a mix of package manager artefacts from the current and earlier Zig workflows.
The test suite is a separate repository you check out alongside
Testing zigimg takes three steps, and one of them is not in this repository. You check out zigimg, you go back one folder and check out the test suite from the separate zigimg/test-suite repository, and then you run the tests with zig build test:
zig build testThe arrangement makes sense for a library that validates itself against a corpus of real files, since the sample images do not belong in the library repository, but it does mean a fresh clone cannot run the tests on its own. A contributor has to know the sibling repository exists.
The sibling layout is also visible inside this repository, which has both src/ and tests/ directories of its own, so the local tests and the external corpus are two different things. The CI badge in the README covers the continuous integration run, and the project has a Discord community linked from the top of the page.
The README also has a user guide section, and its design philosophy paragraph is cut off in the version available here, so the intent behind the API shape has to be read from the source and the format documentation rather than from the philosophy text.
Format details that decide whether your files will load
The per-format sections are where this library either helps you or quietly refuses to.
GIF is broad: GIF87a and GIF89a, animated GIF with the Netscape application extension for looping information, interlaced images, and tiled and layered images used to achieve pseudo true colour. The gap is the plain text extension, which is not supported.
IFF is a long list: 1 to 8 bit, 24 bit, HAM6/8 and EHB ILBM files, uncompressed, byterun 1 and 2 compressed ILBM, PBM encoded files and ACBM. Colour cycle chunks are ignored and the mask is skipped.
TGA reads version 1 and version 2 files and writes version 2, covering uncompressed and compressed 8-bit grayscale, indexed images with 16-bit and 24-bit colormaps, and truecolor at 16-bit RGB555, 24-bit or 32-bit depth. SGI covers 8-bit, RGB at 24 and 48 bit, RGBA at 32 and 64 bit, with RLE and uncompressed files. SUN covers 1, 8, 24 and 32 bit files with uncompressed and RLE, in BGR and RGB, but not the TIFF, IFF or experimental encodings.
TIFF is the one to read carefully. Supported are bilevel, grayscale, palette and RGB(A) files, most baseline tags, Raw, LZW, Deflate, PackBits and CCITT 1D compression, with both big-endian and little-endian decoding. Missing are tile-based files, YCbCr, CMJN and CIE Lab colour spaces, and JPEG or CCITT Fax 3 and 4 compression. Only the first IFD is decoded and the orientation tag is not supported yet.
PAM is the subtlest constraint. It supports a subset where the tuple type is official or easily inferred, and by extension the depth is four or less, all images in a sequence share the same dimensions and maxval, and the colour formats are grayscale, grayscale with alpha, Rgb555, Rgb24, Rgba32, Bgr24, Bgra32, Rgb48 and Rgba64.
The pixel format list is the real specification
Under supported pixel formats the README gives the type list that a Zig developer will actually code against. Indexed images at 1, 2, 4, 8 and 16 bits per pixel. Grayscale at 1, 2, 4, 8 and 16 bits per pixel, plus 8-bit and 16-bit grayscale with alpha. Truecolor covering RGB332, RGB555, RGB565, RGB24 with 8 bits per channel, RGBA32, BGR555, BGR24, BGRA32, RGB48 and RGBA64 with 16 bits per channel.
Then there is the float option, 32-bit float RGBA, and the README calls this the neutral format. That single line explains a lot about the library's shape. A format like PNG can carry grayscale, grayscale with alpha, indexed, truecolor and truecolor with alpha at 8-bit or 16-bit, and the codec converts into the library's internal representation rather than exposing a different API per source format.
The practical effect is that your code deals with one set of colour types, and the conversion happens on load. It also means the library's own type list bounds what a format can give you, so a 48-bit PPM file that the format itself supports is not something the library will hand you, since PPM support stops at 24-bit RGB.
For a library still described as a work in progress, having a single documented neutral pixel format is a deliberate and useful design decision, and it is the kind of thing that makes the remaining gaps survivable.
MIT, per-compiler releases, and an honest work in progress label
The licence is MIT, with the LICENSE file at the root of the repository. Read that file for the terms themselves, and this is not legal advice. The repository also carries a standard set of community files, a .vscode/ directory for editor configuration, and a .github/ directory holding the CI workflow that the badge refers to.
Maintenance is the strongest part of the story. The library is released for each Zig version, with 0.17.0 in October 2026, 0.16.0 in April 2026 and 0.15.1 in September 2025, and the last push to the repository was on 2026-10-15 with the repository not archived. For a library that follows the compiler's release cycle closely, that is a dependable rhythm.
The caveat is the one the README states outright: this is a work in progress. The format table is the honest summary of where that stands, and the entries marked partial are the author's own flag rather than a defect report you would have to discover.
The upgrade cost for an adopter is therefore tied to Zig itself. A compiler upgrade means a new zigimg release, the format table may shift in either direction between versions, and the fact that some things are marked partial means a version bump can change what your code sees.
Where zigimg is the wrong tool
The first wrong fit is a format that is simply not there. ANIM, ICO and XPM are marked as neither readable nor writable, and there is no plan mentioned for them in the README. If your inputs are Windows icons or X11 pixmaps, this library is not an option.
The second is a production pipeline that needs a specific hard case. Interlaced PNG cannot be written, only read. 48-bit PPM is missing. TIFF cannot be written at all, and reading it handles only the first IFD, so a multi-page TIFF is a partial read by construction. Tiled TIFF, YCbCr, CMYK and CIE Lab TIFF are all out. These are not edge cases in some domains, and in those domains this library is the wrong choice.
The third is the alternative approach, which is worth stating explicitly. A from-scratch implementation in Zig means no C toolchain and no native dependency, and you get exactly the subset each codec implements. Binding an existing C codec through the foreign function interface gives broader format coverage, including the cases listed as partial, and costs you a native build dependency and its own licence. Which trade is right depends on whether your bottleneck is coverage or build simplicity, and for a service that only ever handles PNG and JPEG at 8-bit, the pure Zig path is the quieter one.
The fourth is animation as a first class requirement. GIF animation is supported with the Netscape looping extension, and the README notes that PAM animation with differing maxvals and tuple types is technically possible since each AnimationFrame has its own PixelStorage, but is likely not expected by users. Animated formats beyond GIF are where this library stops.
Editorial conclusion
zigimg fits a Zig project that needs to read or write the simple raster formats without pulling in a C toolchain, and that can live with the documented gaps in TIFF, interlaced PNG and 48-bit PPM. It does not fit a pipeline that needs JPEG with the full feature set, tiled TIFF, or any format marked unreadable such as ICO and XPM. Before adopting it, check the format table row for your file type rather than the headline, because the difference between a full and a partial row is where the surprises live.
Frequently asked questions
How do I add zigimg to a Zig project?
Either clone it as a submodule and add it as an anonymous module pointing at zigimg.zig in your build.zig, or run zig fetch --save git+https://github.com/zigimg/zigimg.git to add it to build.zig.zon and then pull it in with b.dependency in your build.zig.
Which image formats can zigimg read and write?
Farbfeld, GIF, PAM, PBM, PCX, QOI and TGA are supported in both directions, while IFF, SGI, SUN, XBM and TIFF are read only and ANIM, ICO and XPM are not supported. BMP, JPEG, PGM, PNG and PPM are marked partial, and the README describes the limits of each.
How do I run the zigimg test suite?
The test suite lives in a separate repository. Check out zigimg, go back one folder and check out the test suite from the zigimg/test-suite repository, then run zig build test.
Which Zig version does zigimg target?
The library currently uses Zig 0.17.0, and it is released per compiler version, with tags for 0.17.0, 0.16.0 and 0.15.1. A Zig upgrade means moving to the matching zigimg release.
What licence is zigimg released under?
It is MIT licensed, with the LICENSE file at the root of the repository, and the library is described in the README as a work in progress.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/zigimg-zigimg)Was this useful?