A PNG (Portable Network Graphics) image format decoder.
pngload can be used to load images in the PNG image format, both from files on disk, or streams in memory. This library was written out of frustration with png-read, which was the only native Common Lisp code that supports PNG.
What makes pngload different than png-read?
pngload is optimized for speed and portability across many different Common Lisp implementation and architecture combinations. On 64-bit SBCL it is more than 3x faster than the png-read library when decoding a particular large 4096x4096 RGBA image. Rough benchmarking in our particular environment at the time of writing shows:
- pngload: 0.901s
- png-read: 3.058s
To overcome some performance bottlenecks, we wrote our own decompressor, as the alternatives were too slow and not easily optimizable.
Also, we use the mmap library on operating systems that support it, with a fallback path when not supported.
pngload should be a lot more hackable, and have more of an educational value than png-read, even after adding lots of type declarations and restructuring the code away from its original cleanliness in favor of performance.
The entire concrete syntax tree is parsed, and is visible as a slot in the returned PNG
object
when decoding an image. png-read does not support some of these. Additionally, human-readable
formats are stored outside of the parse tree in the top-level object. For instance, if a chunk
specifying gamma correction is parsed, this will be stored as a floating-point value, rather than
multiplied by 100,000 and stored as an integer. Again, the raw data is stored in the PARSE-TREE
slot of the returned object, should you ever need more.
pngload is able to load all images in PNGSuite correctly. png-read claims that it can load them all, but they were not checked for validity.
Stores data in a format that is expected by opticl
opticl has supported pngload since its first release, which gives you faster PNG loading automatically if you were already using opticl.
pngload supports additional extension chunk types, such as EXIF information.
pngload can optionally parse only the metadata, skipping decoding completely, in order to quickly retrieve information about an image.
Instead of decoding to a format which is compatible with opticl, pngload can now decode to a flat 1-D array. This is useful for OpenGL texture uploading and some other applications.
pngload can optionally flip the Y axis when decoding, for when the origin is expected to be at the bottom left instead of the top left, as with OpenGL texture rendering.
pngload can optionally write to foreign memory using static-vectors. This is useful when needing to efficiently pass a pointer to the image data with a foreign library, such as with OpenGL.
(ql:quickload :pngload)
Usage is quite simple:
(pngload:load-file #p"/path/to/file.png")
This will return an object which includes everything you would need to render the image data, or query it for other useful data.
Additionally, you may load a PNG datastream from a Common Lisp stream with:
(pngload:load-stream stream)
Both LOAD-FILE
and LOAD-STREAM
accept an optional keyword argument, which can be used to disable
the slow process of decoding the image data. This can be used to very quickly get information about
the file, including but not limited to, the dimensions, last modification date, or palette
information. Image data will be unavailable with this option, obviously. To use this fast reading
method:
(pngload:load-file #p"/path/to/file.png" :decode nil)
or:
(pngload:load-stream stream :decode nil)
Additionally, both LOAD-FILE
and LOAD-STREAM
may take the following keyword arguments:
FLATTEN
when non-NIL, will decode the image data to a 1-dimensional array, rather than the default
method which is to be compatible with opticl.
FLIP-Y
when non-NIL, will flip the pixels on the Y axis, for when the origin is expected to be at
the bottom/left instead of the top/left.
STATIC-VECTOR
when non-NIL, will decode to foreign memory. It is up to the user to free memory
when they are finished with it. Alternatively, you can use WITH-PNG-IN-STATIC-VECTOR
which will
automatically free the memory for you.
pngload has a unified API for querying different metadata that may be stored in a PNG datastream.
The get-metadata
method can be used to query any metadata available. It accepts a PNG object,
which is returned by load-file
or load-stream
as per the above, as well as a key identifying the
type of metadata you want to query. If a PNG datastream does not have the metadata requested, NIL
will be returned. The following keys are recognized:
The image width in pixels. This is the same as (width png)
and is only for convenience.
The image height in pixels. This is the same as (height png)
and is only for convenience.
The number of bits per sample. This is the same as (bit-depth png)
and is only for convenience.
The color type of the image. This is the same as (color-type png)
and is only for convenience. One
of the following is returned:
:indexed-colour
: each pixel consists of an index into a palette.:greyscale
: each pixel consists of a single sample: grey.:greyscale-alpha
: each pixel consists of two samples: grey and alpha.:truecolour
: each pixel consists of three samples: red, green, and blue.:truecolour-alpha
: each pixel consists of four samples: red, green, blue, and alpha.
The method used to compress image data chunks. For standard PNG, this can only be :zlib
. This will
return :unknown
if any other compression scheme was used.
The interlacing method. For standard PNG, this can be either :null
or :adam7
. This will return
:unknown
if any other interlacing method was used.
The filtering method used to decode the image. For standard PNG, this can only be :standard
. This
will return :unknown
if any other filter method was used.
The palette of an :indexed-colour
image. This will return a 2-dimensional array of (color-count 3)
representing the red, green, and blue values of each indexed color in the palette.
The CIE 1931 reference white point. Returns two floating point values for the X and Y values.
The CIE 1931 primary red chromaticity. Returns two floating point values for the X and Y values.
The CIE 1931 primary green chromaticity. Returns two floating point values for the X and Y values.
The CIE 1931 primary blue chromaticity. Returns two floating point values for the X and Y values.
The gamma adjustment for the desired display output intensity. Returns a floating point value.
The ICC color profile of the image. Returns a octet vector to be decoded by any application wishing to make use of this.
The original number of sample significant bits. Returns multiple values; one for each color channel.
Specifies how the samples should be displayed in the sRGB color space. This can be one of the following:
:perceptual
: for images preferring good adaptation to the output device gamut at the expense of colorimetric accuracy, such as photographs.:relative-colorimetric
: for images requiring colour appearance matching (relative to the output device white point), such as logos.:saturation
: for images preferring preservation of saturation at the expense of hue and lightness, such as charts and graphs.:absolute-colorimetric
: for images requiring preservation of absolute colorimetry, such as previews of images destined for a different output device (proofs).
The default background colour to present the image against. Returns 3 values; the red, green, and blue values.
The approximate usage frequency of each colour in the palette. Returns an association list mapping each palette color as a vector of 3 components to their frequencies.
The transparency color of the image. For :indexed-colour
images, this returns an association list
mapping each palette color as a vector of 3 components their transparency value. For :truecolour
images, this returns 3 values; the red, green, and blue sample value of the transparency color. For
:greyscale
images, this returns a single value for the transparency.
Specifies the aspect ratio and physical size of image pixels. Returns a property list specifying the
X and Y dimensions of each pixel, as well as a unit. :unit
can be one of :meter
or :unknown
.
If :unit
is :unknown
, physical size of the pixels is not stored, and only the aspect ratio is
present.
Some PNG images store a "suggested palette" chunk, which stores multiple palettes, histograms, and transparency information together. This returns an association list mapping a palette name to a property list of suggested palette information.
The timestamp the image was last modified. Returns an integer in the universal time format.
Arbitrary textual metadata stored in the PNG datastream. Returns a list of property lists.
Copyright © 2017-2021 Michael Fiano mail@mfiano.net, Bart Botta 00003b@gmail.com.
Licensed under the MIT License.