#9 Read PNG from stdin and/or write PNG to stdout

Ryan Schmidt

I hope I'm not overlooking something obvious, but I'd
like to be able to use pngcrush in a Unix pipeline where
it reads the input PNG from stdin and/or writes the
output PNG to stdout. No such feature is mentioned in
the pngcrush 1.6.2 help text and brief experimentation
did not reveal any such feature, so I presume pngcrush
can't do that today.

The way some other Unix programs allow this, and how I'd
like pngcrush to work, is to treat the filename "-" as
the special indicator for stdin or stdout. For example:

pngcrush foo.png -
(input file foo.png, output to stdout)

pngcrush - foo.png
(input from stdin, output to foo.png)

pngcrush - -
(input from stdin, output to stdout)


  • I second that, none of the png optimization programs seem to support piping. Although it's just a matter to read from stdin/stdout when the argument is '-'.
    I think there is even a compiler option for this behaviour.

  • Bart Nagel
    Bart Nagel

    Adding my support.

  • Pngcrush needs to be able to re-read its input file multiple times, so there would have to be a temporary buffer (or a temporary file) big enough to hold the entire input file. So "pngcrush - -" might look more efficient, but it probably wouldn't really be more efficient.

    In the past, pngcrush also wrote its output file multiple times and selected the smallest, but that was done away with a couple of years ago (since version 1.7.34, July 2012). Now it only writes the trials to a byte-counting function, and only writes the final crushed image to the output file.

    In the meantime, it would be fairly simple to write a shell script that copies STDIN to a temporary file, pngcrushes that to another temporary file, and copies that to STDOUT. Such scripts probably already exist, but I don't have one [yet].

  • Bart Nagel
    Bart Nagel

    Hi, Glenn.

    Regardless of whether it makes any improvement in pngcrush's efficiency in itself (I take it it would not, in this case), it would make many workflows using pngcrush rather more simple. For instance I use pngcrush in various little tools which generate an image, which sometimes ends up as a file or in other cases is sent straight off to a user or similar. To use pngcrush as part of the chain in these cases I need to do the same workaround every time, which is much like the shell script you describe. This means either having that shell script available on every machine the tools are deployed to or rewriting its logic in whichever language I happen to be using for this tool. I'd love if it were a "built-in workaround".

    Is it a feature you'd consider adding, or not? (Whether buffer in memory or a temporary file or options for each.)

  • I second that feature request.

    The shell script workaround is not trivial if done properly. How to take failues into account? How to avoid race conditions? How to name the intermediate file? Where to put the intermediate file? How to cleanup the intermediate file? How to pass arguments? How to find if only stdin, only stdout or both are to be redirected? The shell script would end up having signal handlers to clean up that intermediate file, and for that simple purpose that frankly seems overkill.

    In the typical case, the PNG file is between a few kB and a few hundred kB while pngcrush is typicall run on machines with GBs of RAM. Buffering in case of stdin should really not be an issue, and there could be a warning in the help text that pngcrush needs to buffer the entire file, so if you use "-" to read from stdin, do it at your own risk regarding memory consumption.

    Let's see what it actually means for the user.
    In a Makefile, what I would like to write is something like this:

    dest/%.png: src/%.png
        <$< pngquant --force --nofs - | pngcrush >$@

    But because pngcrush doesn't support pipes, what I actually have to write is this:

    dest/%.png: src/%.png
        set -e ; <$< pngquant --force --nofs - >/tmp/$(notdir $*).$$$$.png ; pngcrush -q /tmp/$(notdir $*).$$$$.png $@ ; $(RM) /tmp/$(notdir $*).$$$$.png

    (And when something fails, there's yet another file lying arond in /tmp.)

    Last edit: Christian Hujer 2015-10-15