Library / SDK
randy408/libspng avatar
randy408/libspng

libspng offers a smaller PNG API, and it is not a drop-in for libpng

Simple, modern libpng alternative

849 stars95 forksCBSD-2-Clause

At a glance

What is it?
libspng is a C library for reading and writing PNG files that trades libpng's API compatibility for a simpler context based interface, optional zlib and a heavy fuzzing and static analysis regime. It is a good fit for new code, and an expensive one to retrofit, because the two libraries do not share an API.
Who is it for?
libspng suits a new C project that needs PNG decoding or encoding with a small API surface, no zlib requirement, and a maintained security process behind it. It is a poor fit for an existing codebase built on libpng, because the README states plainly that the projects are separate and the APIs are not compatible, so a migration is a rewrite of the image handling layer rather than a swap.
Can I use it commercially?
Yes. BSD-2-Clause 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 53 days ago.
What is it written in?
Mainly C, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Same file format, deliberately different API

libspng is a C library for reading and writing Portable Network Graphics format files with a focus on security and ease of use. The critical caveat arrives in the third line of the README: it is an alternative to libpng, the projects are separate and the APIs are not compatible. That single sentence determines who should adopt it. There is no compatibility layer, no drop-in replacement and no gradual migration path, so an application that already links libpng and calls png_create_read_struct and friends cannot switch by swapping a library name. What you get instead is a smaller API. The stated motivation is to provide a fast PNG library with a simpler API than libpng, and it outperforms the reference implementation in common use cases, which is a claim the project backs with a benchmark chart on its site. The user is therefore a new code base, or a subsystem you are willing to rewrite, where the API shape matters more than the sunk cost of the existing integration.

What the feature matrix says about each library

The README compares four libraries across eight capabilities, and the table is more informative than the prose. libspng supports decoding from a stream, gamma correction, progressive image read, parsing of all standard chunks, encoding, and it does not require zlib. Against stb_image, which is listed as lacking gamma correction, progressive read and full chunk parsing, libspng is clearly the more complete decoder. Against lodepng, which is listed as unable to decode from a stream, the same advantage applies. Animated PNG is the one place where libspng is behind, since the table marks it as planned, while libpng has it with a third party patch, and the footnote explains that building with miniz is supported if you want to avoid a zlib dependency. The security row is a claim about process rather than a feature, and it is explained in the footnote that the project is fuzz tested on OSS-Fuzz and that vulnerabilities are fixed before they become public.

The decoder is a context, a buffer and two calls

The API shape is the practical difference. A decode starts by creating a context, pointing it at an input buffer, asking for the output size and then decoding into your own memory. From the README's usage example:

c
#include <spng.h>

/* Create a decoder context */
spng_ctx *ctx = spng_ctx_new(0);

/* Set an input buffer */
spng_set_png_buffer(ctx, buf, buf_size);

/* Determine output image size */
spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &out_size);

/* Decode to 8-bit RGBA */
spng_decode_image(ctx, out, out_size, SPNG_FMT_RGBA8, 0);

Two properties of that shape are worth naming. The output format is a parameter rather than a property of the file, so the same decode call produces RGBA8, or another format, without a separate code path. And the context owns its resources, so the library hands back the memory it allocated, which is what the example does with spng_ctx_free once the pixels have been copied out. The encoder mirrors the same structure but needs a flag at context creation and an explicit header describing the image:

c
/* Creating an encoder context requires a flag */
spng_ctx *enc = spng_ctx_new(SPNG_CTX_ENCODER);

/* Encode to internal buffer managed by the library */
spng_set_option(enc, SPNG_ENCODE_TO_BUFFER, 1);

/* Specify image dimensions, PNG format */
struct spng_ihdr ihdr =
{
    .width = width,
    .height = height,
    .bit_depth = 8,
    .color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA
};

The encoder then writes into a buffer the library manages, which the caller retrieves with spng_get_png_buffer and, as the example notes, owns and frees after a successful call.

Fuzzing, static analysis and a large correctness suite

The security story is the strongest part of the project and it is unusually well evidenced. The code is written according to the rules of the CERT C Coding Standard, all integer arithmetic is checked for overflow, and all error conditions are handled gracefully. The library is continuously fuzzed by OSS-Fuzz, and the code is also scanned with the Clang Static Analyzer, Coverity Scan and PVS-Studio, with badges in the README linking to the Coverity project and the OSS-Fuzz build logs. The test suite goes further than a smoke test. It consists of over 1000 test cases, and 175 test images from the PNG test suite are decoded with all possible output format and flag combinations and then compared against libpng for correctness. That last point is the one that matters most for an adopter, because differential testing against the reference implementation is what turns a claim of compatibility into a checked property. The example program referenced from the README lives at examples/example.c in the repository.

