All formats

libspng

LanguageC (usable from C++)
LicenseBSD 2-Clause
Repositorygithub.com/randy408/libspng
Documentationlibspng.org/docs
Depends onzlib or miniz
Read / writeyes / yes

libspng (simple PNG) is a modern PNG library with a smaller API than libpng: no setjmp, every function returns an error code. It decodes faster than libpng in most cases and is fuzzed continuously. It reads and writes all standard chunks. It doesn’t support APNG.

Installation#

Shell
# Debian / Ubuntu
sudo apt install libspng-dev
# macOS
brew install libspng
# Windows (vcpkg)
vcpkg install libspng

It builds with CMake or Meson. You can also add spng.c and spng.h to your project and link zlib (or define SPNG_USE_MINIZ to use miniz).

Basic usage: decode a PNG to RGBA#

C
#include <spng.h>
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    FILE *fp = fopen("in.png", "rb");
    if (!fp) return 1;

    spng_ctx *ctx = spng_ctx_new(0);
    spng_set_png_file(ctx, fp);

    struct spng_ihdr ihdr;
    int ret = spng_get_ihdr(ctx, &ihdr);
    if (ret) {
        printf("spng_get_ihdr: %s\n", spng_strerror(ret));
        goto done;
    }
    printf("%u x %u, bit depth %u, color type %u\n",
           ihdr.width, ihdr.height, ihdr.bit_depth, ihdr.color_type);

    size_t size;
    spng_decoded_image_size(ctx, SPNG_FMT_RGBA8, &size);
    unsigned char *image = malloc(size);
    ret = spng_decode_image(ctx, image, size, SPNG_FMT_RGBA8, 0);
    if (ret) printf("spng_decode_image: %s\n", spng_strerror(ret));
    // image: width*height*4 bytes
    free(image);
done:
    spng_ctx_free(ctx);
    fclose(fp);
    return ret ? 1 : 0;
}

How to encode a PNG#

This writes RGBA pixels into an in-memory PNG, then saves it:

C
#include <spng.h>
#include <stdio.h>
#include <stdlib.h>

int save_png(const char *path, unsigned char *pixels, uint32_t w, uint32_t h) {
    spng_ctx *ctx = spng_ctx_new(SPNG_CTX_ENCODER);
    spng_set_option(ctx, SPNG_ENCODE_TO_BUFFER, 1);

    struct spng_ihdr ihdr = {0};
    ihdr.width = w;
    ihdr.height = h;
    ihdr.color_type = SPNG_COLOR_TYPE_TRUECOLOR_ALPHA;
    ihdr.bit_depth = 8;
    spng_set_ihdr(ctx, &ihdr);

    int ret = spng_encode_image(ctx, pixels, (size_t)w * h * 4, SPNG_FMT_PNG, SPNG_ENCODE_FINALIZE);
    if (ret) {
        printf("spng_encode_image: %s\n", spng_strerror(ret));
        spng_ctx_free(ctx);
        return 1;
    }
    size_t png_size;
    int err;
    void *png = spng_get_png_buffer(ctx, &png_size, &err);  // caller frees
    FILE *fp = fopen(path, "wb");
    if (fp) {
        fwrite(png, 1, png_size, fp);
        fclose(fp);
    }
    free(png);
    spng_ctx_free(ctx);
    return 0;
}

To write straight to a file instead, call spng_set_png_file(ctx, fp) and skip SPNG_ENCODE_TO_BUFFER.

How to read text chunks#

C
uint32_t n = 0;
if (spng_get_text(ctx, NULL, &n) == 0 && n > 0) {  // first call gets the count
    struct spng_text *text = malloc(n * sizeof(struct spng_text));
    spng_get_text(ctx, text, &n);
    for (uint32_t i = 0; i < n; i++) printf("%s: %s\n", text[i].keyword, text[i].text);
    free(text);
}

Tips#