mirror of https://github.com/roytam1/UXP
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5406 lines
223 KiB
5406 lines
223 KiB
5 years ago
|
libpng-manual.txt - A description on how to use and modify libpng
|
||
|
|
||
|
libpng version 1.6.26 - October 20, 2016
|
||
|
Updated and distributed by Glenn Randers-Pehrson
|
||
|
<glennrp at users.sourceforge.net>
|
||
|
Copyright (c) 1998-2016 Glenn Randers-Pehrson
|
||
|
|
||
|
This document is released under the libpng license.
|
||
|
For conditions of distribution and use, see the disclaimer
|
||
|
and license in png.h
|
||
|
|
||
|
Based on:
|
||
|
|
||
|
libpng versions 0.97, January 1998, through 1.6.26 - October 20, 2016
|
||
|
Updated and distributed by Glenn Randers-Pehrson
|
||
|
Copyright (c) 1998-2016 Glenn Randers-Pehrson
|
||
|
|
||
|
libpng 1.0 beta 6 - version 0.96 - May 28, 1997
|
||
|
Updated and distributed by Andreas Dilger
|
||
|
Copyright (c) 1996, 1997 Andreas Dilger
|
||
|
|
||
|
libpng 1.0 beta 2 - version 0.88 - January 26, 1996
|
||
|
For conditions of distribution and use, see copyright
|
||
|
notice in png.h. Copyright (c) 1995, 1996 Guy Eric
|
||
|
Schalnat, Group 42, Inc.
|
||
|
|
||
|
Updated/rewritten per request in the libpng FAQ
|
||
|
Copyright (c) 1995, 1996 Frank J. T. Wojcik
|
||
|
December 18, 1995 & January 20, 1996
|
||
|
|
||
|
TABLE OF CONTENTS
|
||
|
|
||
|
I. Introduction
|
||
|
II. Structures
|
||
|
III. Reading
|
||
|
IV. Writing
|
||
|
V. Simplified API
|
||
|
VI. Modifying/Customizing libpng
|
||
|
VII. MNG support
|
||
|
VIII. Changes to Libpng from version 0.88
|
||
|
IX. Changes to Libpng from version 1.0.x to 1.2.x
|
||
|
X. Changes to Libpng from version 1.0.x/1.2.x to 1.4.x
|
||
|
XI. Changes to Libpng from version 1.4.x to 1.5.x
|
||
|
XII. Changes to Libpng from version 1.5.x to 1.6.x
|
||
|
XIII. Detecting libpng
|
||
|
XIV. Source code repository
|
||
|
XV. Coding style
|
||
|
XVI. Y2K Compliance in libpng
|
||
|
|
||
|
I. Introduction
|
||
|
|
||
|
This file describes how to use and modify the PNG reference library
|
||
|
(known as libpng) for your own use. In addition to this
|
||
|
file, example.c is a good starting point for using the library, as
|
||
|
it is heavily commented and should include everything most people
|
||
|
will need. We assume that libpng is already installed; see the
|
||
|
INSTALL file for instructions on how to configure and install libpng.
|
||
|
|
||
|
For examples of libpng usage, see the files "example.c", "pngtest.c",
|
||
|
and the files in the "contrib" directory, all of which are included in
|
||
|
the libpng distribution.
|
||
|
|
||
|
Libpng was written as a companion to the PNG specification, as a way
|
||
|
of reducing the amount of time and effort it takes to support the PNG
|
||
|
file format in application programs.
|
||
|
|
||
|
The PNG specification (second edition), November 2003, is available as
|
||
|
a W3C Recommendation and as an ISO Standard (ISO/IEC 15948:2004 (E)) at
|
||
|
<http://www.w3.org/TR/2003/REC-PNG-20031110/
|
||
|
The W3C and ISO documents have identical technical content.
|
||
|
|
||
|
The PNG-1.2 specification is available at
|
||
|
<http://png-mng.sourceforge.net/pub/png/spec/1.2/>.
|
||
|
It is technically equivalent
|
||
|
to the PNG specification (second edition) but has some additional material.
|
||
|
|
||
|
The PNG-1.0 specification is available as RFC 2083
|
||
|
<http://png-mng.sourceforge.net/pub/png/spec/1.0/> and as a
|
||
|
W3C Recommendation <http://www.w3.org/TR/REC-png-961001>.
|
||
|
|
||
|
Some additional chunks are described in the special-purpose public chunks
|
||
|
documents at <http://www.libpng.org/pub/png/spec/register/>
|
||
|
|
||
|
Other information
|
||
|
about PNG, and the latest version of libpng, can be found at the PNG home
|
||
|
page, <http://www.libpng.org/pub/png/>.
|
||
|
|
||
|
Most users will not have to modify the library significantly; advanced
|
||
|
users may want to modify it more. All attempts were made to make it as
|
||
|
complete as possible, while keeping the code easy to understand.
|
||
|
Currently, this library only supports C. Support for other languages
|
||
|
is being considered.
|
||
|
|
||
|
Libpng has been designed to handle multiple sessions at one time,
|
||
|
to be easily modifiable, to be portable to the vast majority of
|
||
|
machines (ANSI, K&R, 16-, 32-, and 64-bit) available, and to be easy
|
||
|
to use. The ultimate goal of libpng is to promote the acceptance of
|
||
|
the PNG file format in whatever way possible. While there is still
|
||
|
work to be done (see the TODO file), libpng should cover the
|
||
|
majority of the needs of its users.
|
||
|
|
||
|
Libpng uses zlib for its compression and decompression of PNG files.
|
||
|
Further information about zlib, and the latest version of zlib, can
|
||
|
be found at the zlib home page, <http://zlib.net/>.
|
||
|
The zlib compression utility is a general purpose utility that is
|
||
|
useful for more than PNG files, and can be used without libpng.
|
||
|
See the documentation delivered with zlib for more details.
|
||
|
You can usually find the source files for the zlib utility wherever you
|
||
|
find the libpng source files.
|
||
|
|
||
|
Libpng is thread safe, provided the threads are using different
|
||
|
instances of the structures. Each thread should have its own
|
||
|
png_struct and png_info instances, and thus its own image.
|
||
|
Libpng does not protect itself against two threads using the
|
||
|
same instance of a structure.
|
||
|
|
||
|
II. Structures
|
||
|
|
||
|
There are two main structures that are important to libpng, png_struct
|
||
|
and png_info. Both are internal structures that are no longer exposed
|
||
|
in the libpng interface (as of libpng 1.5.0).
|
||
|
|
||
|
The png_info structure is designed to provide information about the
|
||
|
PNG file. At one time, the fields of png_info were intended to be
|
||
|
directly accessible to the user. However, this tended to cause problems
|
||
|
with applications using dynamically loaded libraries, and as a result
|
||
|
a set of interface functions for png_info (the png_get_*() and png_set_*()
|
||
|
functions) was developed, and direct access to the png_info fields was
|
||
|
deprecated..
|
||
|
|
||
|
The png_struct structure is the object used by the library to decode a
|
||
|
single image. As of 1.5.0 this structure is also not exposed.
|
||
|
|
||
|
Almost all libpng APIs require a pointer to a png_struct as the first argument.
|
||
|
Many (in particular the png_set and png_get APIs) also require a pointer
|
||
|
to png_info as the second argument. Some application visible macros
|
||
|
defined in png.h designed for basic data access (reading and writing
|
||
|
integers in the PNG format) don't take a png_info pointer, but it's almost
|
||
|
always safe to assume that a (png_struct*) has to be passed to call an API
|
||
|
function.
|
||
|
|
||
|
You can have more than one png_info structure associated with an image,
|
||
|
as illustrated in pngtest.c, one for information valid prior to the
|
||
|
IDAT chunks and another (called "end_info" below) for things after them.
|
||
|
|
||
|
The png.h header file is an invaluable reference for programming with libpng.
|
||
|
And while I'm on the topic, make sure you include the libpng header file:
|
||
|
|
||
|
#include <png.h>
|
||
|
|
||
|
and also (as of libpng-1.5.0) the zlib header file, if you need it:
|
||
|
|
||
|
#include <zlib.h>
|
||
|
|
||
|
Types
|
||
|
|
||
|
The png.h header file defines a number of integral types used by the
|
||
|
APIs. Most of these are fairly obvious; for example types corresponding
|
||
|
to integers of particular sizes and types for passing color values.
|
||
|
|
||
|
One exception is how non-integral numbers are handled. For application
|
||
|
convenience most APIs that take such numbers have C (double) arguments;
|
||
|
however, internally PNG, and libpng, use 32 bit signed integers and encode
|
||
|
the value by multiplying by 100,000. As of libpng 1.5.0 a convenience
|
||
|
macro PNG_FP_1 is defined in png.h along with a type (png_fixed_point)
|
||
|
which is simply (png_int_32).
|
||
|
|
||
|
All APIs that take (double) arguments also have a matching API that
|
||
|
takes the corresponding fixed point integer arguments. The fixed point
|
||
|
API has the same name as the floating point one with "_fixed" appended.
|
||
|
The actual range of values permitted in the APIs is frequently less than
|
||
|
the full range of (png_fixed_point) (-21474 to +21474). When APIs require
|
||
|
a non-negative argument the type is recorded as png_uint_32 above. Consult
|
||
|
the header file and the text below for more information.
|
||
|
|
||
|
Special care must be take with sCAL chunk handling because the chunk itself
|
||
|
uses non-integral values encoded as strings containing decimal floating point
|
||
|
numbers. See the comments in the header file.
|
||
|
|
||
|
Configuration
|
||
|
|
||
|
The main header file function declarations are frequently protected by C
|
||
|
preprocessing directives of the form:
|
||
|
|
||
|
#ifdef PNG_feature_SUPPORTED
|
||
|
declare-function
|
||
|
#endif
|
||
|
...
|
||
|
#ifdef PNG_feature_SUPPORTED
|
||
|
use-function
|
||
|
#endif
|
||
|
|
||
|
The library can be built without support for these APIs, although a
|
||
|
standard build will have all implemented APIs. Application programs
|
||
|
should check the feature macros before using an API for maximum
|
||
|
portability. From libpng 1.5.0 the feature macros set during the build
|
||
|
of libpng are recorded in the header file "pnglibconf.h" and this file
|
||
|
is always included by png.h.
|
||
|
|
||
|
If you don't need to change the library configuration from the default, skip to
|
||
|
the next section ("Reading").
|
||
|
|
||
|
Notice that some of the makefiles in the 'scripts' directory and (in 1.5.0) all
|
||
|
of the build project files in the 'projects' directory simply copy
|
||
|
scripts/pnglibconf.h.prebuilt to pnglibconf.h. This means that these build
|
||
|
systems do not permit easy auto-configuration of the library - they only
|
||
|
support the default configuration.
|
||
|
|
||
|
The easiest way to make minor changes to the libpng configuration when
|
||
|
auto-configuration is supported is to add definitions to the command line
|
||
|
using (typically) CPPFLAGS. For example:
|
||
|
|
||
|
CPPFLAGS=-DPNG_NO_FLOATING_ARITHMETIC
|
||
|
|
||
|
will change the internal libpng math implementation for gamma correction and
|
||
|
other arithmetic calculations to fixed point, avoiding the need for fast
|
||
|
floating point support. The result can be seen in the generated pnglibconf.h -
|
||
|
make sure it contains the changed feature macro setting.
|
||
|
|
||
|
If you need to make more extensive configuration changes - more than one or two
|
||
|
feature macro settings - you can either add -DPNG_USER_CONFIG to the build
|
||
|
command line and put a list of feature macro settings in pngusr.h or you can set
|
||
|
DFA_XTRA (a makefile variable) to a file containing the same information in the
|
||
|
form of 'option' settings.
|
||
|
|
||
|
A. Changing pnglibconf.h
|
||
|
|
||
|
A variety of methods exist to build libpng. Not all of these support
|
||
|
reconfiguration of pnglibconf.h. To reconfigure pnglibconf.h it must either be
|
||
|
rebuilt from scripts/pnglibconf.dfa using awk or it must be edited by hand.
|
||
|
|
||
|
Hand editing is achieved by copying scripts/pnglibconf.h.prebuilt to
|
||
|
pnglibconf.h and changing the lines defining the supported features, paying
|
||
|
very close attention to the 'option' information in scripts/pnglibconf.dfa
|
||
|
that describes those features and their requirements. This is easy to get
|
||
|
wrong.
|
||
|
|
||
|
B. Configuration using DFA_XTRA
|
||
|
|
||
|
Rebuilding from pnglibconf.dfa is easy if a functioning 'awk', or a later
|
||
|
variant such as 'nawk' or 'gawk', is available. The configure build will
|
||
|
automatically find an appropriate awk and build pnglibconf.h.
|
||
|
The scripts/pnglibconf.mak file contains a set of make rules for doing the
|
||
|
same thing if configure is not used, and many of the makefiles in the scripts
|
||
|
directory use this approach.
|
||
|
|
||
|
When rebuilding simply write a new file containing changed options and set
|
||
|
DFA_XTRA to the name of this file. This causes the build to append the new file
|
||
|
to the end of scripts/pnglibconf.dfa. The pngusr.dfa file should contain lines
|
||
|
of the following forms:
|
||
|
|
||
|
everything = off
|
||
|
|
||
|
This turns all optional features off. Include it at the start of pngusr.dfa to
|
||
|
make it easier to build a minimal configuration. You will need to turn at least
|
||
|
some features on afterward to enable either reading or writing code, or both.
|
||
|
|
||
|
option feature on
|
||
|
option feature off
|
||
|
|
||
|
Enable or disable a single feature. This will automatically enable other
|
||
|
features required by a feature that is turned on or disable other features that
|
||
|
require a feature which is turned off. Conflicting settings will cause an error
|
||
|
message to be emitted by awk.
|
||
|
|
||
|
setting feature default value
|
||
|
|
||
|
Changes the default value of setting 'feature' to 'value'. There are a small
|
||
|
number of settings listed at the top of pnglibconf.h, they are documented in the
|
||
|
source code. Most of these values have performance implications for the library
|
||
|
but most of them have no visible effect on the API. Some can also be overridden
|
||
|
from the API.
|
||
|
|
||
|
This method of building a customized pnglibconf.h is illustrated in
|
||
|
contrib/pngminim/*. See the "$(PNGCONF):" target in the makefile and
|
||
|
pngusr.dfa in these directories.
|
||
|
|
||
|
C. Configuration using PNG_USER_CONFIG
|
||
|
|
||
|
If -DPNG_USER_CONFIG is added to the CPPFLAGS when pnglibconf.h is built,
|
||
|
the file pngusr.h will automatically be included before the options in
|
||
|
scripts/pnglibconf.dfa are processed. Your pngusr.h file should contain only
|
||
|
macro definitions turning features on or off or setting settings.
|
||
|
|
||
|
Apart from the global setting "everything = off" all the options listed above
|
||
|
can be set using macros in pngusr.h:
|
||
|
|
||
|
#define PNG_feature_SUPPORTED
|
||
|
|
||
|
is equivalent to:
|
||
|
|
||
|
option feature on
|
||
|
|
||
|
#define PNG_NO_feature
|
||
|
|
||
|
is equivalent to:
|
||
|
|
||
|
option feature off
|
||
|
|
||
|
#define PNG_feature value
|
||
|
|
||
|
is equivalent to:
|
||
|
|
||
|
setting feature default value
|
||
|
|
||
|
Notice that in both cases, pngusr.dfa and pngusr.h, the contents of the
|
||
|
pngusr file you supply override the contents of scripts/pnglibconf.dfa
|
||
|
|
||
|
If confusing or incomprehensible behavior results it is possible to
|
||
|
examine the intermediate file pnglibconf.dfn to find the full set of
|
||
|
dependency information for each setting and option. Simply locate the
|
||
|
feature in the file and read the C comments that precede it.
|
||
|
|
||
|
This method is also illustrated in the contrib/pngminim/* makefiles and
|
||
|
pngusr.h.
|
||
|
|
||
|
III. Reading
|
||
|
|
||
|
We'll now walk you through the possible functions to call when reading
|
||
|
in a PNG file sequentially, briefly explaining the syntax and purpose
|
||
|
of each one. See example.c and png.h for more detail. While
|
||
|
progressive reading is covered in the next section, you will still
|
||
|
need some of the functions discussed in this section to read a PNG
|
||
|
file.
|
||
|
|
||
|
Setup
|
||
|
|
||
|
You will want to do the I/O initialization(*) before you get into libpng,
|
||
|
so if it doesn't work, you don't have much to undo. Of course, you
|
||
|
will also want to insure that you are, in fact, dealing with a PNG
|
||
|
file. Libpng provides a simple check to see if a file is a PNG file.
|
||
|
To use it, pass in the first 1 to 8 bytes of the file to the function
|
||
|
png_sig_cmp(), and it will return 0 (false) if the bytes match the
|
||
|
corresponding bytes of the PNG signature, or nonzero (true) otherwise.
|
||
|
Of course, the more bytes you pass in, the greater the accuracy of the
|
||
|
prediction.
|
||
|
|
||
|
If you are intending to keep the file pointer open for use in libpng,
|
||
|
you must ensure you don't read more than 8 bytes from the beginning
|
||
|
of the file, and you also have to make a call to png_set_sig_bytes()
|
||
|
with the number of bytes you read from the beginning. Libpng will
|
||
|
then only check the bytes (if any) that your program didn't read.
|
||
|
|
||
|
(*): If you are not using the standard I/O functions, you will need
|
||
|
to replace them with custom functions. See the discussion under
|
||
|
Customizing libpng.
|
||
|
|
||
|
FILE *fp = fopen(file_name, "rb");
|
||
|
if (!fp)
|
||
|
{
|
||
|
return (ERROR);
|
||
|
}
|
||
|
|
||
|
if (fread(header, 1, number, fp) != number)
|
||
|
{
|
||
|
return (ERROR);
|
||
|
}
|
||
|
|
||
|
is_png = !png_sig_cmp(header, 0, number);
|
||
|
if (!is_png)
|
||
|
{
|
||
|
return (NOT_PNG);
|
||
|
}
|
||
|
|
||
|
Next, png_struct and png_info need to be allocated and initialized. In
|
||
|
order to ensure that the size of these structures is correct even with a
|
||
|
dynamically linked libpng, there are functions to initialize and
|
||
|
allocate the structures. We also pass the library version, optional
|
||
|
pointers to error handling functions, and a pointer to a data struct for
|
||
|
use by the error functions, if necessary (the pointer and functions can
|
||
|
be NULL if the default error handlers are to be used). See the section
|
||
|
on Changes to Libpng below regarding the old initialization functions.
|
||
|
The structure allocation functions quietly return NULL if they fail to
|
||
|
create the structure, so your application should check for that.
|
||
|
|
||
|
png_structp 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);
|
||
|
|
||
|
png_infop 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 you want to use your own memory allocation routines,
|
||
|
use a libpng that was built with PNG_USER_MEM_SUPPORTED defined, and use
|
||
|
png_create_read_struct_2() instead of png_create_read_struct():
|
||
|
|
||
|
png_structp png_ptr = png_create_read_struct_2
|
||
|
(PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr,
|
||
|
user_error_fn, user_warning_fn, (png_voidp)
|
||
|
user_mem_ptr, user_malloc_fn, user_free_fn);
|
||
|
|
||
|
The error handling routines passed to png_create_read_struct()
|
||
|
and the memory alloc/free routines passed to png_create_struct_2()
|
||
|
are only necessary if you are not using the libpng supplied error
|
||
|
handling and memory alloc/free functions.
|
||
|
|
||
|
When libpng encounters an error, it expects to longjmp back
|
||
|
to your routine. Therefore, you will need to call setjmp and pass
|
||
|
your png_jmpbuf(png_ptr). If you read the file from different
|
||
|
routines, you will need to update the longjmp buffer 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 an error occurs, and libpng longjmp's
|
||
|
back to your setjmp, you will want to call png_destroy_read_struct() to
|
||
|
free any memory.
|
||
|
|
||
|
if (setjmp(png_jmpbuf(png_ptr)))
|
||
|
{
|
||
|
png_destroy_read_struct(&png_ptr, &info_ptr,
|
||
|
&end_info);
|
||
|
fclose(fp);
|
||
|
return (ERROR);
|
||
|
}
|
||
|
|
||
|
Pass (png_infopp)NULL instead of &end_info if you didn't create
|
||
|
an end_info structure.
|
||
|
|
||
|
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.
|
||
|
|
||
|
Now you need to set up the input code. The default for libpng is to
|
||
|
use the C function fread(). 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. If you wish to handle reading data in another
|
||
|
way, you need not call the png_init_io() function, but you must then
|
||
|
implement the libpng I/O methods discussed in the Customizing Libpng
|
||
|
section below.
|
||
|
|
||
|
png_init_io(png_ptr, fp);
|
||
|
|
||
|
If you had previously opened the file and read any of the signature from
|
||
|
the beginning in order to see if this was a PNG file, you need to let
|
||
|
libpng know that there are some bytes missing from the start of the file.
|
||
|
|
||
|
png_set_sig_bytes(png_ptr, number);
|
||
|
|
||
|
You can change the zlib compression buffer size to be used while
|
||
|
reading compressed data with
|
||
|
|
||
|
png_set_compression_buffer_size(png_ptr, buffer_size);
|
||
|
|
||
|
where the default size is 8192 bytes. Note that the buffer size
|
||
|
is changed immediately and the buffer is reallocated immediately,
|
||
|
instead of setting a flag to be acted upon later.
|
||
|
|
||
|
If you want CRC errors to be handled in a different manner than
|
||
|
the default, use
|
||
|
|
||
|
png_set_crc_action(png_ptr, crit_action, ancil_action);
|
||
|
|
||
|
The values for png_set_crc_action() say how libpng is to handle CRC errors in
|
||
|
ancillary and critical chunks, and whether to use the data contained
|
||
|
therein. Starting with libpng-1.6.26, this also governs how an ADLER32 error
|
||
|
is handled while reading the IDAT chunk. Note that it is impossible to
|
||
|
"discard" data in a critical chunk.
|
||
|
|
||
|
Choices for (int) crit_action are
|
||
|
PNG_CRC_DEFAULT 0 error/quit
|
||
|
PNG_CRC_ERROR_QUIT 1 error/quit
|
||
|
PNG_CRC_WARN_USE 3 warn/use data
|
||
|
PNG_CRC_QUIET_USE 4 quiet/use data
|
||
|
PNG_CRC_NO_CHANGE 5 use the current value
|
||
|
|
||
|
Choices for (int) ancil_action are
|
||
|
PNG_CRC_DEFAULT 0 error/quit
|
||
|
PNG_CRC_ERROR_QUIT 1 error/quit
|
||
|
PNG_CRC_WARN_DISCARD 2 warn/discard data
|
||
|
PNG_CRC_WARN_USE 3 warn/use data
|
||
|
PNG_CRC_QUIET_USE 4 quiet/use data
|
||
|
PNG_CRC_NO_CHANGE 5 use the current value
|
||
|
|
||
|
When the setting for crit_action is PNG_CRC_QUIET_USE, the CRC and ADLER32
|
||
|
checksums are not only ignored, but they are not evaluated.
|
||
|
|
||
|
Setting up callback code
|
||
|
|
||
|
You can set up a callback function to handle any unknown chunks in the
|
||
|
input stream. You must supply the function
|
||
|
|
||
|
read_chunk_callback(png_structp png_ptr,
|
||
|
png_unknown_chunkp chunk);
|
||
|
{
|
||
|
/* The unknown chunk structure contains your
|
||
|
chunk data, along with similar data for any other
|
||
|
unknown chunks: */
|
||
|
|
||
|
png_byte name[5];
|
||
|
png_byte *data;
|
||
|
png_size_t size;
|
||
|
|
||
|
/* Note that libpng has already taken care of
|
||
|
the CRC handling */
|
||
|
|
||
|
/* put your code here. Search for your chunk in the
|
||
|
unknown chunk structure, process it, and return one
|
||
|
of the following: */
|
||
|
|
||
|
return (-n); /* chunk had an error */
|
||
|
return (0); /* did not recognize */
|
||
|
return (n); /* success */
|
||
|
}
|
||
|
|
||
|
(You can give your function another name that you like instead of
|
||
|
"read_chunk_callback")
|
||
|
|
||
|
To inform libpng about your function, use
|
||
|
|
||
|
png_set_read_user_chunk_fn(png_ptr, user_chunk_ptr,
|
||
|
read_chunk_callback);
|
||
|
|
||
|
This names not only the callback function, but also a user pointer that
|
||
|
you can retrieve with
|
||
|
|
||
|
png_get_user_chunk_ptr(png_ptr);
|
||
|
|
||
|
If you call the png_set_read_user_chunk_fn() function, then all unknown
|
||
|
chunks which the callback does not handle will be saved when read. You can
|
||
|
cause them to be discarded by returning '1' ("handled") instead of '0'. This
|
||
|
behavior will change in libpng 1.7 and the default handling set by the
|
||
|
png_set_keep_unknown_chunks() function, described below, will be used when the
|
||
|
callback returns 0. If you want the existing behavior you should set the global
|
||
|
default to PNG_HANDLE_CHUNK_IF_SAFE now; this is compatible with all current
|
||
|
versions of libpng and with 1.7. Libpng 1.6 issues a warning if you keep the
|
||
|
default, or PNG_HANDLE_CHUNK_NEVER, and the callback returns 0.
|
||
|
|
||
|
At this point, you can set up a callback function that will be
|
||
|
called after each row has been read, which you can use to control
|
||
|
a progress meter or the like. It's demonstrated in pngtest.c.
|
||
|
You must supply a function
|
||
|
|
||
|
void read_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 "read_row_callback")
|
||
|
|
||
|
To inform libpng about your function, use
|
||
|
|
||
|
png_set_read_status_fn(png_ptr, read_row_callback);
|
||
|
|
||
|
When this function is called the row has already been completely processed and
|
||
|
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.
|
||
|
|
||
|
Unknown-chunk handling
|
||
|
|
||
|
Now you get to set the way the library processes unknown chunks in the
|
||
|
input PNG stream. Both known and unknown chunks will be read. Normal
|
||
|
behavior is that known chunks will be parsed into information in
|
||
|
various info_ptr members while unknown chunks will be discarded. This
|
||
|
behavior can be wasteful if your application will never use some known
|
||
|
chunk types. To change this, you can call:
|
||
|
|
||
|
png_set_keep_unknown_chunks(png_ptr, keep,
|
||
|
chunk_list, num_chunks);
|
||
|
|
||
|
keep - 0: default unknown chunk handling
|
||
|
1: ignore; do not keep
|
||
|
2: keep only if safe-to-copy
|
||
|
3: keep even if unsafe-to-copy
|
||
|
|
||
|
You can use these definitions:
|
||
|
PNG_HANDLE_CHUNK_AS_DEFAULT 0
|
||
|
PNG_HANDLE_CHUNK_NEVER 1
|
||
|
PNG_HANDLE_CHUNK_IF_SAFE 2
|
||
|
PNG_HANDLE_CHUNK_ALWAYS 3
|
||
|
|
||
|
chunk_list - list of chunks affected (a byte string,
|
||
|
five bytes per chunk, NULL or '\0' if
|
||
|
num_chunks is positive; ignored if
|
||
|
numchunks <= 0).
|
||
|
|
||
|
num_chunks - number of chunks affected; if 0, all
|
||
|
unknown chunks are affected. If positive,
|
||
|
only the chunks in the list are affected,
|
||
|
and if negative all unknown chunks and
|
||
|
all known chunks except for the IHDR,
|
||
|
PLTE, tRNS, IDAT, and IEND chunks are
|
||
|
affected.
|
||
|
|
||
|
Unknown chunks declared in this way will be saved as raw data onto a
|
||
|
list of png_unknown_chunk structures. If a chunk that is normally
|
||
|
known to libpng is named in the list, it will be handled as unknown,
|
||
|
according to the "keep" directive. If a chunk is named in successive
|
||
|
instances of png_set_keep_unknown_chunks(), the final instance will
|
||
|
take precedence. The IHDR and IEND chunks should not be named in
|
||
|
chunk_list; if they are, libpng will process them normally anyway.
|
||
|
If you know that your application will never make use of some particular
|
||
|
chunks, use PNG_HANDLE_CHUNK_NEVER (or 1) as demonstrated below.
|
||
|
|
||
|
Here is an example of the usage of png_set_keep_unknown_chunks(),
|
||
|
where the private "vpAg" chunk will later be processed by a user chunk
|
||
|
callback function:
|
||
|
|
||
|
png_byte vpAg[5]={118, 112, 65, 103, (png_byte) '\0'};
|
||
|
|
||
|
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||
|
png_byte unused_chunks[]=
|
||
|
{
|
||
|
104, 73, 83, 84, (png_byte) '\0', /* hIST */
|
||
|
105, 84, 88, 116, (png_byte) '\0', /* iTXt */
|
||
|
112, 67, 65, 76, (png_byte) '\0', /* pCAL */
|
||
|
115, 67, 65, 76, (png_byte) '\0', /* sCAL */
|
||
|
115, 80, 76, 84, (png_byte) '\0', /* sPLT */
|
||
|
116, 73, 77, 69, (png_byte) '\0', /* tIME */
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
...
|
||
|
|
||
|
#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED)
|
||
|
/* ignore all unknown chunks
|
||
|
* (use global setting "2" for libpng16 and earlier):
|
||
|
*/
|
||
|
png_set_keep_unknown_chunks(read_ptr, 2, NULL, 0);
|
||
|
|
||
|
/* except for vpAg: */
|
||
|
png_set_keep_unknown_chunks(read_ptr, 2, vpAg, 1);
|
||
|
|
||
|
/* also ignore unused known chunks: */
|
||
|
png_set_keep_unknown_chunks(read_ptr, 1, unused_chunks,
|
||
|
(int)(sizeof unused_chunks)/5);
|
||
|
#endif
|
||
|
|
||
|
User limits
|
||
|
|
||
|
The PNG specification allows the width and height of an image to be as
|
||
|
large as 2^31-1 (0x7fffffff), or about 2.147 billion rows and columns.
|
||
|
For safety, libpng imposes a default limit of 1 million rows and columns.
|
||
|
Larger images will be rejected immediately with a png_error() call. If
|
||
|
you wish to change these limits, you can use
|
||
|
|
||
|
png_set_user_limits(png_ptr, width_max, height_max);
|
||
|
|
||
|
to set your own limits (libpng may reject some very wide images
|
||
|
anyway because of potential buffer overflow conditions).
|
||
|
|
||
|
You should put this statement after you create the PNG structure and
|
||
|
before calling png_read_info(), png_read_png(), or png_process_data().
|
||
|
|
||
|
When writing a PNG datastream, put this statement before calling
|
||
|
png_write_info() or png_write_png().
|
||
|
|
||
|
If you need to retrieve the limits that are being applied, use
|
||
|
|
||
|
width_max = png_get_user_width_max(png_ptr);
|
||
|
height_max = png_get_user_height_max(png_ptr);
|
||
|
|
||
|
The PNG specification sets no limit on the number of ancillary chunks
|
||
|
allowed in a PNG datastream. By default, libpng imposes a limit of
|
||
|
a total of 1000 sPLT, tEXt, iTXt, zTXt, and unknown chunks to be stored.
|
||
|
If you have set up both info_ptr and end_info_ptr, the limit applies
|
||
|
separately to each. You can change the limit on the total number of such
|
||
|
chunks that will be stored, with
|
||
|
|
||
|
png_set_chunk_cache_max(png_ptr, user_chunk_cache_max);
|
||
|
|
||
|
where 0x7fffffffL means unlimited. You can retrieve this limit with
|
||
|
|
||
|
chunk_cache_max = png_get_chunk_cache_max(png_ptr);
|
||
|
|
||
|
Libpng imposes a limit of 8 Megabytes (8,000,000 bytes) on the amount of
|
||
|
memory that a compressed chunk other than IDAT can occupy, when decompressed.
|
||
|
You can change this limit with
|
||
|
|
||
|
png_set_chunk_malloc_max(png_ptr, user_chunk_malloc_max);
|
||
|
|
||
|
and you can retrieve the limit with
|
||
|
|
||
|
chunk_malloc_max = png_get_chunk_malloc_max(png_ptr);
|
||
|
|
||
|
Any chunks that would cause either of these limits to be exceeded will
|
||
|
be ignored.
|
||
|
|
||
|
Information about your system
|
||
|
|
||
|
If you intend to display the PNG or to incorporate it in other image data you
|
||
|
need to tell libpng information about your display or drawing surface so that
|
||
|
libpng can convert the values in the image to match the display.
|
||
|
|
||
|
From libpng-1.5.4 this information can be set before reading the PNG file
|
||
|
header. In earlier versions png_set_gamma() existed but behaved incorrectly if
|
||
|
called before the PNG file header had been read and png_set_alpha_mode() did not
|
||
|
exist.
|
||
|
|
||
|
If you need to support versions prior to libpng-1.5.4 test the version number
|
||
|
as illustrated below using "PNG_LIBPNG_VER >= 10504" and follow the procedures
|
||
|
described in the appropriate manual page.
|
||
|
|
||
|
You give libpng the encoding expected by your system expressed as a 'gamma'
|
||
|
value. You can also specify a default encoding for the PNG file in
|
||
|
case the required information is missing from the file. By default libpng
|
||
|
assumes that the PNG data matches your system, to keep this default call:
|
||
|
|
||
|
png_set_gamma(png_ptr, screen_gamma, output_gamma);
|
||
|
|
||
|
or you can use the fixed point equivalent:
|
||
|
|
||
|
png_set_gamma_fixed(png_ptr, PNG_FP_1*screen_gamma,
|
||
|
PNG_FP_1*output_gamma);
|
||
|
|
||
|
If you don't know the gamma for your system it is probably 2.2 - a good
|
||
|
approximation to the IEC standard for display systems (sRGB). If images are
|
||
|
too contrasty or washed out you got the value wrong - check your system
|
||
|
documentation!
|
||
|
|
||
|
Many systems permit the system gamma to be changed via a lookup table in the
|
||
|
display driver, a few systems, including older Macs, change the response by
|
||
|
default. As of 1.5.4 three special values are available to handle common
|
||
|
situations:
|
||
|
|
||
|
PNG_DEFAULT_sRGB: Indicates that the system conforms to the
|
||
|
IEC 61966-2-1 standard. This matches almost
|
||
|
all systems.
|
||
|
PNG_GAMMA_MAC_18: Indicates that the system is an older
|
||
|
(pre Mac OS 10.6) Apple Macintosh system with
|
||
|
the default settings.
|
||
|
PNG_GAMMA_LINEAR: Just the fixed point value for 1.0 - indicates
|
||
|
that the system expects data with no gamma
|
||
|
encoding.
|
||
|
|
||
|
You would use the linear (unencoded) value if you need to process the pixel
|
||
|
values further because this avoids the need to decode and re-encode each
|
||
|
component value whenever arithmetic is performed. A lot of graphics software
|
||
|
uses linear values for this reason, often with higher precision component values
|
||
|
to preserve overall accuracy.
|
||
|
|
||
|
|
||
|
The output_gamma value expresses how to decode the output values, not how
|
||
|
they are encoded. The values used correspond to the normal numbers used to
|
||
|
describe the overall gamma of a computer display system; for example 2.2 for
|
||
|
an sRGB conformant system. The values are scaled by 100000 in the _fixed
|
||
|
version of the API (so 220000 for sRGB.)
|
||
|
|
||
|
The inverse of the value is always used to provide a default for the PNG file
|
||
|
encoding if it has no gAMA chunk and if png_set_gamma() has not been called
|
||
|
to override the PNG gamma information.
|
||
|
|
||
|
When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode
|
||
|
opaque pixels however pixels with lower alpha values are not encoded,
|
||
|
regardless of the output gamma setting.
|
||
|
|
||
|
When the standard Porter Duff handling is requested with mode 1 the output
|
||
|
encoding is set to be linear and the output_gamma value is only relevant
|
||
|
as a default for input data that has no gamma information. The linear output
|
||
|
encoding will be overridden if png_set_gamma() is called - the results may be
|
||
|
highly unexpected!
|
||
|
|
||
|
The following numbers are derived from the sRGB standard and the research
|
||
|
behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of
|
||
|
0.45455 (1/2.2) for PNG. The value implicitly includes any viewing
|
||
|
correction required to take account of any differences in the color
|
||
|
environment of the original scene and the intended display environment; the
|
||
|
value expresses how to *decode* the image for display, not how the original
|
||
|
data was *encoded*.
|
||
|
|
||
|
sRGB provides a peg for the PNG standard by defining a viewing environment.
|
||
|
sRGB itself, and earlier TV standards, actually use a more complex transform
|
||
|
(a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is
|
||
|
limited to simple power laws.) By saying that an image for direct display on
|
||
|
an sRGB conformant system should be stored with a gAMA chunk value of 45455
|
||
|
(11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification
|
||
|
makes it possible to derive values for other display systems and
|
||
|
environments.
|
||
|
|
||
|
The Mac value is deduced from the sRGB based on an assumption that the actual
|
||
|
extra viewing correction used in early Mac display systems was implemented as
|
||
|
a power 1.45 lookup table.
|
||
|
|
||
|
Any system where a programmable lookup table is used or where the behavior of
|
||
|
the final display device characteristics can be changed requires system
|
||
|
specific code to obtain the current characteristic. However this can be
|
||
|
difficult and most PNG gamma correction only requires an approximate value.
|
||
|
|
||
|
By default, if png_set_alpha_mode() is not called, libpng assumes that all
|
||
|
values are unencoded, linear, values and that the output device also has a
|
||
|
linear characteristic. This is only very rarely correct - it is invariably
|
||
|
better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the
|
||
|
default if you don't know what the right answer is!
|
||
|
|
||
|
The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS
|
||
|
10.6) which used a correction table to implement a somewhat lower gamma on an
|
||
|
otherwise sRGB system.
|
||
|
|
||
|
Both these values are reserved (not simple gamma values) in order to allow
|
||
|
more precise correction internally in the future.
|
||
|
|
||
|
NOTE: the values can be passed to either the fixed or floating
|
||
|
point APIs, but the floating point API will also accept floating point
|
||
|
values.
|
||
|
|
||
|
The second thing you may need to tell libpng about is how your system handles
|
||
|
alpha channel information. Some, but not all, PNG files contain an alpha
|
||
|
channel. To display these files correctly you need to compose the data onto a
|
||
|
suitable background, as described in the PNG specification.
|
||
|
|
||
|
Libpng only supports composing onto a single color (using png_set_background;
|
||
|
see below). Otherwise you must do the composition yourself and, in this case,
|
||
|
you may need to call png_set_alpha_mode:
|
||
|
|
||
|
#if PNG_LIBPNG_VER >= 10504
|
||
|
png_set_alpha_mode(png_ptr, mode, screen_gamma);
|
||
|
#else
|
||
|
png_set_gamma(png_ptr, screen_gamma, 1.0/screen_gamma);
|
||
|
#endif
|
||
|
|
||
|
The screen_gamma value is the same as the argument to png_set_gamma; however,
|
||
|
how it affects the output depends on the mode. png_set_alpha_mode() sets the
|
||
|
file gamma default to 1/screen_gamma, so normally you don't need to call
|
||
|
png_set_gamma. If you need different defaults call png_set_gamma() before
|
||
|
png_set_alpha_mode() - if you call it after it will override the settings made
|
||
|
by png_set_alpha_mode().
|
||
|
|
||
|
The mode is as follows:
|
||
|
|
||
|
PNG_ALPHA_PNG: The data is encoded according to the PNG
|
||
|
specification. Red, green and blue, or gray, components are
|
||
|
gamma encoded color values and are not premultiplied by the
|
||
|
alpha value. The alpha value is a linear measure of the
|
||
|
contribution of the pixel to the corresponding final output pixel.
|
||
|
|
||
|
You should normally use this format if you intend to perform
|
||
|
color correction on the color values; most, maybe all, color
|
||
|
correction software has no handling for the alpha channel and,
|
||
|
anyway, the math to handle pre-multiplied component values is
|
||
|
unnecessarily complex.
|
||
|
|
||
|
Before you do any arithmetic on the component values you need
|
||
|
to remove the gamma encoding and multiply out the alpha
|
||
|
channel. See the PNG specification for more detail. It is
|
||
|
important to note that when an image with an alpha channel is
|
||
|
scaled, linear encoded, pre-multiplied component values must
|
||
|
be used!
|
||
|
|
||
|
The remaining modes assume you don't need to do any further color correction or
|
||
|
that if you do, your color correction software knows all about alpha (it
|
||
|
probably doesn't!). They 'associate' the alpha with the color information by
|
||
|
storing color channel values that have been scaled by the alpha. The
|
||
|
advantage is that the color channels can be resampled (the image can be
|
||
|
scaled) in this form. The disadvantage is that normal practice is to store
|
||
|
linear, not (gamma) encoded, values and this requires 16-bit channels for
|
||
|
still images rather than the 8-bit channels that are just about sufficient if
|
||
|
gamma encoding is used. In addition all non-transparent pixel values,
|
||
|
including completely opaque ones, must be gamma encoded to produce the final
|
||
|
image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes
|
||
|
described below (the latter being the two common names for associated alpha
|
||
|
color channels). Note that PNG files always contain non-associated color
|
||
|
channels; png_set_alpha_mode() with one of the modes causes the decoder to
|
||
|
convert the pixels to an associated form before returning them to your
|
||
|
application.
|
||
|
|
||
|
Since it is not necessary to perform arithmetic on opaque color values so
|
||
|
long as they are not to be resampled and are in the final color space it is
|
||
|
possible to optimize the handling of alpha by storing the opaque pixels in
|
||
|
the PNG format (adjusted for the output color space) while storing partially
|
||
|
opaque pixels in the standard, linear, format. The accuracy required for
|
||
|
standard alpha composition is relatively low, because the pixels are
|
||
|
isolated, therefore typically the accuracy loss in storing 8-bit linear
|
||
|
values is acceptable. (This is not true if the alpha channel is used to
|
||
|
simulate transparency over large areas - use 16 bits or the PNG mode in
|
||
|
this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is
|
||
|
treated as opaque only if the alpha value is equal to the maximum value.
|
||
|
|
||
|
PNG_ALPHA_STANDARD: The data libpng produces is encoded in the
|
||
|
standard way assumed by most correctly written graphics software.
|
||
|
The gamma encoding will be removed by libpng and the
|
||
|
linear component values will be pre-multiplied by the
|
||
|
alpha channel.
|
||
|
|
||
|
With this format the final image must be re-encoded to
|
||
|
match the display gamma before the image is displayed.
|
||
|
If your system doesn't do that, yet still seems to
|
||
|
perform arithmetic on the pixels without decoding them,
|
||
|
it is broken - check out the modes below.
|
||
|
|
||
|
With PNG_ALPHA_STANDARD libpng always produces linear
|
||
|
component values, whatever screen_gamma you supply. The
|
||
|
screen_gamma value is, however, used as a default for
|
||
|
the file gamma if the PNG file has no gamma information.
|
||
|
|
||
|
If you call png_set_gamma() after png_set_alpha_mode() you
|
||
|
will override the linear encoding. Instead the
|
||
|
pre-multiplied pixel values will be gamma encoded but
|
||
|
the alpha channel will still be linear. This may
|
||
|
actually match the requirements of some broken software,
|
||
|
but it is unlikely.
|
||
|
|
||
|
While linear 8-bit data is often used it has
|
||
|
insufficient precision for any image with a reasonable
|
||
|
dynamic range. To avoid problems, and if your software
|
||
|
supports it, use png_set_expand_16() to force all
|
||
|
components to 16 bits.
|
||
|
|
||
|
PNG_ALPHA_OPTIMIZED: This mode is the same as PNG_ALPHA_STANDARD
|
||
|
except that completely opaque pixels are gamma encoded according to
|
||
|
the screen_gamma value. Pixels with alpha less than 1.0
|
||
|
will still have linear components.
|
||
|
|
||
|
Use this format if you have control over your
|
||
|
compositing software and so don't do other arithmetic
|
||
|
(such as scaling) on the data you get from libpng. Your
|
||
|
compositing software can simply copy opaque pixels to
|
||
|
the output but still has linear values for the
|
||
|
non-opaque pixels.
|
||
|
|
||
|
In normal compositing, where the alpha channel encodes
|
||
|
partial pixel coverage (as opposed to broad area
|
||
|
translucency), the inaccuracies of the 8-bit
|
||
|
representation of non-opaque pixels are irrelevant.
|
||
|
|
||
|
You can also try this format if your software is broken;
|
||
|
it might look better.
|
||
|
|
||
|
PNG_ALPHA_BROKEN: This is PNG_ALPHA_STANDARD; however, all component
|
||
|
values, including the alpha channel are gamma encoded. This is
|
||
|
broken because, in practice, no implementation that uses this choice
|
||
|
correctly undoes the encoding before handling alpha composition. Use this
|
||
|
choice only if other serious errors in the software or hardware you use
|
||
|
mandate it. In most cases of broken software or hardware the bug in the
|
||
|
final display manifests as a subtle halo around composited parts of the
|
||
|
image. You may not even perceive this as a halo; the composited part of
|
||
|
the image may simply appear separate from the background, as though it had
|
||
|
been cut out of paper and pasted on afterward.
|
||
|
|
||
|
If you don't have to deal with bugs in software or hardware, or if you can fix
|
||
|
them, there are three recommended ways of using png_set_alpha_mode():
|
||
|
|
||
|
png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG,
|
||
|
screen_gamma);
|
||
|
|
||
|
You can do color correction on the result (libpng does not currently
|
||
|
support color correction internally). When you handle the alpha channel
|
||
|
you need to undo the gamma encoding and multiply out the alpha.
|
||
|
|
||
|
png_set_alpha_mode(png_ptr, PNG_ALPHA_STANDARD,
|
||
|
screen_gamma);
|
||
|
png_set_expand_16(png_ptr);
|
||
|
|
||
|
If you are using the high level interface, don't call png_set_expand_16();
|
||
|
instead pass PNG_TRANSFORM_EXPAND_16 to the interface.
|
||
|
|
||
|
With this mode you can't do color correction, but you can do arithmetic,
|
||
|
including composition and scaling, on the data without further processing.
|
||
|
|
||
|
png_set_alpha_mode(png_ptr, PNG_ALPHA_OPTIMIZED,
|
||
|
screen_gamma);
|
||
|
|
||
|
You can avoid the expansion to 16-bit components with this mode, but you
|
||
|
lose the ability to scale the image or perform other linear arithmetic.
|
||
|
All you can do is compose the result onto a matching output. Since this
|
||
|
mode is libpng-specific you also need to write your own composition
|
||
|
software.
|
||
|
|
||
|
The following are examples of calls to png_set_alpha_mode to achieve the
|
||
|
required overall gamma correction and, where necessary, alpha
|
||
|
premultiplication.
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
|
||
|
|
||
|
This is the default libpng handling of the alpha channel - it is not
|
||
|
pre-multiplied into the color components. In addition the call states
|
||
|
that the output is for a sRGB system and causes all PNG files without gAMA
|
||
|
chunks to be assumed to be encoded using sRGB.
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
|
||
|
|
||
|
In this case the output is assumed to be something like an sRGB conformant
|
||
|
display preceeded by a power-law lookup table of power 1.45. This is how
|
||
|
early Mac systems behaved.
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR);
|
||
|
|
||
|
This is the classic Jim Blinn approach and will work in academic
|
||
|
environments where everything is done by the book. It has the shortcoming
|
||
|
of assuming that input PNG data with no gamma information is linear - this
|
||
|
is unlikely to be correct unless the PNG files where generated locally.
|
||
|
Most of the time the output precision will be so low as to show
|
||
|
significant banding in dark areas of the image.
|
||
|
|
||
|
png_set_expand_16(pp);
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB);
|
||
|
|
||
|
This is a somewhat more realistic Jim Blinn inspired approach. PNG files
|
||
|
are assumed to have the sRGB encoding if not marked with a gamma value and
|
||
|
the output is always 16 bits per component. This permits accurate scaling
|
||
|
and processing of the data. If you know that your input PNG files were
|
||
|
generated locally you might need to replace PNG_DEFAULT_sRGB with the
|
||
|
correct value for your system.
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB);
|
||
|
|
||
|
If you just need to composite the PNG image onto an existing background
|
||
|
and if you control the code that does this you can use the optimization
|
||
|
setting. In this case you just copy completely opaque pixels to the
|
||
|
output. For pixels that are not completely transparent (you just skip
|
||
|
those) you do the composition math using png_composite or png_composite_16
|
||
|
below then encode the resultant 8-bit or 16-bit values to match the output
|
||
|
encoding.
|
||
|
|
||
|
Other cases
|
||
|
|
||
|
If neither the PNG nor the standard linear encoding work for you because
|
||
|
of the software or hardware you use then you have a big problem. The PNG
|
||
|
case will probably result in halos around the image. The linear encoding
|
||
|
will probably result in a washed out, too bright, image (it's actually too
|
||
|
contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably
|
||
|
substantially reduce the halos. Alternatively try:
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB);
|
||
|
|
||
|
This option will also reduce the halos, but there will be slight dark
|
||
|
halos round the opaque parts of the image where the background is light.
|
||
|
In the OPTIMIZED mode the halos will be light halos where the background
|
||
|
is dark. Take your pick - the halos are unavoidable unless you can get
|
||
|
your hardware/software fixed! (The OPTIMIZED approach is slightly
|
||
|
faster.)
|
||
|
|
||
|
When the default gamma of PNG files doesn't match the output gamma.
|
||
|
If you have PNG files with no gamma information png_set_alpha_mode allows
|
||
|
you to provide a default gamma, but it also sets the ouput gamma to the
|
||
|
matching value. If you know your PNG files have a gamma that doesn't
|
||
|
match the output you can take advantage of the fact that
|
||
|
png_set_alpha_mode always sets the output gamma but only sets the PNG
|
||
|
default if it is not already set:
|
||
|
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB);
|
||
|
png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC);
|
||
|
|
||
|
The first call sets both the default and the output gamma values, the
|
||
|
second call overrides the output gamma without changing the default. This
|
||
|
is easier than achieving the same effect with png_set_gamma. You must use
|
||
|
PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will
|
||
|
fire if more than one call to png_set_alpha_mode and png_set_background is
|
||
|
made in the same read operation, however multiple calls with PNG_ALPHA_PNG
|
||
|
are ignored.
|
||
|
|
||
|
If you don't need, or can't handle, the alpha channel you can call
|
||
|
png_set_background() to remove it by compositing against a fixed color. Don't
|
||
|
call png_set_strip_alpha() to do this - it will leave spurious pixel values in
|
||
|
transparent parts of this image.
|
||
|
|
||
|
png_set_background(png_ptr, &background_color,
|
||
|
PNG_BACKGROUND_GAMMA_SCREEN, 0, 1);
|
||
|
|
||
|
The background_color is an RGB or grayscale value according to the data format
|
||
|
libpng will produce for you. Because you don't yet know the format of the PNG
|
||
|
file, if you call png_set_background at this point you must arrange for the
|
||
|
format produced by libpng to always have 8-bit or 16-bit components and then
|
||
|
store the color as an 8-bit or 16-bit color as appropriate. The color contains
|
||
|
separate gray and RGB component values, so you can let libpng produce gray or
|
||
|
RGB output according to the input format, but low bit depth grayscale images
|
||
|
must always be converted to at least 8-bit format. (Even though low bit depth
|
||
|
grayscale images can't have an alpha channel they can have a transparent
|
||
|
color!)
|
||
|
|
||
|
You set the transforms you need later, either as flags to the high level
|
||
|
interface or libpng API calls for the low level interface. For reference the
|
||
|
settings and API calls required are:
|
||
|
|
||
|
8-bit values:
|
||
|
PNG_TRANSFORM_SCALE_16 | PNG_EXPAND
|
||
|
png_set_expand(png_ptr); png_set_scale_16(png_ptr);
|
||
|
|
||
|
If you must get exactly the same inaccurate results
|
||
|
produced by default in versions prior to libpng-1.5.4,
|
||
|
use PNG_TRANSFORM_STRIP_16 and png_set_strip_16(png_ptr)
|
||
|
instead.
|
||
|
|
||
|
16-bit values:
|
||
|
PNG_TRANSFORM_EXPAND_16
|
||
|
png_set_expand_16(png_ptr);
|
||
|
|
||
|
In either case palette image data will be expanded to RGB. If you just want
|
||
|
color data you can add PNG_TRANSFORM_GRAY_TO_RGB or png_set_gray_to_rgb(png_ptr)
|
||
|
to the list.
|
||
|
|
||
|
Calling png_set_background before the PNG file header is read will not work
|
||
|
prior to libpng-1.5.4. Because the failure may result in unexpected warnings or
|
||
|
errors it is therefore much safer to call png_set_background after the head has
|
||
|
been read. Unfortunately this means that prior to libpng-1.5.4 it cannot be
|
||
|
used with the high level interface.
|
||
|
|
||
|
The high-level read interface
|
||
|
|
||
|
At this point there are two ways to proceed; through the high-level
|
||
|
read interface, or through a sequence of low-level read operations.
|
||
|
You can use the high-level interface if (a) you are willing to read
|
||
|
the entire image into memory, and (b) the input transformations
|
||
|
you want to do are limited to the following set:
|
||
|
|
||
|
PNG_TRANSFORM_IDENTITY No transformation
|
||
|
PNG_TRANSFORM_SCALE_16 Strip 16-bit samples to
|
||
|
8-bit accurately
|
||
|
PNG_TRANSFORM_STRIP_16 Chop 16-bit samples to
|
||
|
8-bit less accurately
|
||
|
PNG_TRANSFORM_STRIP_ALPHA Discard the alpha channel
|
||
|
PNG_TRANSFORM_PACKING Expand 1, 2 and 4-bit
|
||
|
samples to bytes
|
||
|
PNG_TRANSFORM_PACKSWAP Change order of packed
|
||
|
pixels to LSB first
|
||
|
PNG_TRANSFORM_EXPAND Perform set_expand()
|
||
|
PNG_TRANSFORM_INVERT_MONO Invert monochrome images
|
||
|
PNG_TRANSFORM_SHIFT Normalize pixels to the
|
||
|
sBIT depth
|
||
|
PNG_TRANSFORM_BGR Flip RGB to BGR, RGBA
|
||
|
to BGRA
|
||
|
PNG_TRANSFORM_SWAP_ALPHA Flip RGBA to ARGB or GA
|
||
|
to AG
|
||
|
PNG_TRANSFORM_INVERT_ALPHA Change alpha from opacity
|
||
|
to transparency
|
||
|
PNG_TRANSFORM_SWAP_ENDIAN Byte-swap 16-bit samples
|
||
|
PNG_TRANSFORM_GRAY_TO_RGB Expand grayscale samples
|
||
|
to RGB (or GA to RGBA)
|
||
|
PNG_TRANSFORM_EXPAND_16 Expand samples to 16 bits
|
||
|
|
||
|
(This excludes setting a background color, doing gamma transformation,
|
||
|
quantizing, and setting filler.) If this is the case, simply do this:
|
||
|
|
||
|
png_read_png(png_ptr, info_ptr, png_transforms, NULL)
|
||
|
|
||
|
where png_transforms is an integer containing the bitwise OR of some
|
||
|
set of transformation flags. This call is equivalent to png_read_info(),
|
||
|
followed the set of transformations indicated by the transform mask,
|
||
|
then png_read_image(), and finally png_read_end().
|
||
|
|
||
|
(The final parameter of this call is not yet used. Someday it might point
|
||
|
to transformation parameters required by some future input transform.)
|
||
|
|
||
|
You must use png_transforms and not call any png_set_transform() functions
|
||
|
when you use png_read_png().
|
||
|
|
||
|
After you have called png_read_png(), you can retrieve the image data
|
||
|
with
|
||
|
|
||
|
row_pointers = png_get_rows(png_ptr, info_ptr);
|
||
|
|
||
|
where row_pointers is an array of pointers to the pixel data for each row:
|
||
|
|
||
|
png_bytep row_pointers[height];
|
||
|
|
||
|
If you know your image size and pixel size ahead of time, you can allocate
|
||
|
row_pointers prior to calling png_read_png() with
|
||
|
|
||
|
if (height > PNG_UINT_32_MAX/(sizeof (png_byte)))
|
||
|
png_error (png_ptr,
|
||
|
"Image is too tall to process in memory");
|
||
|
|
||
|
if (width > PNG_UINT_32_MAX/pixel_size)
|
||
|
png_error (png_ptr,
|
||
|
"Image is too wide to process in memory");
|
||
|
|
||
|
row_pointers = png_malloc(png_ptr,
|
||
|
height*(sizeof (png_bytep)));
|
||
|
|
||
|
for (int i=0; i<height, i++)
|
||
|
row_pointers[i]=NULL; /* security precaution */
|
||
|
|
||
|
for (int i=0; i<height, i++)
|
||
|
row_pointers[i]=png_malloc(png_ptr,
|
||
|
width*pixel_size);
|
||
|
|
||
|
png_set_rows(png_ptr, info_ptr, &row_pointers);
|
||
|
|
||
|
Alternatively you could allocate your image in one big block and define
|
||
|
row_pointers[i] to point into the proper places in your block.
|
||
|
|
||
|
If you use png_set_rows(), the application is responsible for freeing
|
||
|
row_pointers (and row_pointers[i], if they were separately allocated).
|
||
|
|
||
|
If you don't allocate row_pointers ahead of time, png_read_png() will
|
||
|
do it, and it'll be free'ed by libpng when you call png_destroy_*().
|
||
|
|
||
|
The low-level read interface
|
||
|
|
||
|
If you are going the low-level route, you are now ready to read all
|
||
|
the file information up to the actual image data. You do this with a
|
||
|
call to png_read_info().
|
||
|
|
||
|
png_read_info(png_ptr, info_ptr);
|
||
|
|
||
|
This will process all chunks up to but not including the image data.
|
||
|
|
||
|
This also copies some of the data from the PNG file into the decode structure
|
||
|
for use in later transformations. Important information copied in is:
|
||
|
|
||
|
1) The PNG file gamma from the gAMA chunk. This overwrites the default value
|
||
|
provided by an earlier call to png_set_gamma or png_set_alpha_mode.
|
||
|
|
||
|
2) Prior to libpng-1.5.4 the background color from a bKGd chunk. This
|
||
|
damages the information provided by an earlier call to png_set_background
|
||
|
resulting in unexpected behavior. Libpng-1.5.4 no longer does this.
|
||
|
|
||
|
3) The number of significant bits in each component value. Libpng uses this to
|
||
|
optimize gamma handling by reducing the internal lookup table sizes.
|
||
|
|
||
|
4) The transparent color information from a tRNS chunk. This can be modified by
|
||
|
a later call to png_set_tRNS.
|
||
|
|
||
|
Querying the info structure
|
||
|
|
||
|
Functions are used to get the information from the info_ptr once it
|
||
|
has been read. Note that these fields may not be completely filled
|
||
|
in until png_read_end() has read the chunk data following the image.
|
||
|
|
||
|
png_get_IHDR(png_ptr, info_ptr, &width, &height,
|
||
|
&bit_depth, &color_type, &interlace_type,
|
||
|
&compression_type, &filter_method);
|
||
|
|
||
|
width - holds the width of the image
|
||
|
in pixels (up to 2^31).
|
||
|
|
||
|
height - holds the height of the image
|
||
|
in pixels (up to 2^31).
|
||
|
|
||
|
bit_depth - holds the bit depth of one of the
|
||
|
image channels. (valid values are
|
||
|
1, 2, 4, 8, 16 and depend also on
|
||
|
the color_type. See also
|
||
|
significant bits (sBIT) below).
|
||
|
|
||
|
color_type - describes which color/alpha channels
|
||
|
are present.
|
||
|
PNG_COLOR_TYPE_GRAY
|
||
|
(bit depths 1, 2, 4, 8, 16)
|
||
|
PNG_COLOR_TYPE_GRAY_ALPHA
|
||
|
(bit depths 8, 16)
|
||
|
PNG_COLOR_TYPE_PALETTE
|
||
|
(bit depths 1, 2, 4, 8)
|
||
|
PNG_COLOR_TYPE_RGB
|
||
|
(bit_depths 8, 16)
|
||
|
PNG_COLOR_TYPE_RGB_ALPHA
|
||
|
(bit_depths 8, 16)
|
||
|
|
||
|
PNG_COLOR_MASK_PALETTE
|
||
|
PNG_COLOR_MASK_COLOR
|
||
|
PNG_COLOR_MASK_ALPHA
|
||
|
|
||
|
interlace_type - (PNG_INTERLACE_NONE or
|
||
|
PNG_INTERLACE_ADAM7)
|
||
|
|
||
|
compression_type - (must be PNG_COMPRESSION_TYPE_BASE
|
||
|
for PNG 1.0)
|
||
|