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 is the only native Common Lisp code that supports PNG. Now,
there shall be a choice.
What makes pngload
different than png-read
?
png-read
is very slow. For a simple test on modern hardware, it takes
png-read
0.95 [1] seconds to load an image that takes cl-png
(A CFFI wrapper
for libpng) 0.028s. pngload
takes 0.145s.
[1] Note that I recently applied some SBCL-specific compiler optimizations to
png-read
, so this figure will be lower on SBCL once it is pushed in the next
Quicklisp dist release. Still though, pngload
is approximately 2.5-5x faster,
depending on the image type.
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
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.
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
Makes transitioning to pngload
easier and faster in the future. Its author has
expressed interest in replacing or at least adding pngload
as an optional
backend.
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
.
Can optionally flip the Y axis, for when the origin is expected to be at the bottom left instead of the top left, as with OpenGL texture rendering.
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 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 you are done. Alternatively, you can use
WITH-PNG-IN-STATIC-VECTOR
which will automatically free the memory for you.
Copyright © 2017 Michael Fiano [email protected].
Licensed under the MIT License.
A copy of the license is available here.