Known issues: gamma correction and grayscale formats

The Known Issues section is short and specific, which is preferable to a long list of vague caveats. Decoding to the SPNG_FMT_G8, SPNG_FMT_GA8 and SPNG_FMT_GA16 output formats is not supported for all PNG color type and bit depth combinations, and the README defers to the documentation for the details of which combinations work. Gamma correction is not implemented for the SPNG_FMT_PNG, SPNG_FMT_G8, SPNG_FMT_GA8 and SPNG_FMT_GA16 output formats, which is a sharper limitation than it first appears, since gamma correction is one of the features the feature table claims for the library. The practical implication is that a pipeline that must linearise light, or that decodes unusual grayscale and gray-plus-alpha sources into those specific formats, has to check the documentation before committing. The other limitation is the one already mentioned, animated PNG, which is marked as planned in the feature table rather than implemented.

Two build systems and an optional zlib

Getting the library is straightforward in two ways. The project offers the latest release for download, and the README says you can include spng.c and spng.h directly in your project, which is the single file drop-in model that appeals to people who do not want a package manager in their build. The other route is to build it properly, with either CMake or Meson, and the documentation in docs/build.md covers the details. The repository carries the corresponding build files at the top level, with CMakeLists.txt, a cmake/ directory, meson.build and meson_options.txt, plus a subprojects/ directory for the dependency handling, an examples/ directory with example.c and its own meson.build, and a tests/ directory. The zlib point is worth pulling out, because the feature table lists not requiring zlib as a difference from libpng, and the footnote says that building with miniz is supported. For a project that is already pulling in zlib for other reasons this matters little, but for a small embedded or static binary it can remove a dependency, and the documentation has a section dedicated to it.

Versioning guarantees, the 1.0.0 question and a quiet release history

The versioning section gives unusually precise promises. Releases follow the semantic versioning scheme with additional guarantees: releases from 0.4.0 to 0.8.x are stable, and if 1.0.0 introduces breaking changes then 0.8.x will be maintained as a separate stable branch. Currently, 1.0.0 is planned to be compatible, and the README links the tracking issue for that. So the answer to the question an adopter always asks, will upgrading the minor version break my build, is answered in writing for the current range. The licence is BSD 2-clause Simplified, with a caveat that the project contains optimizations and test images from libpng, which are licensed under the PNG Reference Library License version 2, so a redistribution needs to account for both terms. The release history is the soft spot. The tags are v0.7.2 on 2022-02-11, v0.7.3 on 2022-12-08 and v0.7.4 on 2023-05-08, while the last push to the repository was on 2026-08-31. The work continues, the published versions are sparse, and the 0.8.x line has not been cut, so a new adopter has to decide whether to track master or wait for a tag.

Editorial conclusion

libspng suits a new C project that needs PNG decoding or encoding with a small API surface, no zlib requirement, and a maintained security process behind it. It is a poor fit for an existing codebase built on libpng, because the README states plainly that the projects are separate and the APIs are not compatible, so a migration is a rewrite of the image handling layer rather than a swap. Verify first which PNG features you actually need, since animated PNG is marked as planned rather than supported, gamma correction is not implemented for several output formats, and the newest published release is v0.7.4 from 2023 even though the last push was on 2026-08-31, so decide whether that gap suits you before depending on the 0.8.x line.

Frequently asked questions

Is libspng a drop-in replacement for libpng?

No. The README states that libspng is an alternative to libpng, that the projects are separate and that the APIs are not compatible. Existing libpng code has to be rewritten against the spng context API.

How do I decode a PNG file with libspng?

Create a context with spng_ctx_new, set the input with spng_set_png_buffer, get the output size with spng_decoded_image_size for the format you want, and decode with spng_decode_image into your own buffer. Free the context with spng_ctx_free when you are done.

Does libspng require zlib?

No. The feature table lists not requiring zlib as a difference from libpng, and the documentation notes that building with miniz is supported if you want a smaller or dependency-free build.

Does libspng support animated PNG?

Not yet. The feature table marks animated PNG as planned for libspng, while libpng has it available with a third party patch.

How is libspng tested for correctness and security?

The library is continuously fuzzed by OSS-Fuzz and scanned with the Clang Static Analyzer, Coverity Scan and PVS-Studio. The test suite has over 1000 test cases, and 175 test images are decoded with all possible output format and flag combinations and compared against libpng.

Official sources

  1. License: BSD-2-Clause
  2. Project website
  3. randy408/libspng on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/randy408-libspng.svg)](https://hysenlabs.com/projects/randy408-libspng)

Was this useful?