# Technical Documentation: ValveSoftware/source-sdk-2013

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/ValveSoftware/source-sdk-2013)

### Overview (README.md)

# Source SDK 2013

Source code for Source SDK 2013.

Contains the game code for Half-Life 2, HL2: DM and TF2.

**Now including Team Fortress 2! ✨**

## Build instructions

Clone the repository using the following command:

`git clone https://github.com/ValveSoftware/source-sdk-2013`

### Windows

Requirements:
 - Source SDK 2013 Multiplayer installed via Steam
 - Visual Studio 2022 with the following workload and components:
   - Desktop development with C++:
     - MSVC v143 - VS 2022 C++ x64/x86 build tools (Latest)
     - Windows 11 SDK (10.0.22621.0) or Windows 10 SDK (10.0.19041.1)
 - Python 3.13 or later

Inside the cloned directory, navigate to `src`, run:
```bat
createallprojects.bat
```
This will generate the Visual Studio project `everything.sln` which will be used to build your mod.

Then, on the menu bar, go to `Build > Build Solution`, and wait for everything to build.

You can then select the `Client (Mod Name)` project you wish to run, right click and select `Set as Startup Project` and hit the big green `> Local Windows Debugger` button on the tool bar in order to launch your mod.

The default launch options should be already filled in for the `Release` configuration.

### Linux

Requirements:
 - Source SDK 2013 Multiplayer installed via Steam
 - podman

Inside the cloned directory, navigate to `src`, run:
```bash
./buildallprojects
```

This will build all the projects related to the SDK and your mods automatically against the Steam Runtime.

You can then, in the root of the cloned directory, you can navigate to `game` and run your mod by launching the build launcher for your mod project, eg:
```bash
./mod_tf
```

*Mods that are distributed on Steam MUST be built against the Steam Runtime, which the above steps will automatically do for you.*

## Distributing your Mod

There is guidance on distributing your mod both on and off Steam available at the following link:

https://partner.steamgames.com/doc/sdk/uploading/distributing_source_engine

## Additional Resources

