PNGCRUSH(1)
๐ PNGCRUSH(1) โ the manual page, but make it make sense
okay bestie, welcome to pngcrush(1) ๐ฆ this is the glow-up era of your PNG files, and i'm gonna walk you through it like we're texting at 2am. no gatekeeping, no cap.
โจ NAME โจ
pngcrush โ optimizes (or modifies) PNG (Portable Network Graphics) files. literally its whole personality ๐
๐ธ SYNOPSIS ๐ธ
like, here's how you actually call it, three iconic ways:
pngcrush [ options ] [ infile.png ] [ outfile.png ]
pngcrush -e ext [ options ] [ file1.png ] [ file2.png ] ...
pngcrush -d dir [ options ] [ file1.png ] [ file2.png ] ...
pick your fighter ๐
๐ DESCRIPTION ๐
so pngcrush is an optimizer for PNG (Portable Native... no wait โ Portable Network Graphics) files. its main purpose is to reduce the size of the file's IDAT chunk (or stream). that's the whole mission. main character energy fr ๐ฅ
but it's not a one-trick pony โ pngcrush can also be used to modify a PNG's ancillary chunks (example: transparency information or textual comments). so it optimizes and it edits. versatile queen.
ngl, some familiarity with the PNG (pronounced 'ping') format may be helpful to users of pngcrush. not required, just helpful. consider it a little lore drop ๐ง
and here's the best part: pngcrush has reasonable defaults, so running with no options may produce smaller files. you don't even have to try and it still eats. periodt ๐
this document briefly describes the PNG format where necessary to understand pngcrush. for complete documentation, see:
http://www.libpng.org/pub/png/
๐ซถ the PNG format, explained by your bestie
the actual pixel data of a PNG is contained in one or many IDAT chunks. that's where the real image lives, no cap.
to make an IDAT chunk, PNG encoders take the raw pixel data, filter it with one of 5 different filters (See Section pngcrush(1)) then compress it. filter โ compress โ chunk. that's the pipeline, iykyk โญ
pngcrush reduces the size of PNG files by choosing a different filter or compression methods from those used in the input file. so it's like "hmm, what if we did this differently" and then it just... does.
here's the vibe: pngcrush tries multiple filter/compression methods and compares the size of the resulting IDAT chunk. the filter/compression method with the smallest IDAT chunk is chosen for the output file. smallest wins. it's giving competition arc ๐
the filter and compression levels pngcrush tries are controlled by command line options. so yes, you get to be the director of this whole situation ๐ฌ
and before anyone panics: all of the filter methods and compression levels are lossless. they will not reduce image quality. your pixels stay exactly as gorgeous as they were. no notes. ๐โจ
๐ฆ ancillary chunks (the side quests)
in addition to reducing the size of a PNG file, pngcrush can modify ancillary chunks. ancillary chunks are optional information including:
- transparency (
tRNS) - gamma (
gAMMA) - standard RGB color space conformance (
sRGB) - textual information (
iTXt,tEXtorzTXt)
see the associated command line options for details on manipulating these chunks. there's a whole options section coming and it's lowkey stacked ๐
โจ OPTIONS โจ
okay bestie, this is the big one โ the whole menu of options. grab a snack ๐
-alreadysize โ if the file's IDAT chunk is bigger than the integer size, pngcrush decides it's already been crushed and justโฆ doesn't touch it. bye, no further processing ๐-bit_depthn โ forces the output bit depth to n. the bit-depth restrictions are over in Section pngcrush(1), go check those ๐-bkgdr g b โ sets the default background color for the image. some PNG viewers will use this background when they display it. background is given by the r, g and b integers between 0 and (2bitdepth)-1. for output color type 0 and 4 (gray, see section pngcrush(1)) the green index is used as the gray level of the background ๐จ-bruteโ brute force era: tries 114 different filter/compression methods [11-124]. it is very time-consuming and generally not worthwhile, ngl ๐ญ you can restrict it to certain filter types, compression levels, or strategies by following it with-ffilter,-llevel, or-zstrategy. like so:
pngcrush -brute -f 0 infile.png
that one will try only methods that use filter type 0 โจ
-ctype โ sets the output image color type to type, one of[0, 2, 4, or 6](see section pngcrush(1)). future versions of pngcrush will also allow color type 3, if there are 256 or fewer colors present in the input file. color types 4 and 6 get padded with an opaque alpha channel if the input file has no alpha info. you can use 0 or 4 to convert color to grayscale ๐ค use 0 or 2 to delete an unwanted alpha channel. default is to use the same color type as the input file ๐ซถ-ddir โ picks a directory for all output files. all the output files keep the same name as their respective input files ๐-douโ doubles the image's gamma. this is for fixing gamma in PhotoShop 5.0c5.02 files. it has been claimed that the PS5 bug is actually more complex than that, in some unspecified way ๐-eext โ sets a new extension ext for all output files ๐ท๏ธ-exitโ forces pngcrush to callexit()rather thanreturn()when it's finished. it is unclear to this writer why this option exists ๐-ffilter โ specifies the filter (see section pngcrush(1)) to use with the method given in the preceding-mor-bruteoption. valid filter types are[0-4]: use specified filter,[5]: use adaptive filtering ๐-fixโ fixes otherwise fatal conditions such as bad CRCs. the CRC (Cyclic Redundancy Check) is present in every chunk and can alert the decoder of corrupt data ๐ฉน-forceโ writes a new output file even if it's larger than the input. otherwise the input file gets copied to output if it's smaller than any generated file and no chunk additions, removals, or changes were requested ๐ช-ggamma โ the value to insert in the gAMA chunk, only if the input file has no gAMA chunk. to replace an existing gAMA chunk, use the-replace_gammaoption instead. some decoders will use the gAMA chunk to display the image more accurately. gamma relates the output intensity to the input samples (input_sample = light_out^GAMMA). gamma can be any integer between 0 and 2^32 and is interpreted as GAMMA*100000. for example, if you wanted a GAMMA of 1/2.2, you'd enter45455for gamma โญ-hโ displays help and legal notices ๐-itxtb|a keyword text โ inserts an (uncompressed) iTXt chunk. b|a says whether the chunk should be inserted before or after the IDAT chunk, (see Section pngcrush(1)) ๐-keepchunk_name โ keeps the named chunk chunk_name even if the PNG datastream becomes invalid. currently onlydSIGis recognized as an acceptable value ๐ซฃ-llevel โ the zlib compression level to use on the filtered IDAT chunk with the method specified by the preceding-mor-bruteoption. zlib compression levels are integers between 0 and 9. 0 = no compression, 1 = fastest compression, and 9 = best compression ๐ฅ-locoโ makes the file more compressible by performing a lossless, reversible, color transformation. the resulting file is a MNG format file, not a PNG, and should be given the.mngfile extension. heads up: the loco option has no effect on grayscale or indexed-color PNG files ๐ฆ-mmethod โ the pngcrush method [0-200] to try (0 means try all of 1-10). can be repeated, like-m 1 -m 4 -m 7. this is useful if you run out of memory when pngcrush tries methods 2, 3, 5, 6, 8, 9, or 10 โ those use filtering and are memory intensive ๐ฎโ๐จ methods 1, 4, and 7 use no filtering; methods 11 and up use specified filter, compression level, and strategy ๐ซ-maxmaximum_IDAT_size โ sets the maximum idat size to be used when creating the compression buffer. [1through524288] ๐-mngโ writes a new MNG, doesn't crush embedded PNGs ๐ง-nโ no compression and no output file. this is useful with the-voption to get info, or to test decode speed ๐โโ๏ธ-pโ tells pngcrush to pause and wait for the enter key whenever the screen fills up ๐ฅ๏ธ-plte_lenn โ truncates the PLTE. the PLTE chunk contains from 1 to 256 palette entries. be sure not to truncate it to less than the greatest index present in IDAT โ ๏ธ-qโ quiet, the opposite of verbose ๐คซ-remchunkname โ the name of an ancillary chunk or optional PLTE to be removed. be careful with this one, fr fr. please don't use this feature to remove transparency, gamma, copyright, or other valuable information ๐ to remove several different chunks, repeat it:-rem tEXt -rem pHYs. known chunks (those in the PNG spec or extensions document) can be named with all lower-case letters, so-rem bkgdis equivalent to-rem bKGD. but note:-rem textremoves all forms of text chunks; exact case is required to remove unknown chunks. and if you want to do surgery with a chain-saw ๐ช,-rem allaremoves all known ancillary chunks except for tRNS, and-rem allbremoves all but tRNS and gAMA ๐-replace_gammagamma โ forces a specified gamma in the output file even if gAMA is present in the input. see the-goption for more info ๐-resdpi โ writes a pHYs chunk with a resolution of dpi. the pHYs chunk indicates the desired pixel size ๐-saveโ forces writing of unknown chunks. if the input image has chunks that aren't part of the PNG specification, they should not be discarded ๐-srgbn โ sets the value of rendering intent for the sRGB chunk to n, where n is between 0 and 3. the appropriate rendering intent depends on how the image will be used:0โ Perceptual: when good adaptation to the output device gamut at the expense of colorimetric accuracy is desired, example: photographs ๐ธ1โ Relative colorimetric: images requiring color appearance matching (relative to the output device white point), example: logos ๐ฏ2โ Saturation: preservation of saturation at the expense of hue and lightness is preferred, example: charts and graphs ๐3โ Absolute colorimetric: images requiring preservation of absolute colorimetry, example: proofs (previews of images destined for a different output device) ๐จ๏ธ
-text[b|a] keyword text โ inserts a tEXt chunk. [b|a] says whether the chunk should be inserted before or after the IDAT chunk, (see Section pngcrush(1)) โ๏ธ-newtimestampโ resets the file modification time to a newer time stamp. this is the default โฐ-oldtimestampโ retains the input file's modification time stamp. the default is-newtimestamp, which is the opposite of this option ๐ฐ๏ธ-trnsindex red green blue gray โ inserts a tRNS (transparency) chunk, if no tRNS chunk is found in the file. you must give all five parameters regardless of the color type, scaled to the output bit depth. see the PNG documentation for details ๐ป-trns_arrayn trns[0] trns[1] ... trns[n-1] โ inserts a tRNS (transparency) chunk, if no tRNS chunk is found in the file. see the PNG documentation for details ๐ซง-vโ displays more detailed information. repeat the option (use-v -v) for even more ๐-wsize โ specifies the size, in kbytes (or bytes in the case of 512), of the sliding compression window, where size is one of[32, 16, 8, 4, 2, 1, or 512]. it's best to use the default (32) unless you run out of memory. the program will use a smaller window anyway when the uncompressed file is smaller than 16k ๐ช-zstrategy โ specifies the zlib compression strategy[0, 1, or 2]to be used on the filtered IDAT chunk for the method of the preceding-m. the zlib strategy parameter tunes the compression algorithm and is one of:0: default, most compression is aimed towards string matching ๐งต1: some string matching, some Huffman coding ๐2: use only Huffman coding ๐ณ
-zitxt[b|a] keyword text โ inserts a zTXt chunk. [b|a] says whether the chunk should be inserted before or after the IDAT chunk, (see Section pngcrush(1)) ๐๏ธ-ztxt[b|a] keyword text โ zTXt chunk to insert (see-text) ๐ฆ
๐จ COLOR TYPES ๐จ
the PNG specification provides for five color types, and the color type is literally what determines how the IDAT chunk will be interpreted by the decoder. choosing a color type that's appropriate for the color information in an image can in principle reduce the size โจ however, certain combinations of -c and -bit_depth require color counting, which is currently disabled โ and in such cases no reduction will take place, sorry bestie ๐ญ
here are the PNG color types with their supported bit depths (note that pngcrush does not support changing a file to color type 3 from another color type):
0: grayscale without alpha channel (1,2,4,8,16) ๐ค2: true color without alpha channel (8,16) ๐3: indexed color (1,2,4,8) ๐จ4: grayscale with alpha channel (8,16) ๐ซ๏ธ6: true color with alpha channel (8,16) ๐
an alpha channel represents transparency on a per-pixel basis. an alpha value of zero is completely transparent, and an alpha channel of 2^bitdepth-1 is completely opaque ๐ซถ
๐ฆ FILTER TYPES ๐ฆ
okay so bestie, plot twist: the IDAT chunk can optionally get filtered before it gets compressed. and like, these filters are literally the glow-up the IDAT chunk didn't know it needed โ they make it way more compressible without losing a single byte of data, so you end up with a smaller PNG file. ๐
important vibes check tho: these filters get applied to the bytes of the IDAT chunk, not the pixels. do not come for me. if you want the full lore, go read the PNG specification, but here's the quick rundown:
0: no filter. just vibes, no changes. ๐ซถ1:'sub'transmits the difference between each byte and the value of the corresponding byte of the prior pixel. ngl it's basically "what changed since the last one?"2:'up'transmits the difference between each byte and the value of the corresponding byte of the pixel above this pixel. looking up for once, iconic. โฌ๏ธ3:'average'transmits the difference between each byte and the average of the bytes described in filters 1 and 2. it's giving middle child energy, lowkey.4:'paeth'computes a simple linear function of the corresponding byte in three neighboring pixels (paeth_predictor = left + above - upper left), then transmits the difference between the byte in question and the neighboring byte closest to the value ofpaeth_predictor. yes it's a whole math moment, yes it slays. โจ
๐ TEXT CHUNKS ๐
so you can slide textual information about an image into your PNG using the tEXt, iTXt and zTXt chunks. all text chunks are built the same way: a keyword followed by a string. periodt.
the PNG specification defines these keywords (but bestie, you may invent keywords for other purposes, go off ๐):
Title: Short title or caption for imageAuthor: Name of image's creatorDescription: Longer description of imageCopyright: Copyright noticeCreation Time: Time of original image creationSoftware: Software used to create the imageDisclaimer: Legal disclaimerWarning: Warning of nature of contentSource: Device used to create the imageComment: Miscellaneous comment.
character set tea โ:
- A
tEXtchunk stores text in the ISO/IEC 8859-1 (Latin-1) character set. zTXtchunks also use the Latin-1 character set, but the text is compressed. this can be useful for large text chunks โ big text, small file, we love to see it. ๐iTXtchunks consist of text in the UTF-8 of the Unicode character set. unicode girlies rise. ๐
โ ๏ธ the limits, bestie, respect the limits:keywordmust be at least 1 character and less than 80 characters.textmust be less than 2048 characters when usingpngcrush. and for now? you can only add tentEXt,iTXt, orzTXtchunks perpngcrushrun. ten. that's the whole budget. ๐
๐ SEE ALSO ๐
๐ AUTHOR ๐
this manual page was written by David Whedon <dwhedon@gordian.com> for the Debian GNU/Linux system (but may be used by others โ yes, sharing is caring ๐ซถ). much of the information was gleaned from "PNG (Portable Network Graphics) Specification, Version 1.2" โ credit where credit is due, king. ๐
okay that's the whole page bestie, we made it to the end together ๐งโจ this was PNGCRUSH(1), dated Mon Apr 30, 2001 โ yes she's an elder icon but she still ate, ngl. mwah, go crush some PNGs responsibly ๐
๐
๐ฆ where this page comes from
- epel 9: pngcrush 1.8.13-9.el9 ยท zlib
- fedora 43: pngcrush 1.8.13-25.fc43 ยท Zlib
- fedora 44: pngcrush 1.8.13-26.fc44 ยท Zlib
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms