The AREATK library is used by including the apng.h
C header file in code which needs to use the library functionality. When this header file is included the png.h
header from libpng is also included. Consult the HOW TO section for more discussion of when to use apng.h
as opposed to png.h
.
AREATK core functions allow access to the APNG chunks using functions which follow the traditional libpng chunk API. APIs to read chunks from PNG files have the general name png_get_cHNk
where "cHNk" is the PNG chunk name. APIs to write chunks have the corresponding general name png_set_cHNk
.
Detailed documentation of the individual functions is in the function definitions section of this document.
The functionality provided for reading is:
The functionality provided for writing:
#include <apng.h> /* Do this **INSTEAD OF** #include <png.h> */
Do NOT #include
png.h
before apng.h
if you are building against the libapng library.
Building against the library will give you compatibility with all versions of libpng-1.6 including early versions which do not include APNG support themselves.
It is expected that this approach will remain compatible with later major versions of libpng.
#include <png.h> /* **DO NOT** include apng.h */
This only works if the version of libpng you are building against contains native APNG support. Once you have done this your application will only run against libpng DLLs which are at least the version you built against. Other, earlier, versions will typically cause your application to crash immediately it is executed.
Reading an APNG is possible with any of the libpng read APIs except the "Simplified API". The libpng Simplified API can and probably should be used to read the standard PNG image but this is a separate step and is only required if the APNG is to be displayed.
The following sequence uses the libpng sequential reader. Using the progressive reader allows incremental display of frames but requires a non-linear code flow; decisions about what to do next have to be based on a state machine.
-
png_create_read_struct();
Create a PNG read structure, then:
-
apng_read_enable(png_ptr);
This must be called to ensure that the chunk handling remains compatible with the APNG support. Without this application unknown handling may cause APNG chunks to be skipped.
-
Set application unknown chunk handling if required. This must be done before the next step because it will update the unknown handling.
-
png_read_info(png_ptr, pre_IDAT_info_ptr);
This will populate
pre_IDAT_info_ptr
with theacTL
chunk if present (if this is an APNG) and the fcTL chunk if one is present before the main image data (IDAT
) -
apng_get_acTL(png_ptr, pre_IDAT_info_ptr, &num_frames, &num_plays);
If this succeeds (returns true) decide whether to process the APNG based on the returned information. If you do decide to handle the APNG you must call this:
-
apng_get_fcTL(png_ptr, pre_IDAT_info_ptr, 0, {fcTL parameters});
Returns true if an
fcTL
with sequence number 0 is stored inpre_IDAT_info_ptr
and fills in thefcTL
parameters.Returns false if there is no
fcTL
before the firstIDAT
chunk; this means that the main PNG image is not part of the animation.Determines the next sequence number; if
png_get_fcTL
returnstrue
it is 1 elsefcTL[0]
will occur after the main image and the next sequence number is 0. -
Read the main image; any of the APIs may be used. It is also possible to set IDAT chunks to be handled as "unknown" to avoid decoding the main image at this point.
-
png_read_end(png_ptr, post_IDAT_info_ptr)
This should be called with a separate
png_info_struct
otherwise the results of subsequent calls may be unable to determine error conditions or just be plain misleading. -
Animation loop to find all the frames in the animation: {#animation-loop}
-
apng_get_fcTL(png_ptr, post_IDAT_info_ptr, next_sequence_number++, &<fctl parameters>)
Returns true if an
fcTL
withnext_sequence_number
is stored inpost_IDAT_info_ptr
and fills in thefcTL
parameters.Returns false at the end of the APNG frame list if the APNG is well formed. Exit the animation loop; At this point the total count of frames successful calls to
png_get_fcTL
) will be equal tonum_frames
frompng_get_acTL
in a well formed APNG. -
Frame loop to read all the
fdAT
chunks in the given frame: {#frame-loop}-
apng_get_fdAT(png_ptr, post_IDAT_info_ptr, next_sequence_number, &num_bytes, &frame_data_ptr)
Returns true if an
fdAT
withnext_sequence_number
is stored inpost_IDAT_info_ptr
and fills in num_bytes andframe_data_ptr
appropriately.frame_data_ptr
is set to point to a cache of the next block ofIDAT
data;png_const_byte frame_data[num_bytes]
.In this case increment
next_sequence_number
and continue the frame loop.Returns false if either
next_sequence_number
is thefcTL
of the next frame or the APNG chunk stream has ended or is malformed.In this case exit the frame loop and call
png_get_fcTL
with the same sequence number to get the nextfcTL
or determine that the APNG has ended.
-
Dropped chunks will cause the loops to fail early unless the error occurs with a dropped chunk after the initial
fdAT
chunks of the final frame. Truncation of the final frame cannot be determined without decompressing the sequence of chunks; this is a feature of the APNG design. -
apng_find_after(png_ptr, info_ptr, find_last, what)
is an optional assist function that may be called with either pre_IDAT_info_ptr
or post_IDAT_info_ptr
to determine whether the sequence_number
list is complete. It returns the next or last sequence numbers in the supplied info_struct
.