- [Valve Developer Wiki](https://developer.valvesoftware.com/wiki/Source_SDK_2013)

## License

The SDK is licensed to users on a non-commercial basis under the [SOURCE 1 SDK LICENSE](LICENSE), which is contained in the [LICENSE](LICENSE) file in the root of the repository.

For more information, see [Distributing your Mod](#markdown-header-distributing-your-mod).

---

### Src Thirdparty Libspng Docs Index (`src/thirdparty/libspng/docs/index.md`)

# libspng documentation

## Overview

libspng is a C library for reading and writing Portable Network Graphics (PNG)
format files with a focus on security and ease of use.

## Documentation

* [Build](build.md)
* [Usage](usage.md)
* [API documentation](api.md)
* [libpng migration guide](migrate-libpng.md)

## Download

libspng can be downloaded [here](https://libspng.org/download).

---

### Src Thirdparty Libspng Docs Api (`src/thirdparty/libspng/docs/api.md`)

# API Documentation

* [Error handling](errors.md)
* [Versioning](version.md)
* [Common](context.md)
* [Getting and setting chunk data](chunk.md)
* [Decoder API](decode.md)
* [Encoder API](encode.md)

---

### Src Thirdparty Libspng Docs Build (`src/thirdparty/libspng/docs/build.md`)

# Build

## Platform requirements

* Requires [zlib](http://zlib.net) or a zlib-compatible library
* Integers must be two's complement.
* Fixed width integer types up to `(u)int32_t`
* `CHAR_BIT` must equal 8.
* `size_t` must be unsigned.
* `size_t` and `int` must be at least 32-bit, 16-bit platforms are not
supported.
* Floating point support and math functions

## CMake

```bash
mkdir cbuild
cd cbuild
cmake .. # Don't forget to set optimization level!
make
make install
```

## Meson

```bash
meson build --buildtype=release # Default is debug
cd build
ninja
ninja install
```

## Embedding the source code

The source files `spng.c`/`spng.h` can be embedded in a project without
any configuration, SSE2 intrinsics are enabled by default on x86.

## Build options

| Meson       | CMake      | Compiler option             | Default | Description                                        |
|-------------|------------|-----------------------------|---------|----------------------------------------------------|
| (auto)      | (auto)     | `SPNG_STATIC`               |         | Controls symbol visibility on Windows              |
| enable_opt  | ENABLE_OPT | `SPNG_DISABLE_OPT`          | ON      | Compile with optimizations                         |
|             |            | `SPNG_SSE=<1-4>`            | 1       | SSE version target for x86 (ignored on non-x86)    |
|             |            | `SPNG_ARM`                  | (auto)  | Enable ARM NEON optimizations (ARM64 only)         |
| static_zlib |            |                             | OFF     | Link zlib statically                               |
| use_miniz   |            | `SPNG_USE_MINIZ`            | OFF     | Compile using miniz, disables some features        |
| (auto)      |            | `SPNG_ENABLE_TARGET_CLONES` |         | Use target_clones() to optimize (GCC + glibc only) |
| dev_build   |            |                             | OFF     | Enable the testsuite, requires libpng              |
| benchmarks  |            |                             | OFF     | Enable benchmarks, requires Git LFS                |
| oss_fuzz    |            |                             | OFF     | Enable regression tests with OSS-Fuzz corpora      |

Valid values for `SPNG_SSE`:

* 1 - SSE2
* 2 - same as above
* 3 - SSSE3
* 4 - SSE4.1

Currently only SSE2 optimizations are tested.

The source code alone can be built without any compiler flags,
compiler-specific macros are used to omit the need for options
such as `-msse2`, `-mssse3`.

## miniz

[miniz](https://github.com/richgel999/miniz) is a single source file replacement for zlib,
linking against miniz allows libspng to be embedded into a project with just
four files: `spng.c`, `miniz.c` and their headers.

For building with miniz add the `SPNG_USE_MINIZ` compiler option,
this handles some minor differences in the API.
Performance is mostly identical, slightly better in some cases
compared to stock zlib.

## Profile-guided optimization

[Profile-guided optimization (PGO)](https://clang.llvm.org/docs/UsersManual.html#profile-guided-optimization)
improves performance by up to 10%.

```bash
# 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
```

## Documentation

Documentation is built with [mkdocs](https://www.mkdocs.org/):

```bash
# Run in root directory
mkdocs build
```

---

### Src Thirdparty Libspng Docs Chunk (`src/thirdparty/libspng/docs/chunk.md`)

# Semantics

* Chunk data is stored in `spng_ctx`.

* All `spng_get_*()` functions return 0 on success and non-zero error,
  `SPNG_ECHUNKAVAIL` if the PNG does not contain that chunk or was not previously
  set.
* A successful `spng_set_*()` call will replace any previously set value or list,
  it does not combine chunk data from the file or multiple `spng_set_*()` calls.

The following apply to decoder contexts:

* When calling `spng_get_*()` or `spng_set_*()` functions all
  chunks up to the first IDAT are read, validated then stored
  with the exception of `spng_get_ihdr()`, which only reads the header.
* When calling `spng_get_*()` after the image has been decoded all
  chunks up to the IEND marker are read.
* `spng_set_*()` functions replace stored chunk data for that type.
* Chunk data stored with `spng_set_*()` functions are never replaced with
  input file chunk data i.e. if you set something it will stay that way.

# API

# spng_get_ihdr()
```c
int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr)
```

Get image header

# spng_get_plte()
```c
int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte)
```

Get image palette

# spng_get_trns()
```c
int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns)
```

Get image transparency

# spng_get_chrm()
```c
int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm)
```

Get primary chromacities and white point as floating point numbers

# spng_get_chrm_int()
```c
int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int)
```

Get primary chromacities and white point in PNG's internal representation

# spng_get_gama()
```c
int spng_get_gama(spng_ctx *ctx, double *gamma)
```

Get image gamma

# spng_get_gama_int()
```c
int spng_get_gama_int(spng_ctx *ctx, uint32_t *gamma)
```

Get image gamma in PNG's internal representation

# spng_get_iccp()
```c
int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp)
```

Get ICC profile

!!! note
    ICC profiles are not validated.

# spng_get_sbit()
```c
int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit)
```

Get significant bits

# spng_get_srgb()
```c
int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent)
```

Get rendering intent

# spng_get_text()
```c
int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text)
```

Copies text information to `text`.

`n_text` should be greater than or equal to the number of stored text chunks.

If `text` is NULL and `n_text` is non-NULL then `n_text` is set to the number
of stored text chunks.

Strings may be zero-length (single `'\0'` character) with the exception of `text.keyword`,
all strings are guaranteed to be non-NULL.

!!! note
    Due to the structure of PNG files it is recommended to call this function
    after `spng_decode_image()` to retrieve all text chunks.

!!! warning
    Text data is freed when calling `spng_ctx_free()`.

# spng_get_bkgd()
```c
int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd)
```

Get image background color

# spng_get_hist()
```c
int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist)
```

Get image histogram

# spng_get_phys()
```c
int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys)
```

Get phyiscal pixel dimensions

# spng_get_splt()
```c
int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt)
```

Copies suggested palettes to `splt`.

`n_splt` should be greater than or equal to the number of stored sPLT chunks.

If `splt` is NULL and `n_splt` is non-NULL then `n_splt` is set to the number
of stored sPLT chunks.

!!! warning
    Suggested palettes are freed when calling `spng_ctx_free()`.

# spng_get_time()
```c
int spng_get_time(spng_ctx *ctx, struct spng_time *time)
```

Get modification time

!!! note
    Due to the structure of PNG files it is recommended to call this function
    after `spng_decode_image()`.


# spng_get_unknown_chunks()
```c
int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks)
```

Copies unknown chunk information to `chunks`.

`n_chunks` should be greater than or equal to the number of stored unknown chunks.

If `chunks` is NULL and `n_chunks` is non-NULL then `n_chunks` is set to the number
of stored chunks.

!!! note
    To retrieve all unknown chunks call this functions after `spng_decode_image()`.

!!! warning
    Chunk data is freed when calling `spng_ctx_free()`.


# spng_get_offs()
```c
int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs)
```

Get image offset

# spng_get_exif()
```c
int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif)
```

Get EXIF data

!!! note
    Due to the structure of PNG files it is recommended to call this function
    after `spng_decode_image()`.

!!! warning
    `exif.data` is freed when calling `spng_ctx_free()`.



# spng_set_ihdr()
```c
int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr)
```

Set image header

# spng_set_plte()
```c
int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte)
```

Set image palette

# spng_set_trns()
```c
int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns)
```

Set transparency

# spng_set_chrm()
```c
int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm)
```

Set primary chromacities and white point as floating point numbers

# spng_set_chrm_int()
```c
int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int)
```

Set primary chromacities and white point in PNG's internal representation

# spng_set_gama()
```c
int spng_set_gama(spng_ctx *ctx, double gamma)
```

Set image gamma

# spng_set_gama_int()
```c
int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma)
```

Set image gamma in PNG's internal representation

# spng_set_iccp()
```c
int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp)
```

Set ICC profile

`spng_iccp.profile_name` must only contain printable Latin-1 characters and spaces.
Leading, trailing, and consecutive spaces are not permitted.

!!! note
    ICC profiles are not validated.


# spng_set_sbit()
```c
int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit)
```

Set significant bits

# spng_set_srgb()
```c
int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent)
```

Set rendering intent

# spng_set_text()
```c
int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text)
```

Set text data

`text` should point to an `spng_text` array of `n_text` elements.

`spng_text.text` must only contain Latin-1 characters.
Newlines must be a single linefeed character (decimal 10).

`spng_text.translated_keyword` must not contain linebreaks.

`spng_text.compression_method` must be zero.


# spng_set_bkgd()
```c
int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd)
```

Set image background color

# spng_set_hist()
```c
int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist)
```

Set image histogram

# spng_set_phys()
```c
int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys)
```

Set phyiscal pixel dimensions

# spng_set_splt()
```c
int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt)
```

Set suggested palette(s).

`splt` should point to an `spng_splt` array of `n_splt` elements.

!!! note
    `splt` should be a valid reference for the lifetime of the context.

# spng_set_time()
```c
int spng_set_time(spng_ctx *ctx, struct spng_time *time)
```

Set modification time

# spng_set_unknown_chunks()
```c
int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks)
```

Set unknown chunk data.

!!! note
    `chunks` should be a valid reference for the lifetime of the context.


# spng_set_offs()
```c
int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs)
```

Set image offset

# spng_set_exif()
```c
int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif)
```
Set EXIF data

---

### Src Thirdparty Libspng Docs Context (`src/thirdparty/libspng/docs/context.md`)

# Data types

# spng_ctx
```c
typedef struct spng_ctx spng_ctx;
```

   Context handle.

!!!note
    The context handle has no public members.


# spng_ctx_flags

```c
enum spng_ctx_flags
{
    SPNG_CTX_IGNORE_ADLER32 = 1, /* Ignore checksum in DEFLATE streams */
    SPNG_CTX_ENCODER = 2 /* Create an encoder context */
};
```

# spng_read_fn
```c
typedef int spng_read_fn(spng_ctx *ctx, void *user, void *dest, size_t length)
```

Type definition for callback passed to `spng_set_png_stream()` for decoders.

A read callback function should copy `length` bytes to `dest` and return 0 or
`SPNG_IO_EOF`/`SPNG_IO_ERROR` on error.


# spng_write_fn
```c
typedef int spng_write_fn(spng_ctx *ctx, void *user, void *src, size_t length)
```

Type definition for callback passed to `spng_set_png_stream()` for encoders.

The write callback should process `length` bytes and return 0 or `SPNG_IO_ERROR` on error.


# spng_format
```c
enum spng_format
{
    SPNG_FMT_RGBA8 = 1,
    SPNG_FMT_RGBA16 = 2,
    SPNG_FMT_RGB8 = 4,

    SPNG_FMT_GA8 = 16,
    SPNG_FMT_GA16 = 32,
    SPNG_FMT_G8 = 64,

    /* No conversion or scaling */
    SPNG_FMT_PNG = 256, /* host-endian */
    SPNG_FMT_RAW = 512  /* big-endian */
};
```
!!! note
    The channels are always in [byte-order](https://en.wikipedia.org/wiki/RGBA_color_model#RGBA8888) representation.

    The alpha channel is always [straight alpha](https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied),
    premultiplied alpha is not supported.

# spng_filter
```c
enum spng_filter
{
    SPNG_FILTER_NONE = 0,
    SPNG_FILTER_SUB = 1,
    SPNG_FILTER_UP = 2,
    SPNG_FILTER_AVERAGE = 3,
    SPNG_FILTER_PAETH = 4
};
```

# spng_row_info
```c
struct spng_row_info
{
    uint32_t scanline_idx;
    uint32_t row_num;
    int pass;
    uint8_t filter;
};
```

Contains row and scanline information, used for progressive decoding and encoding.

# spng_option
```c
enum spng_option
{
    SPNG_KEEP_UNKNOWN_CHUNKS = 1,

    SPNG_IMG_COMPRESSION_LEVEL,
    SPNG_IMG_WINDOW_BITS,
    SPNG_IMG_MEM_LEVEL,
    SPNG_IMG_COMPRESSION_STRATEGY,

    SPNG_TEXT_COMPRESSION_LEVEL,
    SPNG_TEXT_WINDOW_BITS,
    SPNG_TEXT_MEM_LEVEL,
    SPNG_TEXT_COMPRESSION_STRATEGY,

    SPNG_FILTER_CHOICE,
    SPNG_CHUNK_COUNT_LIMIT,
    SPNG_ENCODE_TO_BUFFER,
};
```

# spng_filter_choice
```c
enum spng_filter_choice
{
    SPNG_DISABLE_FILTERING = 0,
    SPNG_FILTER_CHOICE_NONE = 8,
    SPNG_FILTER_CHOICE_SUB = 16,
    SPNG_FILTER_CHOICE_UP = 32,
    SPNG_FILTER_CHOICE_AVG = 64,
    SPNG_FILTER_CHOICE_PAETH = 128,
    SPNG_FILTER_CHOICE_ALL = (8|16|32|64|128)
};
```

# API

# spng_ctx_new()
```c
spng_ctx *spng_ctx_new(int flags)
```

Creates a new context.

# spng_ctx_new2()
```c
spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags)
```

Creates a new context with a custom memory allocator, it is passed to zlib.

`alloc` and its members must be non-NULL.

# spng_ctx_free()
```c
void spng_ctx_free(spng_ctx *ctx)
```

Releases context resources.

# spng_set_png_stream()
```c
int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user)
```

Set input PNG stream or output PNG stream, depending on context type.

This can only be done once per context.

!!! info
    PNG's are read up to the file end marker, this is identical behavior to libpng.

# spng_set_png_file()
```c
int spng_set_png_file(spng_ctx *ctx, FILE *file)
```

Set input PNG file or output PNG file, depending on context type.

This can only be done once per context.

# spng_set_image_limits()
```c
int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height)
```

Set image width and height limits, these may not be larger than 2<sup>31</sup>-1.

# spng_get_image_limits()
```c
int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height)
```

Get image width and height limits.

`width` and `height` must be non-NULL.

# spng_set_chunk_limits()
```c
int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_limit)
```

Set chunk size and chunk cache limits, the default chunk size limit is 2<sup>31</sup>-1,
the default chunk cache limit is `SIZE_MAX`.

Reaching either limit while decoding is handled as an out-of-memory error.

!!!note
    This can only be used for limiting memory usage, most standard chunks
    do not require additional memory and are stored regardless of these limits.

# spng_get_chunk_limits()
```c
int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_limit)
```

Get chunk size and chunk cache limits.

# spng_get_row_info()
```c
int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info)
```

Copies the current, to-be-decoded (or to-be-encoded) row's information to `row_info`.

# spng_set_option()
```c
int spng_set_option(spng_ctx *ctx, enum spng_option option, int value)
```

Set `option` to the specified `value`.

For details see [Decode options](decode.md#decode-options) and [Encode options](encode.md#encode-options).

# spng_get_option()
```c
int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value)
```

Get the value for the specified `option`.

For details see [Decode options](decode.md#decode-options) and [Encode options](encode.md#encode-options).

---

### Src Thirdparty Libspng Docs Decode (`src/thirdparty/libspng/docs/decode.md`)

# Data types

## spng_crc_action
```c
enum spng_crc_action
{
    /* Default for critical chunks */
    SPNG_CRC_ERROR = 0,

    /* Discard chunk, invalid for critical chunks,
       since v0.6.2: default for ancillary chunks */
    SPNG_CRC_DISCARD = 1,

    /* Ignore and don't calculate checksum */
    SPNG_CRC_USE = 2
};
```

## spng_decode_flags
```c
enum spng_decode_flags
{
    SPNG_DECODE_USE_TRNS = 1, /* Deprecated */
    SPNG_DECODE_USE_GAMA = 2, /* Deprecated */

    SPNG_DECODE_TRNS = 1, /* Apply transparency */
    SPNG_DECODE_GAMMA = 2, /* Apply gamma correction */
    SPNG_DECODE_PROGRESSIVE = 256 /* Initialize for progressive reads */
};
```

# Error handling

Decoding errors are divided into critical and non-critical errors.

See also: [General error handling](errors.md)

Critical errors are not recoverable, it should be assumed that decoding has
failed completely and any partial image output is invalid, although corrupted
PNG's may appear to decode to the same partial image every time this cannot be guaranteed.

A critical error will stop any further parsing, invalidate the context and return the
relevant error code, most functions check for a valid context state and return
`SPNG_EBADSTATE` for subsequent calls to prevent undefined behavior.
It is strongly recommended to check all return values.

Non-critical errors in a decoding context refers to file corruption issues
that can be handled in a deterministic manner either by ignoring checksums
or discarding invalid chunks.
The image is extracted consistently but may have lost color accuracy,
transparency, etc.

The default behavior is meant to emulate libpng for compatibility reasons
with existing images in the wild, most non-critical errors are ignored.
Configuring decoder strictness is currently limited to checksums.

* Invalid palette indices are handled as black, opaque pixels
* `tEXt`, `zTXt` chunks with non-Latin characters are considered valid
* Non-critical chunks are discarded if the:
    * Chunk CRC is invalid (`SPNG_CRC_DISCARD` is the default for ancillary chunks)
    * Chunk has an invalid DEFLATE stream, by default this includes Adler-32 checksum errors
    * Chunk has errors specific to the chunk type: unexpected length, out-of-range values, etc
* Critical chunks with either chunk CRC or Adler-32 errors will stop parsing (unless configured otherwise)
* Extra trailing image data is silently discarded
* No parsing or validation is done past the `IEND` end-of-file marker

Truncated PNG's and truncated image data is always handled as a critical error,
getting a partial image is possible with progressive decoding but is not
guaranteed to work in all cases. The decoder issues read callbacks that
can span multiple rows or even the whole image, partial reads are not processed.

Some limitations apply, spng will stop decoding if:

* An image row is larger than 4 GB
* Something causes arithmetic overflow (limited to extreme cases on 32-bit)

## Checksums

There are two types of checksums used in PNG's: 32-bit CRC's for chunk data and Adler-32
in DEFLATE streams.

Creating a context with the `SPNG_CTX_IGNORE_ADLER32` flag will cause Adler-32
checksums to be ignored by zlib, both in compressed metadata and image data.
Note this is only supported with zlib >= 1.2.11 and is not available when compiled against miniz.

Chunk CRC handling is configured with `spng_set_crc_action()`,
when `SPNG_CRC_USE` is used for either chunk types the Adler-32 checksums in DEFLATE streams
will be also ignored.
When set for both chunk types it has the same effect as `SPNG_CTX_IGNORE_ADLER32`,
this does not apply vice-versa.

Currently there are no distinctions made between Adler-32 checksum- and other errors
in DEFLATE streams, they're all mapped to the `SPNG_EZLIB` error code.

The libpng equivalent of `spng_set_crc_action()` is `png_set_crc_action()`,
it implements a subset of its features:

| libpng                 | spng               | Notes                   |
|------------------------|--------------------|-------------------------|
| `PNG_CRC_ERROR_QUIT`   | `SPNG_CRC_ERROR`   | Will not abort on error |
| `PNG_CRC_WARN_DISCARD` | `SPNG_CRC_DISCARD` | No warning system       |
| `PNG_CRC_QUIET_USE`    | `SPNG_CRC_USE`     |                         |


The `SPNG_CTX_IGNORE_ADLER32` context flag has the same effect as `PNG_IGNORE_ADLER32`
used with `png_set_option()`.

## Memory usage

The library will always allocate a context buffer,
if the input PNG is a stream or file it will also create a read buffer.

Decoding an image requires at least 2 rows to be kept in memory,
3 if the image is interlaced.

Gamma correction requires an additional 128KB for a lookup table if
the output format has 16 bits per channel (e.g. `SPNG_FMT_RGBA16`).

To limit memory usage for image decoding use `spng_set_image_limits()`
to set an image width/height limit.
This is the equivalent of `png_set_user_limits()`.

Moreover the size calculated by `spng_decoded_image_size()` can be checked
against a hard limit before allocating memory for the output image.

Chunks of arbitrary length (e.g. text, color profiles) take up additional memory,
`spng_set_chunk_limits()` is used to set hard limits on chunk length- and cache limits,
note that reaching either limit is handled as a fatal error.

Since v0.7.0 the `SPNG_CHUNK_COUNT_LIMIT` option controls how many chunks can be stored,
the default is `1000` and is configurable through [`spng_set_option()`](context.md#spng_set_option),
this limit is independent of the chunk cache limit.

# API

See also: [spng_set_png_stream()](context.md#spng_set_png_stream), [spng_set_png_file()](context.md#spng_set_png_file).

# spng_set_png_buffer()
```c
int spng_set_png_buffer(spng_ctx *ctx, void *buf, size_t size)
```

Set input PNG buffer, this can only be done once per context.

# spng_set_crc_action()
```c
int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary)
```

Set how chunk CRC errors should be handled for critical and ancillary chunks.

# spng_decoded_image_size()
```c
int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *out)
```

Calculates decoded image buffer size for the given output format.

An input PNG must be set.

# spng_decode_chunks()
```c
int spng_decode_chunks(spng_ctx *ctx)
```

Decode all chunks before or after the image data (IDAT) stream,
depending on the state of the decoder.

If the image is decoded this function will read up to the end-of-file (IEND) marker.

Calling this function before `spng_decode_image()` is optional.

# spng_decode_image()
```c
int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags)
```

Decodes the PNG file and writes the image to `out`,
the image is converted from the PNG format to the destination format `fmt`.

Interlaced images are deinterlaced, 16-bit images are converted to host-endian.

`out` must point to a buffer of length `len`.

`len` must be equal to or greater than the number calculated with
`spng_decoded_image_size()` with the same output format.

If the `SPNG_DECODE_PROGRESSIVE` flag is set the decoder will be
initialized with `fmt` and `flags` for progressive decoding,
the values of `out`, `len` are ignored.

The `SPNG_DECODE_TNRS` flag is silently ignored if the PNG does not
contain a tRNS chunk or is not applicable for the color type.

This function can only be called once per context.

## Supported format, flag combinations

| PNG Format   | Output format     | Flags  | Notes                                         |
|--------------|-------------------|--------|-----------------------------------------------|
| Any format*  | `SPNG_FMT_RGBA8`  | All    | Convert from any PNG format and bit depth     |
| Any format   | `SPNG_FMT_RGBA16` | All    | Convert from any PNG format and bit depth     |
| Any format   | `SPNG_FMT_RGB8`   | All    | Convert from any PNG format and bit depth     |
| Gray <=8-bit | `SPNG_FMT_G8`     | None** | Only valid for 1, 2, 4, 8-bit grayscale PNG's |
| Gray 16-bit  | `SPNG_FMT_GA16`   | All**  | Only valid for 16-bit grayscale PNG's         |
| Gray <=8-bit | `SPNG_FMT_GA8`    | All**  | Only valid for 1, 2, 4, 8-bit grayscale PNG's |
| Any format   | `SPNG_FMT_PNG`    | None** | The PNG's format in host-endian               |
| Any format   | `SPNG_FMT_RAW`    | None   | The PNG's format in big-endian                |


\* Any combination of color type and bit depth defined in the [standard](https://www.w3.org/TR/2003/REC-PNG-20031110/#table111).

\*\* Gamma correction is not implemented

The `SPNG_DECODE_PROGRESSIVE` flag is supported in all cases.

The alpha channel is always [straight alpha](https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied),
premultiplied alpha is not supported.

## Progressive image decoding

If the `SPNG_DECODE_PROGRESSIVE` flag is set the decoder will be initialized
with `fmt` and `flags` for progressive decoding, the values of `img`, `len` are ignored.

Progressive decoding is straightforward when the image is not interlaced,
calling [spng_decode_row()](#spng_decode_row) for each row of the image will yield
the return value `SPNG_EOI` for the final row:

```c
int error;
size_t image_width = image_size / ihdr.height;

for(i = 0; i < ihdr.height; i++)
{
    void *row = image + image_width * i;

    error = spng_decode_row(ctx, row, image_width);

    if(error) break;
}

if(error == SPNG_EOI) /* success */
```

But for interlaced images rows are accessed multiple times and non-sequentially,
use [spng_get_row_info()](context.md#spng_get_row_info) to get the current row number:

```c
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 */
```

This is the recommended solution in all cases, for non-interlaced images `row_num` will increase
linearly.

# spng_decode_scanline()
```c
int spng_decode_scanline(spng_ctx *ctx, void *out, size_t len)
```

Decodes a scanline to `out`.

This function requires the decoder to be initialized by calling
`spng_decode_image()` with the `SPNG_DECODE_PROGRESSIVE` flag set.

The widest scanline is the decoded image size divided by `ihdr.height`.

For the last scanline and subsequent calls the return value is `SPNG_EOI`.

# spng_decode_row()
```c
int spng_decode_row(spng_ctx *ctx, void *out, size_t len)
```

Decodes and deinterlaces a scanline to `out`.

This function requires the decoder to be initialized by calling
`spng_decode_image()` with the `SPNG_DECODE_PROGRESSIVE` flag set.

The width of the row is the decoded image size divided by `ihdr.height`.

For interlaced images rows are accessed multiple times and non-sequentially,
use [spng_get_row_info()](context.md#spng_get_row_info) to get the current row number.

For the last row and subsequent calls the return value is `SPNG_EOI`.

If the image is not interlaced this function's behavior is identical to
`spng_decode_scanline()`.

# Decode options

| Option                       | Default value | Description                                              |
|------------------------------|---------------|----------------------------------------------------------|
| `SPNG_KEEP_UNKNOWN_CHUNKS`   | `0`           | Set to keep or discard unknown chunks                    |
| `SPNG_IMG_COMPRESSION_LEVEL` | `-1`          | May expose an estimate (0-9) after `spng_decode_image()` |
| `SPNG_IMG_WINDOW_BITS`       | `15`*         | Set zlib window bits used for image decompression        |
| `SPNG_CHUNK_COUNT_LIMIT`     | `1000`        | Limit shared by both known and unknown chunks            |

\* Option may be optimized if not set explicitly.

Options not listed here have no effect on decoders.

---

### Src Thirdparty Libspng Docs Encode (`src/thirdparty/libspng/docs/encode.md`)

# Usage

The context must be created with the `SPNG_CTX_ENCODER` flag set.

Before any (implicit) write operation an output must be set with
[spng_set_png_stream()](context.md#spng_set_png_stream) or [spng_set_png_file()](context.md#spng_set_png_file).

Alternatively the `SPNG_ENCODE_TO_BUFFER` option can be enabled with [spng_set_option()](context.md#spng_set_option),
in this case the encoder will create and manage an internal output buffer,
it is freed by `spng_ctx_free()` unless it's retrieved with [`spng_get_png_buffer()`](#spng_get_png_buffer).

In all cases the PNG must be explicitly finalized, this can be done with the `SPNG_ENCODE_FINALIZE` flag or with a call to
[`spng_encode_chunks()`](#spng_encode_chunks) after the image has been encoded.

# Memory usage

On top of the overhead of the the context buffer the internal write buffer
may grow to the length of entire chunks or more than the length of
the PNG file when encoding to the internal buffer.

Encoding an image requires at least 2 rows to be kept in memory,
this may increase to 3 rows for future versions.

# Data types

## spng_encode_flags

```c
enum spng_encode_flags
{
    SPNG_ENCODE_PROGRESSIVE = 1, /* Initialize for progressive writes */
    SPNG_ENCODE_FINALIZE = 2, /* Finalize PNG after encoding image */
};
```

# API

# spng_encode_chunks()
```c
int spng_encode_chunks(spng_ctx *ctx)
```

Encode all stored chunks before or after the image data (IDAT) stream,
depending on the state of the encoder.

If the image is encoded this function will also finalize the PNG with the end-of-file (IEND) marker.

Calling this function before `spng_encode_image()` is optional.

# spng_encode_image()
```c
int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags)
```

Encodes the image from `img` in the source format `fmt` to the specified PNG format set with [spng_set_ihdr()](chunk.md#spng_set_ihdr).

The width, height, color type, bit depth and interlace method must be set with [spng_set_ihdr()](chunk.md#spng_set_ihdr).

If the color type is set to `SPNG_COLOR_TYPE_INDEXED` a palette must be set with [spng_set_plte()](chunk.md#spng_set_plte).

`img` must point to a buffer of length `len`, `len` must be equal to the expected image
size for the given format `fmt`.

This function may call `spng_encode_chunks()`, writing any pending chunks before the image data.

If the `SPNG_ENCODE_FINALIZE` flag is set this function will call `spng_encode_chunks()` on the last
scanline/row, writing any pending chunks after the image data and finalize the PNG with the
end-of-file (IEND) marker before returning.
In most cases the only data after the image is the 12-byte IEND marker.

When the image is encoded to an internal buffer and the PNG is finalized
[spng_get_png_buffer()](#spng_get_png_buffer) will return the encoded buffer,
this must be freed by the user. If this function isn't called or an error is encountered
the internal buffer is freed by [spng_ctx_free()](context.md#spng_ctx_free).

## Supported format, flag combinations

| Input format   | PNG Format  | Flags | Notes                                  |
|----------------|-------------|-------|----------------------------------------|
| `SPNG_FMT_PNG` | Any format* | All   | Converted from host-endian if required |
| `SPNG_FMT_RAW` | Any format* | All   | No conversion (assumes big-endian)     |

\* Any combination of color type and bit depth defined in the [standard](https://www.w3.org/TR/2003/REC-PNG-20031110/#table111).

16-bit images are assumed to be host-endian except for `SPNG_FMT_RAW`.

The alpha channel is always [straight alpha](https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied),
premultiplied alpha is not supported.

Compression level and other options can be customized with [`spng_set_option()`](context.md#spng_set_option),
see [Encode options](encode.md#encode-options) for all options.
Note that encoder options are optimized based on PNG format and compression level,
overriding other options such as filtering may disable some of these optimizations.


## Progressive image encoding

If the `SPNG_ENCODE_PROGRESSIVE` flag is set the encoder will be initialized
with `fmt` and `flags` for progressive encoding, the values of `img`, `len` are ignored.

With the `SPNG_ENCODE_FINALIZE` flag set the PNG is finalized on the last scanline
or row.

Progressive encoding is straightforward when the image is not interlaced,
calling [spng_encode_row()](#spng_encode_row) for each row of the image will yield
the return value `SPNG_EOI` for the final row:

```c
int error;
size_t image_width = image_size / ihdr.height;

for(i = 0; i < ihdr.height; i++)
{
    void *row = image + image_width * i;

    error = spng_encode_row(ctx, row, image_width);

    if(error) break;
}

if(error == SPNG_EOI) /* success */
```

But for interlaced images (`spng_ihdr.interlaced_method` set to `1`)
rows are accessed multiple times and non-sequentially,
use [spng_get_row_info()](context.md#spng_get_row_info) to get the current row number:

```c
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_encode_row(ctx, row, len);
}
while(!error)

if(error == SPNG_EOI) /* success */
```

# spng_encode_scanline()
```c
int spng_encode_scanline(spng_ctx *ctx, const void *scanline, size_t len)
```

Encodes `scanline`, this function is meant to be used for interlaced PNG's
with image data that is already split into multiple passes.

This function requires the encoder to be initialized by calling
`spng_encode_image()` with the `SPNG_ENCODE_PROGRESSIVE` flag set.

For the last scanline and subsequent calls the return value is `SPNG_EOI`.

# spng_encode_row()
```c
int spng_encode_row(spng_ctx *ctx, const void *row, size_t len)
```

Encodes `row`, interlacing it if necessary.

This function requires the encoder to be initialized by calling
`spng_encode_image()` with the `SPNG_ENCODE_PROGRESSIVE` flag set.

See also: [Progressive-image-encoding](#Progressive-image-encoding)

For the last row and subsequent calls the return value is `SPNG_EOI`.

If the image is not interlaced this function's behavior is identical to
`spng_encode_scanline()`.


# spng_get_png_buffer()
```c
void *spng_get_png_buffer(spng_ctx *ctx, size_t *len, int *error)
```

If `SPNG_ENCODE_TO_BUFFER` is enabled via [spng_set_option()](context.md#spng_set_option) the encoded buffer is returned,
it must be called after [spng_encode_image()](encode.md#spng_encode_image) and the PNG must be finalized.

On success the buffer must be freed by the user.

# Encode options

| Option                           | Default value             | Description                       |
|----------------------------------|---------------------------|-----------------------------------|
| `SPNG_IMG_COMPRESSION_LEVEL`     | `Z_DEFAULT_COMPRESSION`   | Set image compression level (0-9) |
| `SPNG_IMG_WINDOW_BITS`           | `15`*                     | Set image zlib window bits (9-15) |
| `SPNG_IMG_MEM_LEVEL`             | `8`                       | Set zlib `memLevel` for images    |
| `SPNG_IMG_COMPRESSION_STRATEGY`  | `Z_FILTERED`*             | Set image compression strategy    |
| `SPNG_TEXT_COMPRESSION_LEVEL`    | `Z_DEFAULT_COMPRESSION`   | Set text compression level (0-9)  |
| `SPNG_TEXT_WINDOW_BITS`          | `15`                      | Set text zlib window bits (9-15)  |
| `SPNG_TEXT_MEM_LEVEL`            | `8`                       | Set zlib `memLevel` for text      |
| `SPNG_TEXT_COMPRESSION_STRATEGY` | `Z_DEFAULT_STRATEGY`      | Set text compression strategy     |
| `SPNG_FILTER_CHOICE`             | `SPNG_FILTER_CHOICE_ALL`* | Configure or disable filtering    |
| `SPNG_ENCODE_TO_BUFFER`          | `0`                       | Encode to internal buffer         |

\* Option may be optimized if not set explicitly.

Options not listed here have no effect on encoders.

---

### Src Thirdparty Libspng Docs Errors (`src/thirdparty/libspng/docs/errors.md`)

# Error handling

All functions return zero on success and non-zero on error.

Some errors such as integer overflow, OOM, decoding errors may lead to a
non-recoverable state, in this case all subsequent function calls will
return `SPNG_EBADSTATE`.

See also: [Decoder error handling](decode.md#error-handling)

# Functions

# spng_strerror()

```c
const char *spng_strerror(int err)
```

Return the error message for the given error code.

---

### Src Thirdparty Libspng Docs Migrate Libpng (`src/thirdparty/libspng/docs/migrate-libpng.md`)

# Contexts

The context handle `spng_ctx` is an opaque datatype that holds all information,
there is no separate info struct.

Create a new context with [`spng_ctx_new()`](context.md#spng_ctx_new) or [`spng_ctx_new2()`](context.md#spng_ctx_new2) to set a custom memory allocator.

Contexts are decoders by default, to create an encoder use `SPNG_CTX_ENCODER` as context flag.

`spng_ctx_free()` frees all context data.


# Error handling

All functions return zero on success and non-zero on error,
decoding or encoding errors will invalidate the context and most subequent function calls will return
`SPNG_EBADSTATE` to signal this.

See also: [Decoder error handling](decode.md#error-handling)

# Limits

!!! note
    `cache_max` refers to an overall memory usage limit in spng.

| libpng                       | spng                                                | Notes                    |
|------------------------------|-----------------------------------------------------|--------------------------|
| `png_set_user_limits()`      | [`spng_set_image_limits()`](#spng_set_image_limits) |                          |
| `png_get_user_width_max()`   | [`spng_get_image_limits()`](#spng_get_image_limits) |                          |
| `png_get_user_height_max()`  | [`spng_get_image_limits()`](#spng_get_image_limits) |                          |
| `png_set_chunk_malloc_max()` | [`spng_set_chunk_limits()`](#spng_set_chunk_limits) | `chunk_size` argument    |
| `png_get_chunk_malloc_max()` | [`spng_get_chunk_limits()`](#spng_get_chunk_limits) | `chunk_size` argument    |
| `png_set_chunk_cache_max()`  | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_CHUNK_COUNT_LIMIT` |

# Image information and chunk data

!!! info
    Image dimensions and other basic properties can be retrieved with [`spng_get_ihdr()`](chunk.md#spng_get_ihdr).

!!! note
    Most chunk data is copied except for arbitrary length chunks (eXIf, text, sPLT, unknown chunks).

    Chunk lists are not copied, the reference must stay valid for the lifetime of the context.

    To retrieve chunk lists for text, sPLT and unknown chunks the user must allocate buffers for them after querying the list size,
    unlike with libpng the internal list pointers are not accessible.

| libpng                       | spng                                                            | Notes                 |
|------------------------------|-----------------------------------------------------------------|-----------------------|
| `png_get_IHDR()`             | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     | Get image information |
| `png_get_PLTE()`             | [`spng_get_plte()`](chunk.md#spng_get_plte)                     |                       |
| `png_get_tRNS()`             | [`spng_get_trns()`](chunk.md#spng_get_trns)                     |                       |
| `png_get_cHRM()`             | [`spng_get_chrm()`](chunk.md#spng_get_chrm)                     |                       |
| `png_get_cHRM_fixed()`       | [`spng_get_chrm_int()`](chunk.md#spng_get_chrm_int)             |                       |
| `png_get_gAMA()`             | [`spng_get_gama()`](chunk.md#spng_get_gama)                     |                       |
| `png_get_gAMA_fixed()`       | [`spng_get_gama_int()`](chunk.md#spng_get_gama_int)             |                       |
| `png_get_iCCP()`             | [`spng_get_iccp()`](chunk.md#spng_get_iccp)                     |                       |
| `png_get_sBIT()`             | [`spng_get_sbit()`](chunk.md#spng_get_sbit)                     |                       |
| `png_get_sRGB()`             | [`spng_get_srgb()`](chunk.md#spng_get_srgb)                     |                       |
| `png_get_text()`             | [`spng_get_text()`](chunk.md#spng_get_text)                     |                       |
| `png_get_bKGD()`             | [`spng_get_bkgd()`](chunk.md#spng_get_bkgd)                     |                       |
| `png_get_hIST()`             | [`spng_get_hist()`](chunk.md#spng_get_hist)                     |                       |
| `png_get_pHYs()`             | [`spng_get_phys()`](chunk.md#spng_get_phys)                     |                       |
| `png_get_sPLT()`             | [`spng_get_splt()`](chunk.md#spng_get_splt)                     |                       |
| `png_get_tIME()`             | [`spng_get_time()`](chunk.md#spng_get_time)                     |                       |
| `png_get_oFFs()`             | [`spng_get_offs()`](chunk.md#spng_get_offs)                     |                       |
| `png_get_eXIf_1()`           | [`spng_get_exif()`](chunk.md#spng_get_exif)                     |                       |
| `png_get_sCAL())`            | N/A                                                             | Not supported         |
| `png_set_IHDR()`             | [`spng_set_ihdr()`](chunk.md#spng_set_ihdr)                     |                       |
| `png_set_PLTE()`             | [`spng_set_plte()`](chunk.md#spng_set_plte)                     |                       |
| `png_set_tRNS()`             | [`spng_set_trns()`](chunk.md#spng_set_trns)                     |                       |
| `png_set_cHRM()`             | [`spng_set_chrm()`](chunk.md#spng_set_chrm)                     |                       |
| `png_set_cHRM_fixed()`       | [`spng_set_chrm_int()`](chunk.md#spng_set_chrm_int)             |                       |
| `png_set_gAMA()`             | [`spng_set_gama()`](chunk.md#spng_set_gama)                     |                       |
| `png_set_gAMA_fixed()`       | [`spng_set_gama_int()`](chunk.md#spng_set_gama_int)             |                       |
| `png_set_iCCP()`             | [`spng_set_iccp()`](chunk.md#spng_set_iccp)                     |                       |
| `png_set_sBIT()`             | [`spng_set_sbit()`](chunk.md#spng_set_sbit)                     |                       |
| `png_set_sRGB()`             | [`spng_set_srgb()`](chunk.md#spng_set_srgb)                     |                       |
| `png_set_text()`             | [`spng_set_text()`](chunk.md#spng_set_text)                     |                       |
| `png_set_bKGD()`             | [`spng_set_bkgd()`](chunk.md#spng_set_bkgd)                     |                       |
| `png_set_hIST()`             | [`spng_set_hist()`](chunk.md#spng_set_hist)                     |                       |
| `png_set_pHYs()`             | [`spng_set_phys()`](chunk.md#spng_set_phys)                     |                       |
| `png_set_sPLT()`             | [`spng_set_splt()`](chunk.md#spng_set_splt)                     |                       |
| `png_set_tIME()`             | [`spng_set_time()`](chunk.md#spng_set_time)                     |                       |
| `png_set_oFFs()`             | [`spng_set_offs()`](chunk.md#spng_set_offs)                     |                       |
| `png_set_eXIf_1()`           | [`spng_set_exif()`](chunk.md#spng_set_exif)                     |                       |
| `png_set_sCAL())`            | N/A                                                             | Not supported         |
| `png_get_unknown_chunks()`   | [`spng_get_unknown_chunks()`](chunk.md#spng_get_unknown_chunks) |                       |
| `png_set_unknown_chunks()`   | [`spng_set_unknown_chunks()`](chunk.md#spng_set_unknown_chunks) |                       |
| `png_get_image_width()`      | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_image_height()`     | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_bit_depth()`        | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_color_type()`       | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_filter_type()`      | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_interlace_type()`   | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |
| `png_get_compression_type()` | [`spng_get_ihdr()`](chunk.md#spng_get_ihdr)                     |                       |

# Decode

## Set source PNG

!!! note
    Push-style decoding is not supported in this release.

| libpng              | spng                                                      | Notes                   |
|---------------------|-----------------------------------------------------------|-------------------------|
| `png_set_read_fn()` | [`spng_set_png_stream()`](context.md#spng_set_png_stream) | Set PNG stream callback |
| `png_init_io()`     | [`spng_set_png_file()`](context.md#spng_set_png_file)     | Set PNG file (`FILE*`)  |
| N/A                 | [`spng_set_png_buffer()`](context.md#spng_set_png_buffer) | Set PNG buffer          |


## Decoder configuration

| libpng                         | spng                                                     | Notes                                                                   |
|--------------------------------|----------------------------------------------------------|-------------------------------------------------------------------------|
| `png_set_crc_action()`         | [`spng_set_crc_action()`](decode.md#spng_set_crc_action) | See [CRC actions](#crc-action-constants)                                |
| `png_set_interlace_handling()` | N/A                                                      | See [Progressive image decoding](decode.md#progressive-image-decoding). |
| `png_create_read_struct()`     | N/A                                                      | See [Contexts](#contexts)                                               |
| `png_destroy_read_struct()`    | N/A                                                      | See [Contexts](#contexts)                                               |

### CRC action constants

!!! note
    Errors are only signalled through return values, spng never calls `abort()`.

| libpng                 | spng               | Action - critical   | Action - ancillary  |
|------------------------|--------------------|---------------------|---------------------|
| `PNG_CRC_DEFAULT`      | N/A                | `SPNG_CRC_ERROR`    | `SPNG_CRC_USE`      |
| `PNG_CRC_ERROR_QUIT`   | `SPNG_CRC_ERROR`   | error               | error               |
| `PNG_CRC_WARN_DISCARD` | `SPNG_CRC_DISCARD` | (invalid)           | discard data        |
| `PNG_CRC_WARN_USE`     | N/A                | (no warning system) | (no warning system) |
| `PNG_CRC_QUIET_USE`    | `SPNG_CRC_USE`     | use data            | use data            |
| `PNG_CRC_NO_CHANGE`    | N/A                |                     |                     |


## Image formats and transforms

Currently the library only works with source and destination formats,
there are no transforms which change the output format based on the
source PNG's format or other metadata like the tRNS chunk.

Migrating from the traditional libpng API is straightforward if the desired output
format is clearly defined, nonetheless some transforms (such as [Adding transparency](#adding-transparency))
can be implemented on top of the existing API.

All [`spng_format`](context.md#spng_format)'s are explicit and host-endian (except for `SPNG_FMT_PNG` and `SPNG_FMT_RAW`),
PNG formats are converted to the destination `spng_format` when decoding or
converted from the `spng_format` to the destination PNG format when encoding.
When the destination format has an alpha channel and the source doesn't the alpha samples
are implicitly set to the fully opaque, maximum value.
The alpha channel is always [straight alpha](https://en.wikipedia.org/wiki/Alpha_compositing#Straight_versus_premultiplied),
premultiplied alpha is not supported.

!!! note
    Some source/destination combinations are not supported, check supported format, flags combinations for [decoding](decode.md#supported-format-flag-combinations) and [encoding](encode.md#supported-format-flag-combinations).

`SPNG_FMT_PNG` represents the PNG's format specified in the header (IHDR chunk) in host-endian (ie. little-endian on x86),
it is the equivalent of only calling `png_set_swap()` on little-endian when decoding or encoding.
When decoding the output will always be host-endian, when encoding it is assumed
the source image is host-endian.

`SPNG_FMT_RAW` is the same as `SPNG_FMT_PNG` but in big-endian,
it is the same as not doing any transformations when decoding or encoding with libpng.
The PNG standard only supports encoding of 16-bit images in big-endian, when used as the source
format the library will assume the source image is big-endian.
When decoding 16-bit images the output will always be big-endian.

Some decode flags may affect the final image but never the size or the layout of the samples within the pixels.

## Adding transparency

This can be achieved by specifiying an output format with an alpha channel such as `SPNG_FMT_RGBA8` and the `SPNG_DECODE_TRNS` decode flag.

```c
ret = spng_decode_image(ctx, out, len, SPNG_FMT_RGBA8, SPNG_DECODE_TRNS);
```

Note that using `SPNG_DECODE_TRNS` does not result in an error if the image does not have a tRNS chunk or
is not applicable for the PNG format/output format combination, in those cases the flag is ignored.

The `png_set_tRNS_to_alpha()` function applies a tranforms which
adds an alpha channel of the same bit depth if a tRNS chunk is present.
It also implicitly converts indexed color images to 8-bit RGB,
1/2/4-bit grayscale images to 8-bit grayscale and also adds an alpha channel
if there is a tRNS chunk.

This transform can be implemented by choosing the equivalent output format and using `SPNG_DECODE_TRNS` to apply transparency:

```c
int fmt = SPNG_FMT_PNG;
int decode_flags = SPNG_DECODE_TRNS;

if(ihdr.color_type == SPNG_COLOR_TYPE_INDEXED) fmt = SPNG_FMT_RGB8;
else if(ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr.bit_depth < 8) fmt = SPNG_FMT_G8;

struct spng_trns trns = {0};
int have_trns = !spng_get_trns(ctx, &trns);

if(have_trns)
{
    if(ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR)
    {
        if(ihdr.bit_depth == 16) fmt = SPNG_FMT_RGBA16;
        else fmt = SPNG_FMT_RGBA8;
    }
    else if(ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE)
    {
        if(ihdr.bit_depth == 16) fmt = SPNG_FMT_GA16;
        else fmt = SPNG_FMT_GA8;
    }
    else if(ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
    {
        fmt = SPNG_FMT_RGBA8;
    }
}
```

| libpng                             | spng               | Notes                                                     |
|------------------------------------|--------------------|-----------------------------------------------------------|
| `png_set_swap()`                   | N/A                | Byteswapping is done based on source / destination format |
| `png_set_expand_gray_1_2_4_to_8()` | N/A                | Use `SPNG_FMT_G8` when required                           |
| `png_set_tRNS_to_alpha()`          | N/A                | See [Adding transparency](#Adding-transparency)           |
| `png_set_palette_to_rgb()`         | N/A                | Use `SPNG_FMT_RGB8` when required                         |
| `png_set_gamma()`                  | `SPNG_DECODE_GAMA` | Screen gamma of 2.2 is assumed                            |
| `png_read_update_info()`           | N/A                | Not required                                              |
| `png_set_expand_16()`              | N/A                | Not supported                                             |
| `png_set_bgr()`                    | N/A                | Not supported                                             |
| `png_set_gray_to_rgb()`            | N/A                | Use `SPNG_FMT_RGB8` when required                         |
| `png_set_rgb_to_gray()`            | N/A                | Not supported                                             |
| `png_set_rgb_to_gray_fixed()`      | N/A                | Not supported                                             |
| `png_build_grayscale_palette()`    | N/A                | Not supported                                             |
| `png_set_alpha_mode()`             | N/A                | Not supported                                             |
| `png_set_alpha_mode_fixed()`       | N/A                | Not supported                                             |
| `png_set_strip_alpha()`            | N/A                | Not supported                                             |
| `png_set_swap_alpha()`             | N/A                | Not supported                                             |
| `png_set_invert_alpha()`           | N/A                | Not supported                                             |
| `png_set_filler()`                 | N/A                | Not supported                                             |
| `png_set_add_alpha()`              | N/A                | Not supported                                             |
| `png_set_swap_alpha()`             | N/A                | Not supported                                             |
| `png_set_packing()`                | N/A                | Not supported                                             |
| `png_set_packswap()`               | N/A                | Not supported                                             |
| `png_set_shift()`                  | N/A                | Not supported                                             |
| `png_set_invert_mono()`            | N/A                | Not supported                                             |
| `png_set_background()`             | N/A                | Not supported                                             |
| `png_set_background_fixed()`       | N/A                | Not supported                                             |
| `png_set_scale_16()`               | N/A                | Not supported                                             |
| `png_set_strip_16()`               | N/A                | Not supported                                             |

# Decoding images

See also: [Progressive image decoding](decode.md#progressive-image-decoding)

!!! note
    Row pointers (array of pointers) are not used.

| libpng              | spng                                                   | Notes                               |
|---------------------|--------------------------------------------------------|-------------------------------------|
| `png_read_row()`    | [`spng_decode_row()`](encode.md#spng_decode_row)       |                                     |
| `png_write_image()` | [`spng_encode_image()`](encode.md#spng_decode_image)   |                                     |
| `png_read_info()`   | [`spng_decode_chunks()`](decode.md#spng_decode_chunks) | Optional, chunks are read on-demand |
| `png_read_end()`    | [`spng_decode_chunks()`](decode.md#spng_decode_chunks) | Optional, chunks are read on-demand |


# Encode

## Set destination PNG

| libpng               | spng                                                                        | Notes                     |
|----------------------|-----------------------------------------------------------------------------|---------------------------|
| `png_set_write_fn()` | [`spng_set_png_stream()`](context.md#spng_set_png_stream)                   | Set PNG stream callback   |
| `png_init_io()`      | [`spng_set_png_file()`](decode.md#spng_set_png_file)                        | Set PNG file (`FILE*`)    |
| N/A                  | [`spng_set_option(ctx, SPNG_ENCODE_TO_BUFFER)`](context.md#spng_set_option) | Encode to internal buffer |


## Encoder configuration

| libpng                                   | spng                                                | Notes                                                        |
|------------------------------------------|-----------------------------------------------------|--------------------------------------------------------------|
| `png_create_write_struct()`              | N/A                                                 | See [Contexts](#contexts)                                    |
| `png_destroy_write_struct()`             | N/A                                                 | See [Contexts](#contexts)                                    |
| `png_set_keep_unknown_chunks()`          | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_KEEP_UNKNOWN_CHUNKS`                                   |
| `png_handle_as_unknown()`                | N/A                                                 | Not supported                                                |
| `png_set_unknown_chunk_location()`       | N/A                                                 | Not supported, set `location` field ahead of time            |
| `png_set_compression_level()`            | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_IMG_COMPRESSION_LEVEL`                                 |
| `png_set_compression_mem_level()`        | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_IMG_MEM_LEVEL`                                         |
| `png_set_compression_strategy()`         | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_IMG_COMPRESSION_STRATEGY`                              |
| `png_set_compression_window_bits()`      | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_IMG_WINDOW_BITS`                                       |
| `png_set_compression_method()`           | N/A                                                 | Not supported                                                |
| `png_set_text_compression_level()`       | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_TEXT_COMPRESSION_LEVEL`                                |
| `png_set_text_compression_mem_level()`   | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_TEXT_MEM_LEVEL`                                        |
| `png_set_text_compression_strategy()`    | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_TEXT_COMPRESSION_STRATEGY`                             |
| `png_set_text_compression_window_bits()` | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_TEXT_WINDOW_BITS`                                      |
| `png_set_text_compression_method()`      | N/A                                                 | Not supported                                                |
| `png_set_filter()`                       | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_FILTER_CHOICE` (see [Filter choices](#filter-choices)) |
| `png_set_chunk_cache_max()`              | [`spng_set_option()`](context.md#spng_set_option)   | `SPNG_CHUNK_COUNT_LIMIT`                                     |
| `png_set_chunk_malloc_max()`             | [`spng_set_chunk_limits()`](#spng_set_chunk_limits) | `chunk_size` argument                                        |
| `png_get_chunk_malloc_max()`             | [`spng_get_chunk_limits()`](#spng_get_chunk_limits) | `chunk_size` argument                                        |
| `png_set_quantize()`                     | N/A                                                 | Not supported                                                |


## Encoding images

See also: [Progressive image encoding](encode.md#progressive-image-encoding)

!!! note
    Row pointers (array of pointers) are not used.

| libpng                         | spng                                                   | Notes                                       |
|--------------------------------|--------------------------------------------------------|---------------------------------------------|
| `png_write_row()`              | [`spng_encode_row()`](encode.md#spng_encode_row)       |                                             |
| `png_write_image()`            | [`spng_encode_image()`](encode.md#spng_encode_image)   |                                             |
| `png_write_info_before_PLTE()` | N/A                                                    | Not supported                               |
| `png_write_info()`             | [`spng_encode_chunks()`](encode.md#spng_encode_chunks) | Optional, chunks are written on-demand      |
| `png_write_end()`              | [`spng_encode_chunks()`](encode.md#spng_encode_chunks) | Can be replaced with `SPNG_ENCODE_FINALIZE` |

# Common

## Chunk location constants

| libpng           | spng              |
|------------------|-------------------|
| `PNG_HAVE_IHDR`  | `SPNG_AFTER_IHDR` |
| `PNG_HAVE_PLTE`  | `SPNG_AFTER_PLTE` |
| `PNG_AFTER_IDAT` | `SPNG_AFTER_IDAT` |

## Color type constants

| libpng                      | spng                              |
|-----------------------------|-----------------------------------|
| `PNG_COLOR_TYPE_GRAY`       | `SPNG_COLOR_TYPE_GRAYSCALE`       |
| `PNG_COLOR_TYPE_PALETTE`    | `SPNG_COLOR_TYPE_INDEXED`         |
| `PNG_COLOR_TYPE_RGB`        | `SPNG_COLOR_TYPE_TRUECOLOR`       |
| `PNG_COLOR_TYPE_RGB_ALPHA`  | `SPNG_COLOR_TYPE_TRUECOLOR_ALPHA` |
| `PNG_COLOR_TYPE_GRAY_ALPHA` | `SPNG_COLOR_TYPE_GRAYSCALE_ALPHA` |
| `PNG_COLOR_TYPE_RGBA`       | `SPNG_COLOR_TYPE_TRUECOLOR_ALPHA` |
| `PNG_COLOR_TYPE_GA`         | `SPNG_COLOR_TYPE_GRAYSCALE_ALPHA` |


## Filter constants

### Filter values

Filter values defined by the standard.

| libpng                   | spng                  |
|--------------------------|-----------------------|
| `PNG_FILTER_VALUE_NONE`  | `SPNG_FILTER_NONE`    |
| `PNG_FILTER_VALUE_SUB `  | `SPNG_FILTER_SUB`     |
| `PNG_FILTER_VALUE_UP`    | `SPNG_FILTER_UP`      |
| `PNG_FILTER_VALUE_AVG`   | `SPNG_FILTER_AVERAGE` |
| `PNG_FILTER_VALUE_PAETH` | `SPNG_FILTER_PAETH`   |

### Filter choices

Filter choice flags for [`spng_set_option()`](context.md#spng_set_option) when used with `SPNG_FILTER_CHOICE`.

| libpng             | spng                       |
|--------------------|----------------------------|
| `PNG_NO_FILTERS`   | `SPNG_DISABLE_FILTERING`   |
| `PNG_FILTER_NONE`  | `SPNG_FILTER_CHOICE_NONE`  |
| `PNG_FILTER_SUB`   | `SPNG_FILTER_CHOICE_SUB`   |
| `PNG_FILTER_UP`    | `SPNG_FILTER_CHOICE_UP`    |
| `PNG_FILTER_AVG`   | `SPNG_FILTER_CHOICE_AVG`   |
| `PNG_FILTER_PAETH` | `SPNG_FILTER_CHOICE_PAETH` |
| `PNG_ALL_FILTERS`  | `SPNG_FILTER_CHOICE_ALL`   |


## Miscellaneous functions

| libpng                              | spng                                        | Notes                                             |
|-------------------------------------|---------------------------------------------|---------------------------------------------------|
| `png_create_info_struct()`          | N/A                                         | See [Contexts](#contexts)                         |
| `png_set_mem_fn()`                  | N/A                                         | Use [`spng_ctx_new2()`](context.md#spng_ctx_new2) |
| `png_get_mem_ptr()`                 | N/A                                         | Not supported                                     |
| `png_get_current_row_number()`      | [`spng_get_row_info()`](#spng_get_row_info) | `spng_row_info.row_num`                           |
| `png_get_current_pass_number()`     | [`spng_get_row_info()`](#spng_get_row_info) | `spng_row_info.pass`                              |
| `png_get_io_state()`                | N/A                                         | Not supported                                     |
| `png_set_option()`                  | `spng_set_option()`                         |                                                   |
| `png_set_invalid()`                 | N/A                                         | Not supported                                     |
| `png_set_sig_bytes()`               | N/A                                         | Not supported                                     |
| `png_sig_cmp()`                     | N/A                                         | Not supported                                     |
| `png_check_sig()`                   | N/A                                         | Not supported                                     |
| `png_get_compression_buffer_size()` | N/A                                         | Not supported                                     |
| `png_set_compression_buffer_size()` | N/A                                         | Not supported                                     |
| `png_jmpbuf()`                      | N/A                                         | Not supported                                     |
| `png_reset_zstream()`               | N/A                                         | Not supported                                     |
| `png_write_sig()`                   | N/A                                         | Not supported                                     |
| `png_write_chunk()`                 | N/A                                         | Not supported                                     |
| `png_write_chunk_start()`           | N/A                                         | Not supported                                     |
| `png_write_chunk_data()`            | N/A                                         | Not supported                                     |
| `png_write_chunk_end()`             | N/A                                         | Not supported                                     |

---

### Src Thirdparty Libspng Docs Usage (`src/thirdparty/libspng/docs/usage.md`)

# Basic usage

libspng can decode images to an explicit output format (e.g. 8/16-bit RGBA)
from any PNG format. With `SPNG_FMT_PNG` the pixel format will identical
to the PNG's format in host-endian, or big-endian with `SPNG_FMT_RAW`,
the latter does not support any transforms e.g. gamma correction.


```c
#include <spng.h>

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

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

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

/* Get an 8-bit RGBA image regardless of PNG format */
spng_decode_image(ctx, SPNG_FMT_RGBA8, out, out_size, 0);

/* Free context memory */
spng_ctx_free(ctx);

```

For a complete example see [example.c](https://github.com/randy408/libspng/blob/v0.7.2/examples/example.c).


## Decoding untrusted files

To decode untrusted files safely it is required to at least:

* Set an upper image width and height limit with `spng_set_image_limits()`.

* Use `spng_decoded_image_size()` to calculate the output image size
 and check it against a constant limit.

* Set a chunk size and chunk cache limit with `spng_set_chunks_limits()`
  to avoid running out of memory. Note that exceeding either limit is
  handled as an out-of-memory error since v0.6.0.

---

### Src Thirdparty Libspng Docs Version (`src/thirdparty/libspng/docs/version.md`)

# Versioning

Releases follow the [semantic versioning](https://semver.org/) scheme with additional guarantees:

* Releases from 0.4.0 to 0.8.x are stable
* If 1.0.0 will introduce breaking changes then 0.8.x will be maintained as a separate stable branch

Currently 1.0.0 is planned to be [compatible](https://github.com/randy408/libspng/issues/3).

# Macros

`SPNG_VERSION_MAJOR`

libspng version's major number

`SPNG_VERSION_MINOR`

libspng version's minor number

`SPNG_VERSION_PATCH`

libspng version's patch number


# Functions

# spng_version_string()

```c
const char *spng_version_string(void)
```

Returns the library version as a string.

---

--- METRICS ---
- Files Extracted: 12
- Estimated Token Budget: ~18061 tokens
- Canonical Reference: https://codewiki.google/github.com/ValveSoftware/source-sdk-2013
