DEV Community

Anuj Kabra
Anuj Kabra

Posted on

The portal wants a JPG of my PDF certificate

Plenty of upload forms take a certificate only as a JPG, usually with a size limit like "under 200 KB" and sometimes a maximum width in pixels. The PDF you have doesn't have pixels at all: its text is drawn from outlines, so when you turn it into a JPG you choose how many pixels each inch of paper gets. That one number decides whether the small print survives, and the KB limit is a separate step after it. I tested everything below on a dummy A4 certificate I generated with fake details: a big heading, a name, a 9 pt certificate number, 6 and 7 pt small print, a seal, and a pale wavy background pattern like the security print many certificates have.

Pixels come from the resolution you render at

A PDF page has a size in inches (A4 is 8.27 x 11.69 in), so the pixel size of the image is just inches x DPI:

DPI    A4 in pixels    6 pt type in pixels
72     596 x 842       6
96     794 x 1123      8
150    1241 x 1754     12.5
200    1654 x 2339     17
300    2481 x 3508     25
Enter fullscreen mode Exit fullscreen mode

The pixel sizes are what pdftoppm actually wrote for my A4 page (it rounds up, so 1241 rather than 1240). The last column is points / 72 x DPI, the font size in pixels; capital letters are only about two thirds of that. A screenshot of a whole A4 page on a 1080p screen can't be more than about 1080 px tall, which is under 100 DPI. At 72 DPI, which is what a viewer's "1x" export gives, the "8" and the "B" in my 6 pt serial number were grey smudges that looked alike. At 96 they were readable if I squinted, and at 150 they were clean.

The command line: pdftoppm

pdftoppm comes with poppler (poppler-utils on Linux, brew install poppler on a Mac). I used version 25.03.0.

pdftoppm -r 200 -jpeg -jpegopt quality=85 -singlefile certificate.pdf certificate
Enter fullscreen mode Exit fullscreen mode

-r is the DPI, -jpegopt quality= sets the JPEG quality (without it, my files came out at quality 75), and -singlefile writes certificate.jpg instead of certificate-1.jpg. For one page out of a longer file, add -f 2 -l 2 for page 2. It also writes the DPI into the JPEG header, so the 200 DPI file reports 200 x 200 if a form checks that field.

If the form gives a pixel size instead of a DPI, let pdftoppm work out the scale:

pdftoppm -scale-to-x 1000 -scale-to-y -1 -jpeg -singlefile certificate.pdf certificate
Enter fullscreen mode Exit fullscreen mode

That gave me 1000 x 1415; -1 keeps the proportions.

macOS Preview

Open the PDF, select the page, then File > Export (not Export as PDF), set Format to JPEG, type a Resolution, and use the Quality slider. Export writes only the selected page. I ran my tests on Linux, so I haven't clicked through Preview for this post; check the pixel size of what it saves before uploading.

Then the KB limit

Here's what my dummy certificate came to at the default quality 75:

                         150 DPI    200 DPI    300 DPI
with background pattern  386,593    537,605    965,995 bytes
plain white background   127,690    192,847    351,011 bytes
Enter fullscreen mode Exit fullscreen mode

The text barely costs anything. The fine wavy background is what fills the file, and converting to grayscale didn't fix that: -gray at 150 DPI only went from 386,593 to 383,104 bytes.

So to get under 200 KB there are two dials, pixels and quality, and the order matters. I pushed my 300 DPI render to 200 KB without reducing pixels, and ImageMagick had to go down to quality 8: the text still read fine, but the cream background broke into patchy white blocks. Reducing to 1240 px wide first, the same 200 KB came out at quality 47 and looked like the original at normal zoom. For 100 KB, 1000 px wide landed at quality 30 while 1240 px needed 17, with visible smudges around the letters.

With ImageMagick (version 7, the command is magick; on version 6 it's convert), render a lossless PNG once, then resize and let ImageMagick find the quality:

pdftoppm -r 300 -png -singlefile certificate.pdf certificate-300
magick certificate-300.png -resize 1240x -define jpeg:extent=200kb upload.jpg
Enter fullscreen mode Exit fullscreen mode

-resize 1240x sets the width and keeps the proportions, and jpeg:extent searches for the highest quality that fits. My result was 194,735 bytes at 1240 x 1753. Starting from the PNG instead of a JPEG avoids compressing twice.

With poppler only, a small loop does the same search by hand:

limit=200000
for q in 90 85 80 75 70 65 60 55 50 45 40; do
  pdftoppm -r 120 -jpeg -jpegopt quality=$q -singlefile certificate.pdf upload
  size=$(stat -c %s upload.jpg)   # macOS: stat -f %z upload.jpg
  echo "quality $q: $size bytes"
  [ "$size" -le "$limit" ] && break
done
Enter fullscreen mode Exit fullscreen mode

At 150 DPI my patterned certificate was still 221,594 bytes at quality 40, so I dropped to 120 DPI, which stopped at quality 60 with 195,945 bytes. If even that isn't enough, lower -r again rather than the quality.

The gotcha: don't start from screen resolution

The usual advice is "render higher and scale down", and the part of it that matters is the first half. When I compared a page rendered directly at 1000 px wide with one rendered at 300 DPI and then resized to 1000 px, I couldn't see a difference in the small print; pdftoppm smooths edges as it renders. What does ruin small print is starting from too few pixels: a screenshot, or a viewer export at 72 DPI, can't be fixed by enlarging it later, because the detail was never captured. So render at 200 or 300 DPI, keep that file, and come down only as far as the form's pixel and KB limits make you. Before uploading, open the JPG at 100% and read the smallest line, usually the certificate number or the verification code.

A browser option

I built ToolOcean, and its PDF to images page renders pages in the browser without uploading the file. It offers PNG or JPEG and three scales, 1x, 2x and 4x, which the page describes as 72, 144 and 288 DPI. PNG is selected by default, so switch it to JPEG for an upload form. On my dummy certificate the JPEGs came out at 595 x 841 (105,487 bytes), 1190 x 1683 (439,103 bytes) and 2381 x 3367 (1,247,072 bytes), downloaded as a ZIP; each page also has its own Download button. Two things to know: it has no quality or KB setting, so you'll still need one of the steps above to get under a limit, and its JPEGs say 72 DPI in the header at every scale even though the pixels match the scale you picked. The page says it can't open password-protected PDFs. After I picked the file, the only network requests were the page's own renderer script and fonts and a 340-byte analytics ping: toolocean.co/pdf-to-images.

Drafted with AI help, tested and checked by me.

Top comments (0)