Everyone is welcome to contribute to the development of OptiPNG. This document provides useful information to the potential contributors, but many pieces of advice given here may be followed by any programmer.
Priority has been given to the following quality factors, in decreasing order of importance:
README
file for contact info.)
png_set_read_fn()
,
png_set_write_fn()
to a customized function
optipng_read_write_data()
that gathers the necessary statistics and writes the chunk
data to a file only in the final optimization step.
Furthermore, the code is ostensibly not polluted with pre-ANSI portability hacks like:
#if defined(HAVE_STRING_H) || defined(STDC) #include <string.h> #endifnor with hacks that depend on the availability of various supporting library features:
#if PNG_FLOATING_POINT_SUPPORTED /* implement a certain application feature using the libpng * floating point routines */ #elif PNG_FIXED_POINT_SUPPORTED /* implement the same feature using the libpng fixed point * routines */ #else /* implement the same feature using hand-crafted code, or * do not implement it at all, crippling the application */ #endifBy using portability hacks, the build process is easier. However, two pieces of code that are expected to do the same thing are a source of problems, especially when the person who modifies them is not completely aware of the situation. It is much less painful to simply require the necessary library features:
#ifndef PNG_FIXED_POINT_SUPPORTED #error This program requires libpng with fixed point processing #endifThe disadvantage of the latter approach is possibly a more inconvenient build process. The supporting library/libraries may have to be rebuilt and linked statically. This is a much smaller problem, though, and it is better to have a bloat of a few hundred kilobytes in the executable, instead of having a crippled program, or a program of lower quality.
The program usage is typical to the category of command-line applications. There are some peculiarities, however, which are enumerated below.
optipng input1.png input2.png input3.pngThis behavior is similar to that of
compress
,
gzip
and other Unix utilities. At the user's
option, the input is preserved in backup files.
This approach is more natural to batch processing. It is
easy, for example, to run OptiPNG in a WWW directory and
optimize all the PNG files, leaving everything else in
place.
Another advantage resides in a higher processing speed, when
the input file is already optimized. Instead of being copied
to an identical output file, it is just left in place.
optipng input.png output.pngThis may be more useful for experimentation purposes, but it is more onerous for the regular user. Running the program in batch mode is still possible, but that would require an alternate mode, such as:
optipng -multi input1.png input2.png input3.pngThe disadvantages of this approach are the inconsistency between the two modes, and the difficulty to run the optimization in-place.
'-'
and are
case-insensitive. Single-letter options cannot be contracted;
e.g.
optipng -k -qcannot be contracted to
optipng -kqThis restriction eliminates the need to use a double dash when specifying a multi-character option, e.g.
-quiet
and --quiet
are equivalent. Double-dashed
option specification is used mainly as a compatibility hack
in programs that used (and continue to use) option contraction.
Even if newer programs use double-dashed option specification,
with or without allowing contractions, this is not necessarily
good style. Still, multiple dashes are accepted by OptiPNG.
(On a side note: while case sensitivity is useful in C, mainly to appease the name space pollution problems incurred by macro definitions, it is a mixed blessing in the Unix file system. If two file names are distinguished only by one or more capital letters, these names still say and mean the same thing. No good directory organization should have two such files in the same directory. From this point of view, the Windows approach where the letter case is retained, but the access is case-independent, is better. At least we are lucky that email addresses are case-insensitive...)
A regular PNG decoder may choose to stop the decoding process whenever it detects integrity problems within the input. On the other hand, at the user's option, OptiPNG can ignore non-fatal errors and, in some particular instances, replace the invalid input with corrected output. The correction is performed based on simple, automatic decisions.
It is essential for this program to run as fast as possible. Here are some advices on how to adjust the compiler parameters in order to obtain the best speed results, and still to maintain a small size of the executable.
"gcc -O3"
. Loop unrolling
may also be enabled. Most of the time is spent by this code, and
it is important to optimize it to the maximum extent possible.
"gcc -O2"
may give better results than
"gcc -O3"
in some circumstances.
"gcc -O2"
. The speed of the OptiPNG program
is determined by the speed of the compression and decompression
routines (zlib), and the amount of time spent doing other tasks
is insignificant, so this code needs not be inlined. Besides,
too much inlining may increase the chance of cache penalty,
with a negative effect on program execution.
PNG_NO_XXX
macros
when compiling libpng. Here are a few examples:
#define PNG_NO_FLOATING_POINT_SUPPORTED // not needed #define PNG_NO_MNG_FEATURES // no MNG support #define PNG_NO_SETJMP_SUPPORTED // see "Exception handling" #define PNG_NO_READ_TRANSFORMS #define PNG_NO_WRITE_TRANSFORMS
It is unfortunate that C does not provide an exception handling system, and the standard alternatives (returned error codes or the setjmp mechanism) are many times unsatisfactory. Exception handling is exceptionally useful to implementing recovery.
OptiPNG uses
cexcept,
an ultra-thin abstraction layer that
implements structured exception handling on top of the setjmp
mechanism. Essentially, this exception handling system
defines macros such as Throw
, Try
and
Catch
, which are used by
OptiPNG. The multi-layered approach to throwing, catching and
re-throwing exceptions allows the program to continue with the
next file, even if fatal errors occur inside libpng. This allows
the source code to be much cleaner without a significant
performance overhead.
There are many issues pertaining to how the cexcept macros work,
and they can be read inside the "cexcept.h"
file.
If OptiPNG or portions of it are ported to C++, it is strongly
recommended to use the native C++ exception handling instead.