2

How would you scale/optimize/minimally output a PNG image so that it just falls below a certain maximum file size? (The input sources are various - PDF, JPEG, GIF, TIFF...)

I've looked in many places but can't find an answer to this question.

In ImageMagick a JPEG output can do this with extent (see e.g. ImageMagick: scale JPEG image with a maximum file-size), but there doesn't seem to be an equivalent for other file formats e.g. PNG.

I could use Wand or PIL in a loop (preference for python) until the filesize is below a certain value, but for 1000s of images this will have a large I/O overhead unless there's a way to predict/estimate the filesize without writing it out first. Perhaps this is the only option.

I could also wrap the various (macOS) command-line tools in python.

Additionally, I only want to do any compression at all where it's absolutely necessary (the source is mainly text), which leaves a choice of compression algorithms.

Thanks for all help.

PS Other relevant questions:

Scale image according a maximum file size

Compress a PNG image with ImageMagick

python set maximum file size when converting (pdf) to jpeg using e.g. Wand

Edit: https://stackoverflow.com/a/40588202/1021819 is quite close too - though the exact code there already (inevitably?) makes some choices about how to go about reducing the file size (resize in that case). Perhaps there is no generalized way to do this without a multi-dimensional search.

Also, since the input files are PDFs, can this even be done with PIL? The first choice is about rasterization, for which I have been using Wand.

https://stackoverflow.com/a/34618887/1021819 is also useful, in that it uses Wand, so putting that operation within the binary-chop loop seems to be a way forward.

jtlz2
  • 7,700
  • 9
  • 64
  • 114
  • Possible duplicate of [Python PIL: Find the size of image without writing it as a file](https://stackoverflow.com/questions/40587343/python-pil-find-the-size-of-image-without-writing-it-as-a-file) – Ofer Sadan Aug 01 '17 at 07:25
  • You can zoom in on the correct size fairly quickly by doing a [binary search](https://en.wikipedia.org/wiki/Binary_search_algorithm). You don't need to save the file to disk, save it to a `io.BytesIO()`. Note that the PNG files produced by PIL can often be reduced considerably by the use of a PNG optimizer like [optipng](http://optipng.sourceforge.net). – PM 2Ring Aug 01 '17 at 07:28
  • Thanks both - super helpful - I do want to drive everything from python if possible (rather than calling executables from it) – jtlz2 Aug 01 '17 at 07:30
  • Fair enough, there _is_ a Python module that does image file optimization, but it uses external programs to actually perform the optimizations, so you might as well do it yourself by calling `optipng` via `subprocess`. – PM 2Ring Aug 01 '17 at 07:37
  • The objective is somewhat pointless, because PNG is lossless, and you aren't trading away image appearance for filesize. The tradeoff is compression speed versus optimization, not appearance versus optimization. You might look into using the IM -colors option to reduce the number of colors, which will affect filesize and appearance. – Glenn Randers-Pehrson Aug 01 '17 at 13:35
  • @GlennRanders-Pehrson It's not at all pointless - certain APIs I am using only admit files below a certain size, and in certain formats, and do better depending on the format used. Speed is less of an issue for me. – jtlz2 Aug 01 '17 at 13:49
  • If you are willing to resize your file to smaller dimensions, then I have a bash unix shell script the uses ImageMagick to iteratively resize the image until the file size reaches a given size. See http://www.fmwconcepts.com/imagemagick/downsize/index.php – fmw42 Aug 01 '17 at 16:17
  • epic - thanks @fmw42 ! – jtlz2 Aug 02 '17 at 06:15
  • I meant optimizing for a specified size is pointless. With PNG, just go for the smallest possible compression, using my pngcrush app, optipng, zopflipng, etc., without worrying about any "tradeoff" of size versus appearance. If that's not good enough, consider reducing the number of colors with pngquant (255 colors is a good first try because it'll allow 8-bit paletted PNGs which will save a lot compared to RGB PNGs.) – Glenn Randers-Pehrson Aug 02 '17 at 14:47

1 Answers1

2

With PNG there is no tradeoff of compression method and visual appearance because PNG is lossless. Just go for the smallest possible file, using my "pngcrush" application, "optipng", "zopflipng" or the like.

If you need a smaller file than any of those can produce, try reducing the number of colors to 255 or fewer, which will allow the PNG codec to produce an indexed-color PNG (color-type 3) which is around 1/3 of the filesize of an RGB PNG. You can use ImageMagick's "-colors 255" option to do this. However, I recommend the "pngquant" application for this; it does a better job than IM does in most cases.

Glenn Randers-Pehrson
  • 11,940
  • 3
  • 37
  • 61