An efficient, powerful, safe, and free PNG library, written in pure Swift. MaxPNG is
MaxPNG is written in pure Swift, and it has a dependency on just a single C library — zlib. MaxPNG makes no reference to slow, legacy Objective C frameworks, in fact, it doesn’t even import Foundation. You get the benefit of a comfortable Swift API, without the overhead of aging Apple frameworks. MaxPNG is actively maintained, and the latest release snapshot builds on Swift 3.1.1. (Current master
branch is written in Swift 4.)
Decode or encode a PNG file in just one function call.
import MaxPNG
let (png_raw_data, png_properties):([UInt8], PNGProperties) = try png_decode(path: "my_png_file.png")
let my_png_settings = PNGProperties(width: 3, height: 3, bit_depth: 8, color: .rgb, interlaced: false)
let my_png_data:[UInt8] = [0 ,0 ,0 , 255,255,255, 255,0 ,255,
255,255,255, 0 ,0 ,0 , 0 ,255,0 ,
120,120,255, 150,120,255, 180,120,255]
try png_encode(path: "my_output_png.png", raw_data: my_png_data, properties: my_png_settings)
MaxPNG’s entire public API is documented.
MaxPNG is batteries-included, providing several utility functions that will deinterlace and normalize image data, turning any PNG file into an array of RGBA samples. In most cases, MaxPNG’s default output can be sent directly to a graphics API such as OpenGL. MaxPNG even includes functions to premultiply image alpha, and format data buffers that can be sent to the Cairo graphics library.
MaxPNG includes a progressive API that reads and writes PNGs scanline by scanline, allowing you to process enormous PNG files. The progressive decoder and encoder objects also clean up after themselves, so you never have to worry about closing file streams or managing zlib internal state.
let png = try PNGDecoder(path: "my_png_file.png")
let out = try PNGEncoder(path: "my_resaved_png.png", properties: png.properties)
while let scanline = try png.next_scanline()
{
try out.add_scanline(scanline)
}
try out.finish()
MaxPNG is written in pure Swift, and so it should behave like a Swift library. Its decoder is fully standards-compliant, passing all 161 official PNG unit tests, among others. It supports interlacing, indexed color, and even chroma key transparency. MaxPNG also throws errors like a Swift library should, minimizing the chance that you’ll end up with a corrupt PNG.
MaxPNG was built on Linux, and developed on github from the start. It has nothing to do with Apple, or any Apple framework, even Foundation. I created it because there was no existing, maintained open source Swift PNG library.
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 (unsupported) has one encoded channel in the image data, but the colors the indices represent are always RGB triples. 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
has 8
bits per channel. Hence, one pixel of an RGBA PNG is 4 * 8 = 32
bits long, or 4
bytes.
What does interlacing mean?
Interlacing is a way of progressivly ordering the image data in a PNG so it can be displayed at lower resolution even when partially downloaded. Interlacing is common in images downloaded from 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.
MaxPNG will read interlaced images as a series of subimage scanlines. To recover a rectangular pixel array, you should pass the interlaced scanlines into the provided PNGProperties
member function .deinterlace(raw_data:)
function.
How do I deinterlace an interlaced PNG?
Use PNGProperties
’s member function .deinterlace(raw_data:)
.
PNGProperties › func deinterlace(raw_data:[UInt8]) -> [UInt8]?
The scanlines passed in the scanline array must be in ADAM7 order, and their sizes must agree with the bit depth and color format parameters passed through the PNGProperties
struct.
Why not use a C PNG decoder like
libpng
?
Cause it either a) doesn’t work in Swift, or b) it actually does work but the API is so bad that I don’t know how to get it to work, which, if you think about it, is just as bad. Either way, libpng
is written in C. MaxPNG is written in Swift. Yay!
Why does it depend on
zlib
then?
ZLib is a standard compression/decompression library that is installed by default on most Linux systems. Although it is written in C library, 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. (Be warned though, it doesn’t compile on Swift ≥3.1.)
Does MaxPNG work on Mac OSX?
MaxPNG works great on macOS with the preinstalled zlib.
What is the progressive API good for?
Some PNGs are so large that loading them into your RAM will make you very sad. These PNGs are not meant to be viewed, rather processed as data for other purposes. (Think satellite scan data.) Reading them line by line avoids this problem by letting you stream the picture in and out of your program while you do your thing (such as downsampling them to something small enough that you can view on your screen).
Why did it “skip”
nUGZ
??? That’s my favorite chunk!!!
Right now, MaxPNG only recognizes the chunks IHDR
, IDAT
, IEND
, PLTE
, and .tRNS
. The other ancillary chunks are currently unrecognized, but still validated for chunk ordering.
Wait, MaxPNG lets you skip
IDAT
??? Why would you ever want to do that?
By default, MaxPNG will decode the image pixel data, but if you pass PNGDecoder.init(path:recognizing:)
an empty array in its recognizing:[PNGChunkType]
field, it will ignore the pixel data chunks. Sometimes you want to do this if, for example, you just want to get the dimensions of the PNG file. Decoding the pixel data we don’t care about would just be a waste of time.
Does MaxPNG do gamma correction?
No. Gamma is meant to be applied at the image display stage. MaxPNG only gives you the raw, integer color data in the file. 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. MaxPNG doesn’t read gAMA
right now.
Can I add extra chunks to my PNG output?
At the moment, no. MaxPNG currently only writes the basic IHDR
, IDAT
, IEND
chunks, and the PLTE
and tRNS
chunks if applicable.
I hate maxpng isnt there any other png encoder/decoder out there i stg
It’s okay, I only wrote MaxPNG because I couldn’t find any good existing free Swift PNG library. Here’s a rundown of some of the alternatives I stumbled across from a simple search of 'swift png'
in the magical github search bar:
Not a library, just a wrapper around the Cocoa framework.
Not a library, just a wrapper around libpng
. Also has no support for decoding PNG files.
This repository was empty. I did however enjoy the github youtube channel
Actually one of the most complete Swift PNG libraries I’ve seen. Has no support for encoding PNG files though, and I don’t believe it lets you read by scanline. Also depends on Apple Foundation.
I have no idea what this repository does.
Build MaxPNG with the swift package manager, swift build
. Make sure you have the zlib
headers on your computer (sudo apt-get install libz-dev
).