libspng

repository·master·Indexed 21 days ago

https://github.com/randy408/libspng

A fast, secure, and easy-to-use C library for reading and writing PNG files, designed as a modern alternative to libpng with a simplified API. It supports decoding and encoding images, managing PNG chunks (such as text, EXIF, and ICC profiles), and provides flexible build options via CMake, Meson, or direct source embedding. The library can optionally use miniz as a zlib replacement for easier integration.

Tokens
14.5K
Snippets
38
Records
70
Agent score
70%

What's inside libspng

  1. Understand chunk data semantics in libspng

    master

    Chunk data is stored within the spng_ctx. Understanding how data is retrieved and modified is critical for correct usage:

    Error Handling

    All spng_get_*() functions return 0 on success. If they return a non-zero error, specifically SPNG_ECHUNKAVAIL, it means the PNG does not contain that chunk or it was not previously set.

    Setting and Overwriting Data

    • Replacement: A successful spng_set_*() call replaces any previously set value or list. It does not combine data from the file with existing data or combine multiple spng_set_*() calls.
    • Persistence: Data set via spng_set_*() is never replaced by input file chunk data. If you manually set a value, it remains that way regardless of what is in the source file.

    Decoder Context Behavior

    • Chunk Reading: When calling spng_get_*() or spng_set_*(), the decoder reads and validates all chunks up to the first IDAT chunk (except spng_get_ihdr(), which only reads the header).
    • Post-Decode Reading: After the image has been decoded, calling spng_get_*() will read all chunks up to the IEND marker.
    • Recommendation: For certain chunks like text, time, unknown_chunks, and exif, it is recommended to call the getter functions after spng_decode_image() to ensure all chunks are retrieved.
  2. Understand libspng Contexts

    master

    In libspng, the spng_ctx handle is an opaque datatype that serves as the central container for all information. Unlike libpng, there is no separate info struct.

    • Creation: Use spng_ctx_new() or spng_ctx_new2() (for custom memory allocators) to create a new context.
    • Role: Contexts are decoders by default. To create an encoder, you must pass the SPNG_CTX_ENCODER flag during creation.
    • Cleanup: Use spng_ctx_free() to release all associated context data.
  3. Understand libspng error return values

    master

    In libspng, all functions follow a consistent error reporting pattern: they return 0 on success and a non-zero integer on error.

    Non-recoverable states: Certain errors—such as integer overflows, Out of Memory (OOM) conditions, or specific decoding errors—may put the library into a non-recoverable state. If this occurs, all subsequent function calls will return the error code SPNG_EBADSTATE.

  4. Retrieve image information and chunk data

    master

    Basic image properties (dimensions, bit depth, color type, etc.) are retrieved via spng_get_ihdr().

    Data Handling Nuances:

    • Copying: Most chunk data is copied by libspng.
    • Arbitrary Length Chunks: Data for chunks like eXIf, text, sPLT, and unknown chunks is not copied.
    • Chunk Lists: Lists are not copied; the reference must remain valid for the lifetime of the context.
    • Buffer Allocation: Unlike libpng, you cannot access internal list pointers for text, sPLT, and unknown chunks. You must first query the list size and then allocate your own buffers to retrieve the data.
  5. Handle decoding errors in libspng

    master

    Errors in libspng are categorized into two types:

    1. Critical Errors: These are non-recoverable. The decoder stops parsing, invalidates the context, and returns an error code. Any partial image output should be considered invalid. Subsequent calls to the context will return SPNG_EBADSTATE.
    2. Non-critical Errors: These are file corruption issues that can be handled deterministically (e.g., by ignoring checksums or discarding invalid chunks). The image is extracted consistently, but may suffer from lost color accuracy or transparency.

    Note on Truncation: Truncated PNGs or truncated image data are always treated as critical errors.

  6. Use miniz as a zlib replacement

    master
    By setting the SPNG_USE_MINIZ compiler option, libspng will use miniz instead of zlib. This allows you to embed libspng into a project using only four files: spng.c, miniz.c, and their respective headers. Performance is generally comparable to or slightly better than stock zlib.
  7. Understand image formats and endianness in libspng

    master

    libspng uses explicit, host-endian spng_format values (except for SPNG_FMT_PNG and SPNG_FMT_RAW).

    • Alpha Channel: When the destination format has an alpha channel but the source does not, alpha samples are implicitly set to fully opaque (maximum value). The library uses straight alpha; premultiplied alpha is not supported.
    • SPNG_FMT_PNG: Represents the PNG format specified in the IHDR chunk in host-endianness (e.g., little-endian on x86). When decoding, the output is always host-endian. When encoding, the source is assumed to be host-endian.
    • SPNG_FMT_RAW: Represents the PNG format in big-endian. This is equivalent to performing no transformations when decoding or encoding with libpng. When decoding 16-bit images, the output will always be big-endian.

    Note: Always check supported format and flag combinations for decoding and encoding, as some combinations are not supported.

  8. Handle errors in libspng

    master

    All libspng functions follow a consistent error pattern:

    • Success: Returns 0.
    • Error: Returns a non-zero error code.

    Critical Behavior: Decoding or encoding errors will invalidate the context. Once a context is invalidated, most subsequent function calls will return SPNG_EBADSTATE to signal that the context is no longer in a valid state for operations.

  9. Perform progressive image decoding

    master

    To decode images incrementally (useful for large files or streaming), initialize the decoder with the SPNG_DECODE_PROGRESSIVE flag in spng_decode_image().

    For both interlaced and non-interlaced images, the recommended approach is to use spng_decode_row() in a loop combined with spng_get_row_info() to handle the non-sequential access required by interlaced formats.

    Implementation Pattern:

    int error;
    struct spng_row_info row_info;
    
    do {
        error = spng_get_row_info(ctx, &row_info);
        if(error) break;
    
        void *row = image_buffer + (image_width * row_info.row_num);
        error = spng_decode_row(ctx, row, row_len);
    } while(error != SPNG_EOI);
    int error;
    struct spng_row_info row_info;
    
    do
    {
        error = spng_get_row_info(ctx, &row_info);
        if(error) break;
    
        void *row = image + image_width * row_info.row_num;
    
        error = spng_decode_row(ctx, row, len);
    }
    while(!error)
    
    if(error == SPNG_EOI) /* success */
  10. Apply Profile-guided optimization (PGO)

    master

    PGO can improve performance by up to 10%. To use it with Meson, follow these steps to generate the profile and then use it for the final build:

    1. Generate the profile:
      • Configure with -Db_pgo=generate.
      • Build and run the examples with benchmark images.
    2. Use the profile:
      • Configure with -Db_pgo=use.
      • Build and install.
    # Run in root directory
    git clone https://github.com/libspng/benchmark_images.git
    cd build
    meson configure -Dbuildtype=release --default-library both -Db_pgo=generate
    ninja
    ./example ../benchmark_images/medium_rgb8.png
    ./example ../benchmark_images/medium_rgba8.png
    ./example ../benchmark_images/large_palette.png
    meson configure -Db_pgo=use
    ninja
    ninja install