Alien-FreeImage
view release on metacpan or search on metacpan
src/Source/LibPNG/libpng-manual.txt view on Meta::CPAN
or png_calloc() and passed in via a png_set_*() function, with
png_data_freer(png_ptr, info_ptr, freer, mask)
freer - one of
PNG_DESTROY_WILL_FREE_DATA
PNG_SET_WILL_FREE_DATA
PNG_USER_WILL_FREE_DATA
mask - which data elements are affected
same choices as in png_free_data()
This function only affects data that has already been allocated.
You can call this function after reading the PNG data but before calling
any png_set_*() functions, to control whether the user or the png_set_*()
function is responsible for freeing any existing data that might be present,
and again after the png_set_*() functions to control whether the user
or png_destroy_*() is supposed to free the data. When the user assumes
responsibility for libpng-allocated data, the application must use
png_free() to free it, and when the user transfers responsibility to libpng
for data that the user has allocated, the user must have used png_malloc()
or png_calloc() to allocate it.
If you allocated your row_pointers in a single block, as suggested above in
the description of the high level read interface, you must not transfer
responsibility for freeing it to the png_set_rows or png_read_destroy function,
because they would also try to free the individual row_pointers[i].
If you allocated text_ptr.text, text_ptr.lang, and text_ptr.translated_keyword
separately, do not transfer responsibility for freeing text_ptr to libpng,
because when libpng fills a png_text structure it combines these members with
the key member, and png_free_data() will free only text_ptr.key. Similarly,
if you transfer responsibility for free'ing text_ptr from libpng to your
application, your application must not separately free those members.
The png_free_data() function will turn off the "valid" flag for anything
it frees. If you need to turn the flag off for a chunk that was freed by
your application instead of by libpng, you can use
png_set_invalid(png_ptr, info_ptr, mask);
mask - identifies the chunks to be made invalid,
containing the bitwise OR of one or
more of
PNG_INFO_gAMA, PNG_INFO_sBIT,
PNG_INFO_cHRM, PNG_INFO_PLTE,
PNG_INFO_tRNS, PNG_INFO_bKGD,
PNG_INFO_hIST, PNG_INFO_pHYs,
PNG_INFO_oFFs, PNG_INFO_tIME,
PNG_INFO_pCAL, PNG_INFO_sRGB,
PNG_INFO_iCCP, PNG_INFO_sPLT,
PNG_INFO_sCAL, PNG_INFO_IDAT
For a more compact example of reading a PNG image, see the file example.c.
Reading PNG files progressively
The progressive reader is slightly different from the non-progressive
reader. Instead of calling png_read_info(), png_read_rows(), and
png_read_end(), you make one call to png_process_data(), which calls
callbacks when it has the info, a row, or the end of the image. You
set up these callbacks with png_set_progressive_read_fn(). You don't
have to worry about the input/output functions of libpng, as you are
giving the library the data directly in png_process_data(). I will
assume that you have read the section on reading PNG files above,
so I will only highlight the differences (although I will show
all of the code).
png_structp png_ptr;
png_infop info_ptr;
/* An example code fragment of how you would
initialize the progressive reader in your
application. */
int
initialize_png_reader()
{
png_ptr = png_create_read_struct
(PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
user_error_fn, user_warning_fn);
if (!png_ptr)
return (ERROR);
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
{
png_destroy_read_struct(&png_ptr,
(png_infopp)NULL, (png_infopp)NULL);
return (ERROR);
}
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr,
(png_infopp)NULL);
return (ERROR);
}
/* This one's new. You can provide functions
to be called when the header info is valid,
when each row is completed, and when the image
is finished. If you aren't using all functions,
you can specify NULL parameters. Even when all
three functions are NULL, you need to call
png_set_progressive_read_fn(). You can use
any struct as the user_ptr (cast to a void pointer
for the function call), and retrieve the pointer
from inside the callbacks using the function
png_get_progressive_ptr(png_ptr);
which will return a void pointer, which you have
to cast appropriately.
*/
png_set_progressive_read_fn(png_ptr, (void *)user_ptr,
info_callback, row_callback, end_callback);
return 0;
}
/* A code fragment that you call as you receive blocks
of data */
int
process_data(png_bytep buffer, png_uint_32 length)
{
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_read_struct(&png_ptr, &info_ptr,
(png_infopp)NULL);
return (ERROR);
}
/* This one's new also. Simply give it a chunk
of data from the file stream (in order, of
course). On machines with segmented memory
models machines, don't give it any more than
64K. The library seems to run fine with sizes
of 4K. Although you can give it much less if
necessary (I assume you can give it chunks of
1 byte, I haven't tried less then 256 bytes
yet). When this function returns, you may
want to display any rows that were generated
in the row callback if you don't already do
so there.
*/
png_process_data(png_ptr, info_ptr, buffer, length);
/* At this point you can call png_process_data_skip if
you want to handle data the library will skip yourself;
it simply returns the number of bytes to skip (and stops
libpng skipping that number of bytes on the next
png_process_data call).
return 0;
}
/* This function is called (as set by
png_set_progressive_read_fn() above) when enough data
has been supplied so all of the header has been
read.
*/
void
info_callback(png_structp png_ptr, png_infop info)
{
/* Do any setup here, including setting any of
the transformations mentioned in the Reading
PNG files section. For now, you _must_ call
either png_start_read_image() or
png_read_update_info() after all the
src/Source/LibPNG/libpng-manual.txt view on Meta::CPAN
After you have these structures, you will need to set up the
error handling. When libpng encounters an error, it expects to
longjmp() back to your routine. Therefore, you will need to call
setjmp() and pass the png_jmpbuf(png_ptr). If you
write the file from different routines, you will need to update
the png_jmpbuf(png_ptr) every time you enter a new routine that will
call a png_*() function. See your documentation of setjmp/longjmp
for your compiler for more information on setjmp/longjmp. See
the discussion on libpng error handling in the Customizing Libpng
section below for more information on the libpng error handling.
if (setjmp(png_jmpbuf(png_ptr)))
{
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return (ERROR);
}
...
return;
If you would rather avoid the complexity of setjmp/longjmp issues,
you can compile libpng with PNG_NO_SETJMP, in which case
errors will result in a call to PNG_ABORT() which defaults to abort().
You can #define PNG_ABORT() to a function that does something
more useful than abort(), as long as your function does not
return.
Checking for invalid palette index on write was added at libpng
1.5.10. If a pixel contains an invalid (out-of-range) index libpng issues
a benign error. This is enabled by default because this condition is an
error according to the PNG specification, Clause 11.3.2, but the error can
be ignored in each png_ptr with
png_set_check_for_invalid_index(png_ptr, 0);
If the error is ignored, or if png_benign_error() treats it as a warning,
any invalid pixels are written as-is by the encoder, resulting in an
invalid PNG datastream as output. In this case the application is
responsible for ensuring that the pixel indexes are in range when it writes
a PLTE chunk with fewer entries than the bit depth would allow.
Now you need to set up the output code. The default for libpng is to
use the C function fwrite(). If you use this, you will need to pass a
valid FILE * in the function png_init_io(). Be sure that the file is
opened in binary mode. Again, if you wish to handle writing data in
another way, see the discussion on libpng I/O handling in the Customizing
Libpng section below.
png_init_io(png_ptr, fp);
If you are embedding your PNG into a datastream such as MNG, and don't
want libpng to write the 8-byte signature, or if you have already
written the signature in your application, use
png_set_sig_bytes(png_ptr, 8);
to inform libpng that it should not write a signature.
Write callbacks
At this point, you can set up a callback function that will be
called after each row has been written, which you can use to control
a progress meter or the like. It's demonstrated in pngtest.c.
You must supply a function
void write_row_callback(png_structp png_ptr, png_uint_32 row,
int pass);
{
/* put your code here */
}
(You can give it another name that you like instead of "write_row_callback")
To inform libpng about your function, use
png_set_write_status_fn(png_ptr, write_row_callback);
When this function is called the row has already been completely processed and
it has also been written out. The 'row' and 'pass' refer to the next row to be
handled. For the
non-interlaced case the row that was just handled is simply one less than the
passed in row number, and pass will always be 0. For the interlaced case the
same applies unless the row value is 0, in which case the row just handled was
the last one from one of the preceding passes. Because interlacing may skip a
pass you cannot be sure that the preceding pass is just 'pass-1', if you really
need to know what the last pass is record (row,pass) from the callback and use
the last recorded value each time.
As with the user transform you can find the output row using the
PNG_ROW_FROM_PASS_ROW macro.
You now have the option of modifying how the compression library will
run. The following functions are mainly for testing, but may be useful
in some cases, like if you need to write PNG files extremely fast and
are willing to give up some compression, or if you want to get the
maximum possible compression at the expense of slower writing. If you
have no special needs in this area, let the library do what it wants by
not calling this function at all, as it has been tuned to deliver a good
speed/compression ratio. The second parameter to png_set_filter() is
the filter method, for which the only valid values are 0 (as of the
July 1999 PNG specification, version 1.2) or 64 (if you are writing
a PNG datastream that is to be embedded in a MNG datastream). The third
parameter is a flag that indicates which filter type(s) are to be tested
for each scanline. See the PNG specification for details on the specific
filter types.
/* turn on or off filtering, and/or choose
specific filters. You can use either a single
PNG_FILTER_VALUE_NAME or the bitwise OR of one
or more PNG_FILTER_NAME masks.
*/
png_set_filter(png_ptr, 0,
PNG_FILTER_NONE | PNG_FILTER_VALUE_NONE |
PNG_FILTER_SUB | PNG_FILTER_VALUE_SUB |
PNG_FILTER_UP | PNG_FILTER_VALUE_UP |
PNG_FILTER_AVG | PNG_FILTER_VALUE_AVG |
PNG_FILTER_PAETH | PNG_FILTER_VALUE_PAETH|
PNG_ALL_FILTERS);
src/Source/LibPNG/libpng-manual.txt view on Meta::CPAN
setting the pointer to NULL. May be called at any time
after the structure is initialized.
When the simplified API needs to convert between sRGB and linear colorspaces,
the actual sRGB transfer curve defined in the sRGB specification (see the
article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2
approximation used elsewhere in libpng.
WRITE APIS
For write you must initialize a png_image structure to describe the image to
be written:
version: must be set to PNG_IMAGE_VERSION
opaque: must be initialized to NULL
width: image width in pixels
height: image height in rows
format: the format of the data you wish to write
flags: set to 0 unless one of the defined flags applies; set
PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB for color format images
where the RGB values do not correspond to the colors in sRGB.
colormap_entries: set to the number of entries in the color-map (0 to 256)
int png_image_write_to_file, (png_imagep image,
const char *file, int convert_to_8bit, const void *buffer,
png_int_32 row_stride, const void *colormap));
Write the image to the named file.
int png_image_write_to_stdio(png_imagep image, FILE *file,
int convert_to_8_bit, const void *buffer,
png_int_32 row_stride, const void *colormap)
Write the image to the given (FILE*).
With all write APIs if image is in one of the linear formats with
(png_uint_16) data then setting convert_to_8_bit will cause the output to be
a (png_byte) PNG gamma encoded according to the sRGB specification, otherwise
a 16-bit linear encoded PNG file is written.
With all APIs row_stride is handled as in the read APIs - it is the spacing
from one row to the next in component sized units (float) and if negative
indicates a bottom-up row layout in the buffer.
Note that the write API does not support interlacing, sub-8-bit pixels,
and indexed (paletted) images.
VI. Modifying/Customizing libpng
There are two issues here. The first is changing how libpng does
standard things like memory allocation, input/output, and error handling.
The second deals with more complicated things like adding new chunks,
adding new transformations, and generally changing how libpng works.
Both of those are compile-time issues; that is, they are generally
determined at the time the code is written, and there is rarely a need
to provide the user with a means of changing them.
Memory allocation, input/output, and error handling
All of the memory allocation, input/output, and error handling in libpng
goes through callbacks that are user-settable. The default routines are
in pngmem.c, pngrio.c, pngwio.c, and pngerror.c, respectively. To change
these functions, call the appropriate png_set_*_fn() function.
Memory allocation is done through the functions png_malloc(), png_calloc(),
and png_free(). The png_malloc() and png_free() functions currently just
call the standard C functions and png_calloc() calls png_malloc() and then
clears the newly allocated memory to zero; note that png_calloc(png_ptr, size)
is not the same as the calloc(number, size) function provided by stdlib.h.
There is limited support for certain systems with segmented memory
architectures and the types of pointers declared by png.h match this; you
will have to use appropriate pointers in your application. If you prefer
to use a different method of allocating and freeing data, you can use
png_create_read_struct_2() or png_create_write_struct_2() to register your
own functions as described above. These functions also provide a void
pointer that can be retrieved via
mem_ptr=png_get_mem_ptr(png_ptr);
Your replacement memory functions must have prototypes as follows:
png_voidp malloc_fn(png_structp png_ptr,
png_alloc_size_t size);
void free_fn(png_structp png_ptr, png_voidp ptr);
Your malloc_fn() must return NULL in case of failure. The png_malloc()
function will normally call png_error() if it receives a NULL from the
system memory allocator or from your replacement malloc_fn().
Your free_fn() will never be called with a NULL ptr, since libpng's
png_free() checks for NULL before calling free_fn().
Input/Output in libpng is done through png_read() and png_write(),
which currently just call fread() and fwrite(). The FILE * is stored in
png_struct and is initialized via png_init_io(). If you wish to change
the method of I/O, the library supplies callbacks that you can set
through the function png_set_read_fn() and png_set_write_fn() at run
time, instead of calling the png_init_io() function. These functions
also provide a void pointer that can be retrieved via the function
png_get_io_ptr(). For example:
png_set_read_fn(png_structp read_ptr,
voidp read_io_ptr, png_rw_ptr read_data_fn)
png_set_write_fn(png_structp write_ptr,
voidp write_io_ptr, png_rw_ptr write_data_fn,
png_flush_ptr output_flush_fn);
voidp read_io_ptr = png_get_io_ptr(read_ptr);
voidp write_io_ptr = png_get_io_ptr(write_ptr);
The replacement I/O functions must have prototypes as follows:
void user_read_data(png_structp png_ptr,
png_bytep data, png_size_t length);
void user_write_data(png_structp png_ptr,
png_bytep data, png_size_t length);
void user_flush_data(png_structp png_ptr);
The user_read_data() function is responsible for detecting and
handling end-of-data errors.
Supplying NULL for the read, write, or flush functions sets them back
to using the default C stream functions, which expect the io_ptr to
point to a standard *FILE structure. It is probably a mistake
to use NULL for one of write_data_fn and output_flush_fn but not both
of them, unless you have built libpng with PNG_NO_WRITE_FLUSH defined.
It is an error to read from a write stream, and vice versa.
Error handling in libpng is done through png_error() and png_warning().
Errors handled through png_error() are fatal, meaning that png_error()
should never return to its caller. Currently, this is handled via
setjmp() and longjmp() (unless you have compiled libpng with
PNG_NO_SETJMP, in which case it is handled via PNG_ABORT()),
but you could change this to do things like exit() if you should wish,
as long as your function does not return.
On non-fatal errors, png_warning() is called
to print a warning message, and then control returns to the calling code.
By default png_error() and png_warning() print a message on stderr via
fprintf() unless the library is compiled with PNG_NO_CONSOLE_IO defined
(because you don't want the messages) or PNG_NO_STDIO defined (because
fprintf() isn't available). If you wish to change the behavior of the error
functions, you will need to set up your own message callbacks. These
functions are normally supplied at the time that the png_struct is created.
It is also possible to redirect errors and warnings to your own replacement
functions after png_create_*_struct() has been called by calling:
png_set_error_fn(png_structp png_ptr,
png_voidp error_ptr, png_error_ptr error_fn,
png_error_ptr warning_fn);
png_voidp error_ptr = png_get_error_ptr(png_ptr);
If NULL is supplied for either error_fn or warning_fn, then the libpng
default function will be used, calling fprintf() and/or longjmp() if a
problem is encountered. The replacement error functions should have
parameters as follows:
void user_error_fn(png_structp png_ptr,
png_const_charp error_msg);
void user_warning_fn(png_structp png_ptr,
png_const_charp warning_msg);
The motivation behind using setjmp() and longjmp() is the C++ throw and
catch exception handling methods. This makes the code much easier to write,
as there is no need to check every return code of every function call.
However, there are some uncertainties about the status of local variables
after a longjmp, so the user may want to be careful about doing anything
after setjmp returns non-zero besides returning itself. Consult your
compiler documentation for more details. For an alternative approach, you
may wish to use the "cexcept" facility (see http://cexcept.sourceforge.net),
which is illustrated in pngvalid.c and in contrib/visupng.
Beginning in libpng-1.4.0, the png_set_benign_errors() API became available.
You can use this to handle certain errors (normally handled as errors)
as warnings.
png_set_benign_errors (png_ptr, int allowed);
allowed: 0: treat png_benign_error() as an error.
1: treat png_benign_error() as a warning.
As of libpng-1.6.0, the default condition is to treat benign errors as
warnings while reading and as errors while writing.
Custom chunks
If you need to read or write custom chunks, you may need to get deeper
into the libpng code. The library now has mechanisms for storing
and writing chunks of unknown type; you can even declare callbacks
for custom chunks. However, this may not be good enough if the
library code itself needs to know about interactions between your
chunk and existing `intrinsic' chunks.
If you need to write a new intrinsic chunk, first read the PNG
specification. Acquire a first level of understanding of how it works.
Pay particular attention to the sections that describe chunk names,
and look at how other chunks were designed, so you can do things
similarly. Second, check out the sections of libpng that read and
write chunks. Try to find a chunk that is similar to yours and use
it as a template. More details can be found in the comments inside
the code. It is best to handle private or unknown chunks in a generic method,
via callback functions, instead of by modifying libpng functions. This
is illustrated in pngtest.c, which uses a callback function to handle a
private "vpAg" chunk and the new "sTER" chunk, which are both unknown to
libpng.
If you wish to write your own transformation for the data, look through
the part of the code that does the transformations, and check out some of
the simpler ones to get an idea of how they work. Try to find a similar
transformation to the one you want to add and copy off of it. More details
can be found in the comments inside the code itself.
Configuring for gui/windowing platforms:
You will need to write new error and warning functions that use the GUI
interface, as described previously, and set them to be the error and
warning functions at the time that png_create_*_struct() is called,
in order to have them available during the structure initialization.
They can be changed later via png_set_error_fn(). On some compilers,
you may also have to change the memory allocators (png_malloc, etc.).
Configuring zlib:
There are special functions to configure the compression. Perhaps the
most useful one changes the compression level, which currently uses
input compression values in the range 0 - 9. The library normally
uses the default compression level (Z_DEFAULT_COMPRESSION = 6). Tests
have shown that for a large majority of images, compression values in
the range 3-6 compress nearly as well as higher levels, and do so much
faster. For online applications it may be desirable to have maximum speed
(Z_BEST_SPEED = 1). With versions of zlib after v0.99, you can also
specify no compression (Z_NO_COMPRESSION = 0), but this would create
files larger than just storing the raw bitmap. You can specify the
compression level by calling:
#include zlib.h
png_set_compression_level(png_ptr, level);
Another useful one is to reduce the memory level used by the library.
The memory level defaults to 8, but it can be lowered if you are
short on memory (running DOS, for example, where you only have 640K).
Note that the memory level does have an effect on compression; among
other things, lower levels will result in sections of incompressible
data being emitted in smaller stored blocks, with a correspondingly
larger relative overhead of up to 15% in the worst case.
#include zlib.h
png_set_compression_mem_level(png_ptr, level);
src/Source/LibPNG/libpng-manual.txt view on Meta::CPAN
fprintf(stderr, ...
#endif
When PNG_DEBUG = 1, the macros are defined, but only png_debug statements
having level = 0 will be printed. There aren't any such statements in
this version of libpng, but if you insert some they will be printed.
VII. MNG support
The MNG specification (available at http://www.libpng.org/pub/mng) allows
certain extensions to PNG for PNG images that are embedded in MNG datastreams.
Libpng can support some of these extensions. To enable them, use the
png_permit_mng_features() function:
feature_set = png_permit_mng_features(png_ptr, mask)
mask is a png_uint_32 containing the bitwise OR of the
features you want to enable. These include
PNG_FLAG_MNG_EMPTY_PLTE
PNG_FLAG_MNG_FILTER_64
PNG_ALL_MNG_FEATURES
feature_set is a png_uint_32 that is the bitwise AND of
your mask with the set of MNG features that is
supported by the version of libpng that you are using.
It is an error to use this function when reading or writing a standalone
PNG file with the PNG 8-byte signature. The PNG datastream must be wrapped
in a MNG datastream. As a minimum, it must have the MNG 8-byte signature
and the MHDR and MEND chunks. Libpng does not provide support for these
or any other MNG chunks; your application must provide its own support for
them. You may wish to consider using libmng (available at
http://www.libmng.com) instead.
VIII. Changes to Libpng from version 0.88
It should be noted that versions of libpng later than 0.96 are not
distributed by the original libpng author, Guy Schalnat, nor by
Andreas Dilger, who had taken over from Guy during 1996 and 1997, and
distributed versions 0.89 through 0.96, but rather by another member
of the original PNG Group, Glenn Randers-Pehrson. Guy and Andreas are
still alive and well, but they have moved on to other things.
The old libpng functions png_read_init(), png_write_init(),
png_info_init(), png_read_destroy(), and png_write_destroy() have been
moved to PNG_INTERNAL in version 0.95 to discourage their use. These
functions will be removed from libpng version 1.4.0.
The preferred method of creating and initializing the libpng structures is
via the png_create_read_struct(), png_create_write_struct(), and
png_create_info_struct() because they isolate the size of the structures
from the application, allow version error checking, and also allow the
use of custom error handling routines during the initialization, which
the old functions do not. The functions png_read_destroy() and
png_write_destroy() do not actually free the memory that libpng
allocated for these structs, but just reset the data structures, so they
can be used instead of png_destroy_read_struct() and
png_destroy_write_struct() if you feel there is too much system overhead
allocating and freeing the png_struct for each image read.
Setting the error callbacks via png_set_message_fn() before
png_read_init() as was suggested in libpng-0.88 is no longer supported
because this caused applications that do not use custom error functions
to fail if the png_ptr was not initialized to zero. It is still possible
to set the error callbacks AFTER png_read_init(), or to change them with
png_set_error_fn(), which is essentially the same function, but with a new
name to force compilation errors with applications that try to use the old
method.
Support for the sCAL, iCCP, iTXt, and sPLT chunks was added at libpng-1.0.6;
however, iTXt support was not enabled by default.
Starting with version 1.0.7, you can find out which version of the library
you are using at run-time:
png_uint_32 libpng_vn = png_access_version_number();
The number libpng_vn is constructed from the major version, minor
version with leading zero, and release number with leading zero,
(e.g., libpng_vn for version 1.0.7 is 10007).
Note that this function does not take a png_ptr, so you can call it
before you've created one.
You can also check which version of png.h you used when compiling your
application:
png_uint_32 application_vn = PNG_LIBPNG_VER;
IX. Changes to Libpng from version 1.0.x to 1.2.x
Support for user memory management was enabled by default. To
accomplish this, the functions png_create_read_struct_2(),
png_create_write_struct_2(), png_set_mem_fn(), png_get_mem_ptr(),
png_malloc_default(), and png_free_default() were added.
Support for the iTXt chunk has been enabled by default as of
version 1.2.41.
Support for certain MNG features was enabled.
Support for numbered error messages was added. However, we never got
around to actually numbering the error messages. The function
png_set_strip_error_numbers() was added (Note: the prototype for this
function was inadvertently removed from png.h in PNG_NO_ASSEMBLER_CODE
builds of libpng-1.2.15. It was restored in libpng-1.2.36).
The png_malloc_warn() function was added at libpng-1.2.3. This issues
a png_warning and returns NULL instead of aborting when it fails to
acquire the requested memory allocation.
Support for setting user limits on image width and height was enabled
by default. The functions png_set_user_limits(), png_get_user_width_max(),
and png_get_user_height_max() were added at libpng-1.2.6.
The png_set_add_alpha() function was added at libpng-1.2.7.
The function png_set_expand_gray_1_2_4_to_8() was added at libpng-1.2.9.
Unlike png_set_gray_1_2_4_to_8(), the new function does not expand the
tRNS chunk to alpha. The png_set_gray_1_2_4_to_8() function is
deprecated.
A number of macro definitions in support of runtime selection of
assembler code features (especially Intel MMX code support) were
added at libpng-1.2.0:
( run in 0.382 second using v1.01-cache-2.11-cpan-63c85eba8c4 )