A pure Swift PNG library. Enjoy fast PNG encoding and decoding with strong data types, strict validation, and a safe, expressive, and Swifty API.
Decode a PNG file to a type of your choice in just one function call.
import PNG let (pixels, (x: width, y: height)) = try PNG.rgba(path: "example.png", of: UInt8.self) // pixels: [PNG.RGBA<UInt8>] // width: Int // height: Int
Use a component type of
UInt16 to capture the full color depth of a 16-bit PNG.
let (pixels, (x: width, y: height)) = try PNG.rgba(path: "example.png", of: UInt16.self) // pixels: [PNG.RGBA<UInt16>] // width: Int // height: Int
Return only the components you need with the grayscale and grayscale-alpha APIs.
let (pixels, (x: width, y: height)) = try PNG.va(path: "example.png", of: UInt8.self) // pixels: [PNG.VA<UInt8>] // width: Int // height: Int
let (pixels, (x: width, y: height)) = try PNG.v(path: "example.png", of: UInt8.self) // pixels: [UInt8] // width: Int // height: Int
- Supports all standard PNG formats, including indexed and interlaced formats
- Supports common graphics API interchange formats such as ARGB32
- Supports ancillary chunks, including private ancillary chunks
- Supports chroma key transparency
- Multi-level APIs, including raw chunk-level APIs
- Strong typing and expressive enumerations to catch invalid states at compile time
- Fixed-layout currency types for efficient C interop
- No Foundation imports and one system dependency, zlib
- Tested on MacOS and Linux
- Thorough API documentation
What’s the difference between bit depth and color type?
Color type refers to the channels present in a PNG. A grayscale PNG has only one color channel, while an RGB PNG has three (red, green, and blue). An RGBA PNG has four — three color channels, plus one alpha channel. Similarly, a grayscale–alpha PNG has two — one grayscale “color” channel and one alpha channel. An indexed-color PNG has one encoded channel in the image data, but the colors the indices represent are always RGBA quadruples. The vast majority of PNGs in the world are either of color type RGB or RGBA.
Bit depth goes one level lower; it represents the size of each channel. A PNG with a bit depth of
8 bits per channel. Hence, one pixel of an RGBA PNG is
4 * 8 = 32 bits long, or
What is interlacing?
Interlacing is a way of progressively ordering the image data in a PNG so it can be displayed at lower resolution even when partially downloaded. Interlacing is sometimes used in images on social media such as Instagram or Twitter, but rare elsewhere. Interlacing hurts compression, and so it usually significantly increases the size of a PNG file, sometimes as much as thirty percent.
Why does this package depend on
ZLib is a standard compression/decompression library that is installed by default on MacOS and most Linux systems. Although it is written in C, it is wrapped by almost every major programming language including Java and Python. The only other Swift PNG decoder library in existence at the time of writing, SwiftGL Image, actually implements its own, pure Swift,
INFLATE algorithm. (Note that it doesn’t compile on Swift ≥3.1.)
Does this package work on MacOS?
How do I access/encode custom PNG metadata chunks?
Use the ancillary chunk API on the
Data.Rectangular types, which expose ancillary chunk types and data through the
ancillaries instance property. See this tutorial for more details. Note that, except for
tRNS, PNG does not parse ancillary chunks, it only provides their data as a
[UInt8] buffer. Consult the PNG specification to interpret the ancillary chunks.
Does this package do gamma correction?
No. Gamma is meant to be applied at the image display stage. PNG only gives you the base pixel values in the image (with indexed pixel dereferencing and chroma key substitution). Gamma is also easy to apply to raw color data but computationally expensive to remove. Some PNGs include gamma data in a chunk called
gAMA, but most don’t, and viewers will just apply a
γ = 2.2 regardless.
Build PNG with the swift package manager,
swift build (
-c release). Make sure you have the
zlib headers on your computer (
sudo apt-get install libz-dev).
Help us keep the lights on
v3.0.0 - Jan 7, 2019
The library has been completely rewritten since version 2.0.1 and now features a much streamlined and improved API, as well as ancillary PNG chunk support, and a wider variety of color format inputs and outputs. Grayscale–alpha and indexed color now have first-class status in the 3.0 API, and are fully integrated with all PNG color backends in the file format’s specification. The typing system has also been greatly strengthened, resulting in an API which returns far fewer optionals, provides more expressive enumerations, and has a much greater chance of catching errors at compile time.
2.0.1 - May 21, 2017
This release adds a new overload to
png_encode(path:raw_data:properties:chunk_size:) that takes a Swift
UnsafeBufferPointer<UInt8> instead of an
Array, to avoid having to recopy a foreign array into Swift managed memory.
2.0.0 - May 19, 2017
In addition to being faster and more memory-efficient, MaxPNG 2 brings new features:
- Support for indexed-color and interlaced PNG files
- Passes all PNG test suite test cases
- Contiguous encoding and decoding functions, which are more efficient than the progressive variety
- Support for chroma keys, which are split between the
- RGBA normalization
- Ability to generate premultiplied alpha
- Ability to generate Cairo buffers from PNG files
- Ability to decompose interlaced PNGs into their constituent subimages
- Ability to encode indexed and interlaced PNG files
- Increased safety and validation
- Better-designed API and API naming
- Full API documentation