libspng
| Language | C (usable from C++) |
|---|---|
| License | BSD 2-Clause |
| Repository | github.com/randy408/libspng |
| Documentation | libspng.org/docs |
| Depends on | zlib or miniz |
| Read / write | yes / 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#
- Limit memory use on untrusted files with
spng_set_image_limits(ctx, max_w, max_h)andspng_set_chunk_limits. SPNG_DECODE_TRNSin the flags ofspng_decode_imageappliestRNStransparency when decoding to RGBA8.