1

I was advised on Stack Overflow to post here.

TL;DR: Can ImageMagick's convert convert smartphone photographs of document pages to a fax-quality PDF file and shrink the file size by several orders of magnitude?

The details

I have lost count of the number of times I've experimented over the years to "convert" photographs of document pages to a fax-quality PDF. The photographs can take several MB's per page, while fax-quality can take a few dozen KB's at most. This is inconsequential on a per-page basis, but with everything being stored electronically, it adds up quick.

I've tried various combinations of convert's named arguments -density 200x200, -density 72x72, -monochrome, -colorspace Gray, and -depth 2. For example, one invocation pattern might be:

convert -density 72x72 -monochrome -depth 2 File1.jpg File2.jpg Output.pdf

I follow the conversion with pdfimages -list OutputFile.pdf to inspect the result. In the past, this revealed that it always uses 8-bit depth regardless of the presence/absence/specification of the -depth parameter. When -depth is less than 8, however, not all gray levels are used, which allows the space to be recovered in the compression (which always seems to occur).

At no time, however, is the size of the output file less than the sum of the sizes of the input files. In fact, -monochrome seems to double the file size, regardless of other parameters. So far, it seems that not specifying any optional parameters almost always gives the smallest file size, which still incurs extra tens of KB's. So there's no point doing any conversion. In fact, it's much more efficient to use pdfjam to combine the photographed pages into a full-color full-resolution PDF.

My area of profession isn't image processing, but I done grad school in Elec. Eng. and have been exposed to concepts of sub-sampling, high/low frequency filtering, and anti-aliasing. It seems to me like it shouldn't be difficult to extract fax-quality from a photo, and get the reduced file size of fax-quality.

Is anyone aware of a convert invocation pattern that will accomplish this? Is there a fundamental aspect of its operation that makes unachievable?

2
  • What you really need is OCR software - then all your pdf contains is text, not pictures.
    – Tetsujin
    Apr 12, 2021 at 7:03
  • I'm not too concerned about augmenting the image with recognized text. I just want to benefit from the smaller size of fax-quality documents. It seems like a last-century problem, and I'm puzzled by my inability to find a solution. Apr 12, 2021 at 11:58

2 Answers 2

1

I rediscovered the -resample options at this page. The -density parameter was the wrong one to use. And I mistakenly tried -resample after extracting the images from the PDF output of previous applications of convert, which is a bad thing to do. I do not know how faithful the extracted images are cmopared to the originals, and the results of convert image1.jpg image2.jpg Output.pdf was very bad.

Luckily, I didn't give up. I hunted down the original images, found their DPIs using identify -verbose image1.jpg and identify -verbose image2.jpg, found that they were 72dpi, then tried convert -resample 50x50 image1.jpg image2.jpg Output.pdf, and found perfectly acceptable quality at a reduced file size.

The -monochrome parameter still causes file size doubling, so I'll avoid that and explore other ways to do away with the space wasted by colour, but at least I have a way to reduce the resolution of the colour photos and combine them into PDF. I'm getting slight savings from convert -colorspace Gray -resample 50x50 image?.jpg Output.pdf. As before, -depth 2 inflates file size slightly and gives much worse quality, especially if the page has graded shadows for whatever reason. According to this page, -grayscale Rec709Luminance is another solution, but it still increases the total file volume (but not by 2x!) and the result seems a bit dark/dim.

Based on this page, I tried

convert -colorspace Gray -colors 32 -resample 50x50 image?.jpg Output.pdf

It created a slightly smaller file than without -colorspace Gray -colors 32, but pushing it even further with -colorspace Gray -colors 16 yielded a slightly larger file (and dimmer image). It all seems so unpredictable and inconsistent, though I'm sure it's my lack of insight into the inner workings of ImageMagick and Ghostscript. In any case, -resample 50x50 works well, but none of the options I've tried for grayscale yield smaller file, or the difference is insignificant and not worth the lost of colour.

One thing that baffles the bejeezus out of me is the fact that the resolution is 72dpi. There is no way that can be true. It's way better than that. And even in the output, for which I specify 50dpi, the quality is much better than that.

Afternote: At least from one online information source, it looks like my bafflement is misplaced. The default resolution at which smartphone photos are imported is 72dpi, according to this page. On the other hand, my bafflement doesn't seem misplaced when I compare the seemingly high-quality 72dpi photos to the 200dpi flatbed scans of documents, the former appearing to be much more high fidelity than the latter. A possible explanation is that the 200dpi scans are pure B&W rather than grayscale. I suspect that this is not the main reason for these counterintuitive observations, but I can't disprove it.

1

The following reduced the photographed document page from 2.5MB to 57KB:

python
from PIL import Image 
Image.open('IMG_0774.JPG').resize((im.width//2, im.height//2)).rotate(-90).convert(mode="1", dither=Image.NONE).save('IMG_0774.JPGsmall.png')

Furthermore, this page shows how to export a list of images to a PDF file. Once I get it working, I'll post back about whether it exports each image to its own page, and maybe even having a Python script that accepts bash arguments (filenames). I'm new to Python, so it could take a while. Meanwhile, if anyone knows this off the top of his/her head, feel free to steal my thunder!

So far, I have the following:

from PIL import Image
ims = []
fns=('IMG_0774.JPG','IMG_0775.JPG')
for fn in fns:
    im = Image.open(fn)
    im = im.resize((im.width//2, im.height//2))
    im = im.rotate(-90)
    im = im.convert(mode="1", dither=Image.NONE)
    ims.append(im)

ims[0].save( 'IMG_077xSmall.pdf' , save_all=True , append_images=ims[1:] )

Unfortunately, the output PDF file is 12MB, which is many orders of magnitude bigger than the downsampled black & white images if I save them as PNG. As well, there is cropping of non-whitespace content on the 2nd page.

The best solution I've found so far is to use convert outside of Python. So generate the small PNG's in Python:

import os
from PIL import Image 
fns=('IMG_0774.JPG','IMG_0775.JPG')
for fn in fns:
    im = Image.open(fn)
    im = im.resize((im.width//2, im.height//2))
    im = im.rotate(-90)
    im = im.convert(mode="1", dither=Image.NONE)
    fnBase = os.path.splitext(fn)[0]
    im.save( fnBase+'small.png' )

Then convert the PNG's into a PDF at the shell command line:

convert IMG_077[45]small.png IMG_077Xsmall.pdf

The resulting file sizes are as follows, which is very reasonable.

# Originals
2526685 IMG_0774.JPG
2699515 IMG_0775.JPG

# Resized, rotated, and converted to black & white
  56818 IMG_0774small.png
  62809 IMG_0775small.png

# PDF from ImageMagick's "convert" at the shell command line
 153749 IMG_077xSmall.pdf

Even with this "solution", however the problem of cropped content from IMG_0775.JPG remains. It occurs when the PNG is saved after resizing, rotating, and conversion to black & white.

A more compact solution of fax quality

Thanks to fmw42 in another thread, a compact PDF file of fax quality can be created from multiple JPEG files using the following ImageMagick command:

convert IMG_0774.JPG IMG_0775.JPG \
  -sample 50% -compress fax -type bilevel +dither \
  OutputFile.pdf

The +dither avoids dithering, which can lead to black speckle in regions that are gray in the original images.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .