OptiPNG - Design decisions and rationale

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.

Quality

Priority has been given to the following quality factors, in decreasing order of importance:

  1. Correctness
    The most important goal is to produce PNG files that comply to the PNG specification. The code is written with great care, and it is tested extensively. However, if you do find defects, please report them to the author. (See the README file for contact info.)
  2. Efficiency
    OptiPNG is designed to be fast. It needs to run a suite of brute-force trials, and the biggest amount of time is spent during zlib compression and decompression, and during I/O. This amount of time is reduced to a minimum:
  3. Readability and maintainability
    ["Premature optimization is the root of all evil." - D. E. Knuth]
    OptiPNG is not a simple application, even though the code is clear and well commented. It may be possible to optimize the code even more, and sacrifice some readability, by inlining functions manually, eliminating the overhead of the structured exception handling, etc. There is a strong word of caution against this, because the time spent in OptiPNG is minimal, and such gain is insignificant. No visible extra performance will be achieved, and readability will have much to suffer.

    Furthermore, the code is ostensibly not polluted with pre-ANSI portability hacks like:

    #if defined(HAVE_STRING_H) || defined(STDC)
    #include <string.h>
    #endif
    
    nor 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
        */
    #endif
    
    By 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
    #endif
    
    The 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.
  4. Functionality
    OptiPNG serves its primary goal: to optimize the size of the given PNG files. Additional features, such as error recovery, or support for external image formats, have been implemented. When adding any new extra feature, it is important to preserve the level of other quality factors -- especially of those with a higher priority.
  5. Portability

Usage

The program usage is typical to the category of command-line applications. There are some peculiarities, however, which are enumerated below.

File recovery

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.

Compiler optimizations

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.

Exception handling

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.


Copyright © 2003-2006 Cosmin Truţa. Permission to distribute freely.
Appeared: 23 Feb 2003.
Last updated: 5 Aug 2006.