123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634 |
- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <meta name="Author" content="Cosmin Truţa">
- <title>A guide to PNG optimization</title>
- </head>
- <body>
- <h2>A guide to PNG optimization</h2>
- <h3>1. Background</h3>
- <h4>1.1 The PNG file format</h4>
- <p>
- The <a href="http://www.libpng.org/pub/png/">Portable Network Graphics</a>
- (<b><i>PNG</i></b>) is a format for storing compressed raster graphics. The
- compression engine is based on the <b><i>Deflate</i></b> method
- [<a href="http://www.ietf.org/rfc/rfc1951">RFC1951</a>],
- designed by
- <a href="http://www.pkware.com/">PKWare</a>
- and originally used in <b>PKZIP</b>.
- </p>
- <p>
- The PNG format is defined by the
- <a href="http://www.libpng.org/pub/png/spec/">PNG Specification</a>.
- This specification was developed by an ad-hoc group named the
- <a href="http://www.libpng.org/pub/png/">PNG Development Group</a>, and it is
- both an International Standard (published under the formal name
- ISO/IEC 15948) and a W3C Recommendation.
- </p>
- <p>
- PNG was initially intended as a superior, patent-free replacement of GIF. The
- final outcome is a modern, extensible, reliable image format, capable to handle
- an impressive number of image types (from 1-bit black-and-white images up to
- 48-bit RGB images with a full 16-bit alpha channel), and geared by a
- significantly stronger lossless compression engine (typically 5-25% better than
- GIF).
- </p>
- <p>
- Unlike other lossless compression schemes, PNG compression does not depend
- solely on the statistics of the input, but it may vary within wide limits,
- depending on the compressor's implementation. A good PNG encoder must be
- able to take informed decisions about the factors that affect the size of the
- output. The purpose of this article is to provide information about these
- factors, and to give advice on implementing efficient PNG encoders.
- </p>
- <h4>1.2 The PNG compression</h4>
- <p>
- The PNG compression works in a pipeline manner.
- </p>
- <p>
- In the first stage, the image pixels are passed through a lossless arithmetic
- transformation named <b><i>delta filtering</i></b>, or simply
- <b><i>filtering</i></b>, and sent further as a (filtered) byte sequence.
- Filtering does not compress or otherwise reduce the size of the data, but it
- makes the data more compressible.
- </p>
- <p>
- In the second stage, the filtered byte sequence is passed through the
- Ziv-Lempel algorithm (LZ77), producing LZ77 codes that are further compressed
- by the Huffman algorithm in the third and final stage. The combination of the
- last two stages is referred to as the <b><i>Deflate compression</i></b>, a
- widely-used, patent-free algorithm for universal, lossless data compression.
- The maximum size of the LZ77 sliding window in Deflate is 32768 bytes, and the
- LZ77 matches can be between 3 and 258 bytes long.
- </p>
- <p>
- A complete description of the PNG compression is beyond the scope of this
- guide. The PNG Specification describes the format completely, and provides
- a complete list of references to the underlying technologies.
- </p>
- <h3>2. Factors that affect the PNG file size</h3>
- <div>
- Like any other compression scheme, PNG compression depends on the statistics
- of the input data. In addition, it depends on the following PNG-specific
- parameters:
- </div>
- <ol>
- <li>
- The PNG image type
- </li>
- <li>
- The PNG delta filters
- </li>
- <li>
- The strategy of searching LZ77 matches
- </li>
- <li>
- The size of the Huffman buffers inside the Deflate encoder
- </li>
- </ol>
- <p>
- Depending on how these parameters are chosen by the implementation, PNG
- compression may vary within wide limits. The process of selecting the best
- configuration is computationally infeasible, but heuristics to select a
- satisfactory configuration are available. The problem of improving these
- heuristics constitutes an interesting subject for research.
- </p>
- <h4>2.1 The PNG image type</h4>
- <p>
- The type of a PNG image is defined in the <b><code>IHDR</code></b> image
- header. The image has a certain bit depth, up to 16 bits per sample, and a
- certain color type, from Grayscale to RGB+Alpha. If two PNG files of different
- types represent exactly the same image, each file can be regarded as a lossless
- transformation of the other. A lossless transformation can reduce the
- <i>uncompressed</i> stream, and such a transformation is named <b><i>image
- reduction</i></b>. In most cases, image reductions are capable of reducing the
- <i>compressed</i> stream (which is, in fact, our interest), as an indirect
- effect of reducing the size of the compressor's input.
- </p>
- <div>
- The possible image reductions are:
- </div>
- <ul>
- <li>
- <i>Bit depth reduction</i>
- <br>
- The bit depth can be reduced to a minimum value that is acceptable for all
- samples. For example, if all sample values in a 16-bit image have the form
- (256+1)*<i>n</i>, (e.g. #0000, #2323, #FFFF), then the bit depth can be
- reduced to 8, and the new sample values will become <i>n</i>, (e.g. #00, #23,
- #FF).
- </li>
- <li>
- <i>Color type reduction</i>
- <br>
- - If an RGB image has 256 distinct colors or less, it can be reencoded as a
- Palette image.
- <br>
- - If an RGB or Palette image has only gray pixels, it can be reencoded as
- Grayscale.
- <br>
- A color type reduction can also enable a bit depth reduction.
- </li>
- <li>
- <i>Color palette reduction</i>
- <br>
- If the color palette contains redundant entries (i.e. duplicate entries that
- indicate the same RGB value) or sterile entries (i.e. entries that do not
- have a correspondent in the raw pixel data), these entries can be removed.
- <br>
- A color palette reduction can also enable a bit depth reduction.
- </li>
- <li>
- <i>Alpha channel reduction</i>
- <br>
- If all pixels in a Grayscale+Alpha or an RGB+Alpha image are fully opaque
- (i.e. all alpha components are equal to 2^<sup>bitdepth</sup>-1), or if the
- transparency information can be stored entirely in a (much cheaper)
- <b><code>tRNS</code></b> chunk, the alpha channel can be stripped.
- </li>
- </ul>
- <p>
- There are, however, a few cases when some image type reductions do not
- necessarily lead to the reduction of the compressed stream. The
- <a href="http://www.cs.toronto.edu/~cosmin/pngtech/">PNG-Tech</a> site contains
- experimental analyses of these possibilities; for example, see the article
- <a href="8bpp.html">8 bits per pixel in paletted images</a>.
- </p>
- <p>
- Interlacing, useful for a faster, progressive rendering, is another component
- of the PNG image type that affects compression. In an interlaced stream, the
- samples corresponding to neighboring pixels are stored far away, hence the data
- in it is less correlated and less compressible. Unlike JPEG, where interlacing
- may improve the compression slightly, the PNG interlacing degrades the
- compression significantly.
- </p>
- <h4>2.2 The PNG delta filters</h4>
- <p>
- The role of filtering can be illustrated in the following example. Assume the
- sequence 2, 3, 4, 5, 6, 7, 8, 9. Although it has much redundancy, the sequence
- is not compressible by a Ziv-Lempel compressor, nor by a Huffman compressor.
- However, if one makes a simple and reversible transformation, replacing each
- value with the numerical difference between it and the value to its left, the
- sequence becomes 2, 1, 1, 1, 1, 1, 1, 1, which is highly compressible.
- </p>
- <p>
- The PNG format employs five types of filters: <b><i>None</i></b>,
- <b><i>Left</i></b>, <b><i>Up</i></b>, <b><i>Average</i></b>, and
- <b><i>Paeth</i></b>. The first filter leaves the original data intact, and the
- other four are subtracting from each pixel a value that involves the
- neighbor pixels from the left, up, and/or the upper left.
- </p>
- <p>
- A certain filter is assigned to each row, and is applied to all pixels from
- that row. Therefore, an image can be delta-filtered in a huge number of
- possible configurations (5 ^ <sup><i>height</i></sup>), and each configuration
- leads to a different compressed output. Two different filter configurations may
- make a difference in the compressed file size by a couple of factors, so a
- careful choice of filters is of paramount importance.
- </p>
- <p>
- It is possible to apply a single filter to all rows, or to apply different
- filters to different rows. In the former case, the filtering process is
- <b><i>fixed</i></b>; in the latter, it is <b><i>adaptive</i></b>.
- </p>
- <div>
- While an exhaustive search is unfeasible, the PNG Specification suggests a
- heuristic filtering strategy:
- </div>
- <ul>
- <li>
- If the image type is Palette, or the bit depth is smaller than 8, then
- do not filter the image (i.e. use fixed filtering, with the filter
- <i>None</i>).
- </li>
- <li>
- (The other case) If the image type is Grayscale or RGB (with or without
- Alpha), and the bit depth is not smaller than 8, then use adaptive filtering
- as follows: <i>independently for each row</i>, apply all five filters and
- select the filter that produces the smallest sum of absolute values per row.
- </li>
- </ul>
- <p>
- Cases where the above heuristics are less than optimal are shown on the
- <a href="http://www.cs.toronto.edu/~cosmin/pngtech/">PNG-Tech</a>
- site; for example, see
- <a href="better-filtering.html">Brute-force vs. heuristic filtering</a>.
- </p>
- <h4>2.3 The strategy of searching LZ77 matches</h4>
- <p>
- The Ziv-Lempel algorithm works under the assumption that contiguous sequences
- appear repeatedly in the input stream. If the sequence to be encoded matches
- one or more sequences already present in the sliding history window, the
- encoder sends a LZ77 pair (<i>distance</i>, <i>length</i>) that points to the
- <i>closest</i> match. In most LZ77 incarnations, including Deflate, smaller
- distance codes are encoded more concisely.
- </p>
- <p>
- In Deflate, in particular, the regular (non-matched) symbols, and the match
- lengths, are sent to the same Huffman coder, while the match distances are sent
- to a separate Huffman coder. If the LZ77 matches fall between the accepted
- boundaries (i.e. they are not shorter than 3 and not longer than 258), a greedy
- strategy will accept them as a replacement for the symbols to which they
- correspond.
- </p>
- <p>
- The greedy strategy is preferable when compressing text files, or many types of
- binary files, but it may be suboptimal when compressing filtered data, such as
- the byte strings that come from a PNG filter. Filtered data consist mostly of
- small values with a pseudo-random distribution. Therefore, in certain
- situations, it may be desirable to favor the encoding of individual symbols,
- even if matches that may replace these symbols exist.
- </p>
- <p>
- The
- <a href="http://www.zlib.org/">zlib Reference Library</a>
- is a reference implementation of Deflate, which is further used by the
- <a href="http://www.libpng.org/pub/png/libpng.html">PNG Reference Library</a>.
- By default, <b>zlib</b> selects the greedy strategy, but the user is able to
- specify his or her custom preference via the <code>strategy</code> parameter.
- This parameter can take one of the following values:
- <br>
- - <code>Z_DEFAULT_STRATEGY = 0</code>, the default greedy search strategy.
- <br>
- - <code>Z_FILTERED = 1</code>, a strategy in which the matches are accepted
- only if their length is 6 or bigger.
- <br>
- - <code>Z_HUFFMAN_ONLY = 2</code>, a fast strategy in which the Ziv-Lempel
- algorithm is entirely bypassed, and all the symbols from the input are encoded
- directly by the Huffman coder.
- <br>
- - <code>Z_RLE = 3</code> (appeared in the <b>zlib-1.2.x</b> series), a fast
- strategy in which the LZ77 algorithm is essentially reduced to the Run-Length
- Encoding algorithm. In other words, the matches are accepted only if their
- distance is 1. For example, the 10-symbol sequence "<code>aaaaaaaaaa</code>"
- can be LZ77-encoded as
- ['<code>a</code>', (<i>distance</i>=1, <i>length</i>=9)];
- by removing <i>distance</i>=1 from the picture, this encoding can be regarded
- as a peculiar run-length encoding (which differs from the classic RLE by using
- <i>length</i>=9 instead of <i>count</i>=10).
- <br>
- The <code>strategy</code> parameter affects only the compression ratio. It does
- not affect the correctness of the compressed output, even if it is set to an
- inappropriate value.
- </p>
- <p>
- It was experimentally observed that the LZ77 search is occasionally capable of
- producing smaller PNGs if it is less exhaustive. The reason behind this act
- resides in the same category of "strategic searches" discussed here.
- Unfortunately, there is no known method of anticipating which search level
- (from the fastest and the least exhaustive, to the slowest and the most
- exhaustive) is better, other than assuming "the most exhaustive is better in
- most cases".
- </p>
- <p>
- Unfortunately, even a "filtered" strategy does not always produce better
- results than a "greedy" strategy on filtered input, and the only known method
- to obtain the best combination is by multiple trials. Experiments and
- measurements can, again, be found on the
- <a href="http://www.cs.toronto.edu/~cosmin/pngtech/">PNG-Tech</a>
- site; for example, see the original
- <a href="z_rle.html">Z_RLE strategy proposal</a>.
- </p>
- <h4>2.4 The size of Huffman buffers</h4>
- <p>
- As mentioned earlier, the entropy encoder inside the Deflate method is the
- static Huffman algorithm. The output of LZ77 is fed into a buffer which is
- occasionally flushed by sending a static Huffman tree followed by all the
- Huffman codes, to the output of Deflate. After this, both the buffer and the
- Huffman tree are reset, waiting for the subsequent LZ77 codes to come and
- refill the buffer.
- </p>
- <blockquote>
- The Deflate specification refers to <i>dynamic Huffman codes</i>. However, this
- is a misnomer, in which the term <i>dynamic</i> is used in contrast to the
- <i>fixed</i> Huffman codes. The fixed Huffman codes are simply built according
- to a predefined Huffman tree, without regard to the actual symbol frequencies.
- The dynamic Huffman codes referred to by the Deflate specification are NOT
- built by the dynamic Huffman algorithm, as defined, for example, by Faller,
- Gallager and Knuth (the FGK algorithm), or by Vitter (the V algorithm).
- The predefined Huffman tree was introduced in <b>PKZIP</b> as a fast
- compression alternative, but it produces poor results even on text, and it is
- almost useless in PNG compression. Still, a PNG stream that contains codes
- built by the fixed (predefined) Huffman tree, is a valid stream, and a
- compliant PNG reader must decode this stream correctly.
- </blockquote>
- <p>
- It is desirable to establish the buffer boundaries so that sequences conforming
- to the same probability model are fit in the same Huffman buffer. Methods for
- approaching these boundaries exist, but they are not used in the mainstream
- Deflate implementation(s). Instead, the buffers are flushed when a limit
- (typically, 16k LZ77 codes) is reached. This is, however, a fast approach, and
- the results are satisfactory.
- </p>
- <p>
- The size of Huffman buffers is indirectly determined by the encoder's memory
- (usage) level. For this reason, certain memory levels might be good for certain
- types of images.
- </p>
- <h3>3. PNG (lossless) optimization programs</h3>
- <p>
- The multitude of PNG encoding programs is listed at
- <a href="http://www.libpng.org/pub/png/pngapps.html">http://www.libpng.org/pub/png/pngapps.html</a>.
- Their performance varies as much as the range of possible compression ratios;
- the good encoders are at least applying the filtering heuristics, described
- briefly in the PNG Specification, and illustrated above.
- <br>
- Some programs gain extra compression by discarding some of the data in the
- input images (so these programs are <i>lossy</i>!)
- </p>
- <p>
- This section contains the small list of <b><i>PNG optimization programs</i></b>
- that show a particular concern towards obtaining a file size as small as
- possible. They work by performing repeated compression trials, applying various
- parameter sets, and selecting the parameter set that yields the smallest
- compressed output.
- </p>
- <ul>
- <li>
- <p>
- <b>pngrewrite</b> by Jason Summers, available at
- <a href="http://www.pobox.com/~jason1/pngrewrite/">http://www.pobox.com/~jason1/pngrewrite</a>,
- is an open-source program that performs lossless image reductions.
- It works best in conjunction with <b>pngcrush</b> (see below); the user
- should run <b>pngcrush</b> <i>after</i> <b>pngrewrite</b>.
- </p>
- </li>
- <li>
- <p>
- <b>pngcrush</b> by Glenn Randers-Pehrson, available at
- <a href="http://pmt.sourceforge.net/pngcrush/">http://pmt.sourceforge.net/pngcrush</a>,
- is an open-source program that iterates over PNG filters and zlib (Deflate)
- parameters, compresses the image repeatedly using each parameter
- configuration, and chooses the configuration that yields the smallest
- compressed (IDAT) output.
- At the user's option, the program can explore few (below 10) or many (a
- brute-force traversal over more than 100) configurations. The method of
- selecting the parameters for "few" trials is particularly effective, and the
- use of a brute-force traversal is generally not recommended.
- </p>
- <p>
- In addition, <b>pngcrush</b> offers a multitude of extra features, such as
- recovery of erroneous PNG files (e.g. files containing bad CRCs), and
- chunk-level editing of PNG meta-data.
- </p>
- </li>
- <li>
- <p>
- <b>OptiPNG</b> by Cosmin Truţa, available at
- <a href="http://www.cs.toronto.edu/~cosmin/pngtech/optipng/">http://www.cs.toronto.edu/pngtech/optipng</a>,
- is a newer open-source program, inspired from <b>pngcrush</b>, but designed
- to be more flexible and to run faster.
- Unlike <b>pngcrush</b>, <b>OptiPNG</b> performs the trials entirely in
- memory, and writes only the final output file on the disk. Moreover, it
- offers multiple optimization presets to the user, who can choose among a
- range of options from "very few trials" to "very many trials" (in contrast to
- the coarser "smart vs. brute" option offered by <b>pngcrush</b>).
- </p>
- <p>
- It is important to mention that the achieved compression ratio is less and
- less likely to improve when higher-level presets (trigerring more trials)
- are being used. Even if the program is capable of searching automatically
- over more than 200 configurations (and the advanced users have access to more
- than 1000 configurations!), a preset that selects around 10 trials should be
- satisfactory for most users. Furthermore, a preset that selects between
- 30-40 trials <i>should</i> be satisfactory for all users, for it is very,
- very unlikely to be beaten significantly by any wider search. The rest of the
- trial configurations are offered rather as a curiosity (but they were used in
- the experimentation from which we concluded they are indeed useless!)
- </p>
- </li>
- <li>
- <p>
- <b>AdvanceCOMP</b> by Andrea Mazzoleni is a set of tools for optimizing
- ZIP/GZIP, PNG and MNG files, based on the powerful <b>7-Zip</b> deflation
- engine. The name of the PNG optimization tool is <b>AdvPNG</b>. At the time
- of this writing, <b>AdvPNG</b> does not perform image reductions, so the use
- of <b>pngrewrite</b> or <b>OptiPNG</b> prior to optimiziation may be
- necessary. However, given the effectivenes of <b>7-Zip</b> deflation,
- <b>AdvanceCOMP</b> is a powerful contender.
- </p>
- <p>
- The <b>AdvanceCOMP</b> tool set is a part of the <b>AdvanceMAME</b> project,
- available at
- <a href="http://advancemame.sourceforge.net/">http://advancemame.sourceforge.net</a>.
- </p>
- </li>
- <li>
- <p>
- <b>PNGOut</b> by Ken Silverman, available at
- <a href="http://advsys.net/ken/utils.htm">http://advsys.net/ken/utils.htm</a>,
- is a freely-available compiled program (no source code), running on
- Windows and Linux. According to our tests, the compression ratio achieved by
- <b>PNGOut</b> is comparable to that of <b>AdvPNG</b>.
- Unfortunately, due to the lack of information, we cannot say much about this
- tool.
- </p>
- <p>
- A nice GUI frontend for <b>PNGOut</b>, named <b>PNGGauntlet</b>, is
- available at
- <a href="http://www.numbera.com/software/pnggauntlet.aspx">http://www.numbera.com/software/pnggauntlet.aspx</a>.
- </p>
- </li>
- </ul>
- <h3>4. An extra note on losslessness</h3>
- <p>
- What is lossless PNG optimization, after all? This is a straightforward
- question, whose answer is intuitive, yet not so straightforward.
- </p>
- <p>
- Losslessness in the strictest sense, where no information whatsoever is lost,
- can only be achieved by leaving the original file (<i>any</i> file) intact, or
- by transforming it (e.g. compressing it, encrypting it) in such a way that
- there is an inverse transformation which recovers it completely, bit by bit.
- </p>
- <p>
- In the case of PNG images, this condition of strict losslessness has little
- relevance to the casual graphics user, and is, therefore, too strong.
- There are instances where strict losslessness is required; for example, when
- handling certified PNG files whose integrity is guaranteed by an external
- checksum like <b>MD5</b> or <b>SHA</b>, or by a digital signature such as
- <b><code>dSIG</code></b>. Most of the time, however, it is desirable to relax
- the notion of PNG losslessness, to the extent of not losing any information
- that pertains to the <i>rendered image</i> and to the
- <i>semantic value of the metadata</i> that accompanies the image. This allows
- the user to concentrate on what is really important when it comes to preserving
- the contents of a PNG image, and enables the concept of PNG optimization tools.
- </p>
- <blockquote>
- A <b><i>lossless transform</i></b> of a PNG image file is a transform which
- fully preserves the <i>rendered</i> RGB triples (the RGB triples that come
- either directly, or from a palette index, or from a gray->RGB expansion), the
- <i>rendered</i> transparency (the alpha samples that come either directly, or
- from a <b><code>tRNS</code></b> chunk, or the implicit 100% opacity assumed due
- to the lack of any explicit transparency information), the <i>order of
- rendering</i> (sequential or interlaced), and the semantics contained by the
- ancillary chunks.
- </blockquote>
- <div>
- This definition allows the execution of the above-mentioned image reduction
- operations, and the recompression of <b><code>IDAT</code></b>. It also allows
- the alteration or the elimination of other pieces of information that are
- technically valid, but have no influence on any presentation of the image
- pixels:
- </div>
- <ul>
- <li>
- The information that pertains to <b><i>Deflate</i></b> streams, either inside
- <b><code>IDAT</code></b>, or in other compressed chunks like
- <b><code>zTXt</code></b>, <b><code>iTXt</code></b> or
- <b><code>iCCP</code></b>; e.g. the LZ77 window size, the type and size of
- <b><i>Deflate</i></b> blocks, etc. (The only thing that matters is that the
- decompressed byte sequence must remain the same.)
- </li>
- <li>
- The order of palette entries inside a <b><code>PLTE</code></b> chunk. (When
- changing this order, the information that depends on it, such as the
- palette-encoded pixels or the <b><code>tRNS</code></b> information, must be
- updated accordingly.)
- </li>
- <li>
- RGB triples that do not correspond to any pixel in the actual image, but are
- stored in a <b><code>tRNS</code></b> chunk.
- </li>
- <li>
- Fully opaque <b><code>tRNS</code></b> entries in a palette image.
- </li>
- <li>
- Gamma correction (<b><code>gAMA</code></b>) or significant bit
- (<b><code>sBIT</code></b>) information inside an image that consists
- exclusively of samples whose intensity is either minimum (0) or maximum
- (2^<sup>bitdepth</sup>-1).
- </li>
- <li>
- The fact that a textual comment is stored uncompressed in a
- <b><code>tEXt</code></b> chunk, or compressed in a <b><code>zTXt</code></b>
- chunk, or with no translation in an <b><code>iTXt</code></b> chunk.
- </li>
- <li>
- Etcetera.
- </li>
- </ul>
- <p>
- If any of the discardable information is important in a particular application,
- and lossless PNG optimization is still desirable, it is recommended to store
- this information in ancillary chunks, rather than hack it inside critical
- chunks. For example, if sterile palette entries are necessary (e.g. for later
- editing stages), it is recommended to store them inside a suggested palette
- (<b><code>sPLT</code></b>) chunk, rather than keeping them inside
- <b><code>PLTE</code></b>.
- </p>
- <h3>5. Selective bibliography</h3>
- <p>
- Besides the discussed specifications, the references below provide essential
- information necessary to comprehend the contents of this article.
- </p>
- <ul>
- <li>
- Thomas Boutell, Glenn Randers-Pehrson et al.
- <i>Portable Network Graphics (PNG) Specification, Second Edition</i>.
- ISO/IEC 15948:2003(E); W3C Recommendation 10 November 2003.
- </li>
- <li>
- David A. Huffman.
- A method for the construction of minimum redundancy codes.
- In <i>Proceedings of the Institute of Radio Engineers</i>,
- vol. 40, no. 9, pp. 1098-1101, September 1952.
- </li>
- <li>
- Jacob Ziv and Abraham Lempel.
- A universal algorithm for data compression.
- <i>IEEE Transactions on Information Theory</i>,
- vol. IT-23, no. 3, pp. 337-343, May 1977.
- <br>
- <font size="-1">
- Due to a historical accident, the famous algorithm is better-known as the
- "Lempel-Ziv (LZ) algorithm", even though the "Ziv-Lempel algorithm" is a
- more legitimate name.
- </font>
- </li>
- <li>
- Greg Roelofs.
- <i>PNG: The definitive guide</i>.
- O'Reilly and Associates, 1999.
- </li>
- </ul>
- <hr>
- <address>
- <font size="-1">
- Copyright © 2003-2008 Cosmin Truţa. Permission to distribute freely.
- <br>
- Appeared: 7 Apr 2003.
- <br>
- Last updated: 10 May 2008.
- </font>
- </address>
- </body>
- </html>
|