Benchmark11 min read

I ran a real photo corpus through every format this site outputs

Every format comparison I could find online quotes the same handful of numbers, and none of them say where the numbers came from. So I pointed our own conversion pipeline at 46 real images, 477 megapixels of them, and encoded every one into every format this site can produce. Below is the whole table, the method, and the three results that contradicted what I expected, including one that says something unflattering about our own default settings.

The corpus

Format benchmarks usually run on a handful of famous test images, which is how you end up with advice that falls apart on a screenshot. I wanted the mix a converter actually sees, so the corpus is 46 files off my own machine, sorted into six categories by what they are rather than by what extension they carry:

CategoryFilesAvg sizeSource formatTotal
iPhone HEIC812.2 MPHEIC7.5 MB
Phone photos811.5 MPJPEG18.6 MB
Detailed photos89.3 MPPNG29.6 MB
Flat graphics818.4 MPPNG21.4 MB
Screenshots65.0 MPPNG10.7 MB
Transparency84.5 MPPNG1.3 MB

Categories assigned by inspection, not by extension: colour count on a downsampled copy separates flat artwork from photographs far more reliably than the file name does, and the transparency group is files with a genuinely non-opaque alpha channel rather than files that merely have one.

Every file was decoded once to raw pixels, and every encoder ran from that same buffer. That matters more than it sounds: if you encode PNG from a fresh decode and JPEG from a pipeline that has already been resized or rotated, you are comparing two different images and calling it a format comparison.

What was measured

Two settings for each lossy format, because they answer different questions. The site column is what SwiftConverter did when this was measured: quality 100, and WebP in lossless mode. Both settings have since changed, for the reason findings 3 and the JPG rows below make plain; the columns are kept as they were run. The web column is what people usually mean when they say “convert this for my website”: quality 80. Alongside every size sits a PSNR figure, computed by decoding the result back to pixels and comparing it against the source, so “lossless” is a measurement here and not a claim.

Apple M1, 8 cores, 8 GB, macOS 26.3
node 24.13.1, sharp 0.35.3, libvips 8.18.3, heic-convert 2.1.0

node scripts/measure-formats.mjs <corpus-dir> --json results.json

The whole corpus, every format

All 46 images, 89.0 MB of source, encoded eight ways.
FormatTotalvs sourceMedianPSNRms/image
PNG299.9 MB+237%3,679 KBlossless200
JPG site (q100)124.0 MB+39%2,356 KB49.9 dB77
JPG web (q80)30.1 MB-66%629 KB42.3 dB45
WebP site (lossless)110.7 MB+24%1,917 KBlossless4,347
WebP web (q80)17.4 MB-81%275 KB42.1 dB518
AVIF (q50)8.9 MB-90%168 KB43.9 dB2,143
GIF (256 colours)117.9 MB+32%1,638 KB48.1 dB2,344
PDF34.7 MB-61%774 KBn/a547

Totals rather than an average of per-image ratios, so one 84 KB logo does not swing the result as hard as a 12 megapixel photo. PSNR is the mean over images where it is defined; lossless means every one of the 46 came back pixel-identical. PDF has no PSNR because imageToPdf embeds a JPEG, and pulling it back out would measure our PDF writer rather than the format.

Three things in that table are worth stopping on: PNG nearly quadruples the corpus, our own lossless WebP setting is the slowest thing on the list by a factor of eight, and AVIF at quality 50 lands at a tenth of the size with a higher average PSNR than JPEG at quality 80.

Finding 1: HEIC is far better than anything replacing it

The single most dramatic column in the whole run is the HEIC one, and it explains why so many people are unhappy after converting their photo library.

8 iPhone HEIC files, 7.5 MB of source, 12.2 MP average.
TargetTotalvs sourceMedianPSNR
PNG90.2 MB+1,108%13,497 KBlossless
GIF40.0 MB+436%5,109 KB42.4 dB
WebP lossless31.5 MB+322%4,227 KBlossless
JPG q10028.4 MB+281%3,782 KB56.3 dB
PDF8.4 MB+12%872 KBn/a
JPG q807.2 MB-4%698 KB44.8 dB
WebP q804.2 MB-44%275 KB42.6 dB
AVIF q502.0 MB-74%168 KB41.3 dB

Sorted by size rather than by format family, because the ranking is the finding. HEIC decoded through heic-convert at quality 1.0, then encoded from the resulting pixels.

The same eight photos, as stored by the phone and as eight different conversions.
HEIC (source)7.5 MB
AVIF q502.0 MB
WebP q804.2 MB
JPG q807.2 MB
PDF8.4 MB
JPG q10028.4 MB
WebP lossless31.5 MB
GIF40.0 MB
PNG90.2 MB

Bar length is total bytes across the eight files. The source bar is emphasised because it is the reference, and PNG because it is the result worth remembering.

Look at the JPG q80 row. Eight HEIC files at 7.5 MB became 7.2 MB of JPEG, a 4% saving, at 44.8 dB. In other words HEIC at Apple's default settings is holding roughly the same amount of data as a quality-80 JPEG of the same photo, which is a genuinely good result for a format most people never chose. If you are converting HEIC because Windows will not open it and not because you need a smaller file, JPG is the honest target: same size, opens everywhere. If you want it smaller than it started, WebP cuts it roughly in half.

Finding 2: converting a photo to PNG is almost always wrong

“PNG is the high quality one” is the most expensive piece of folk wisdom in image formats. It is true and it is beside the point. PNG is lossless, so it preserves whatever it is handed, including all the noise and compression artefacts a photo already carries. Compressing noise losslessly is the worst case for any encoder.

PNG output as a percentage of the source, by category.
CategorySourceAs PNGChange
iPhone HEIC7.5 MB90.2 MB+1,108%
Phone photos (JPEG)18.6 MB132.4 MB+610%
Detailed photos (PNG)29.6 MB43.5 MB+47%
Screenshots (PNG)10.7 MB11.0 MB+3%
Flat graphics (PNG)21.4 MB21.7 MB+2%
Transparency (PNG)1.3 MB1.1 MB-17%

The PNG-to-PNG rows are a re-encode at compressionLevel 6, which is what our pipeline uses. A source PNG saved by a tool using level 9 will grow slightly on the way through; that is the +47% and +3% here, not a defect in PNG.

There is exactly one row where PNG wins, and it is the row where PNG is the only candidate: images with real transparency. Everywhere else, the honest advice is that PNG is a delivery format for graphics and a storage format for masters, not a quality upgrade for a photograph. If you already have PNGs and want them smaller, WebP is the direct swap, and it keeps the alpha channel.

The PNG-to-PNG rows also carry a smaller lesson about our own tool. Re-encoding at compression level 6 grew the detailed-photo group by 47%, because those files had been saved by something more aggressive. Level 6 is a deliberate speed trade, but it means “convert PNG to PNG” is not a no-op here, and it is not always in your favour.

Finding 3: our lossless WebP default costs more than it is worth

This is the result I did not want. SwiftConverter encodes WebP in lossless mode, which sounded principled when it was written: you asked for a conversion, not a quality reduction, so we do not silently throw pixels away. The numbers say that principle is expensive.

WebP lossless against WebP quality 80, same images, same run.
CategoryLosslessq80Size ratioLossless ms/img
Phone photos43.7 MB4.3 MB10.2x8,020
iPhone HEIC31.5 MB4.2 MB7.5x6,672
Flat graphics12.1 MB5.6 MB2.1x4,758
Detailed photos17.0 MB2.0 MB8.4x3,883
Screenshots5.9 MB0.9 MB6.4x1,815
Transparency0.5 MB0.3 MB1.4x300

Encode time is per image on an M1, single pass, excluding decode. The whole 46-image corpus took 200 seconds in lossless WebP and 24 seconds at quality 80.

Eight seconds per phone photo, to produce a file 10 times larger than the quality-80 version that measured 41.1 dB. Nobody converting a holiday photo to WebP wants that trade, and on a 25 MB upload it is most of a request budget spent making the file worse for the purpose the user had in mind. The place lossless earns its keep is the transparency row, where the ratio collapses to 1.4x and the encode is fast because the images are small and flat.

Finding 4: AVIF wins on bytes and loses on seconds

AVIF at quality 50 produced the smallest output in all six categories, by a wide margin, while scoring a higher mean PSNR (43.9 dB) than JPEG at quality 80 (42.3 dB). On screenshots it hit 45.4 dB at 95% smaller than the source. On transparency it hit 54.1 dB at 88% smaller. It is not close.

The cost is time. AVIF averaged 2,143 ms per image against 45 ms for JPEG, roughly 48 times slower, and 99 seconds for the corpus. For a build step or a one-off export that is irrelevant. For a web request with someone waiting, it is the difference between a tool that feels instant and one that feels broken, which is why AVIF is not currently on the format list here. The honest summary is that AVIF is the best format in this benchmark and the worst fit for this product.

Finding 5: GIF is not what you remember

GIF scored 48.1 dB on average, which is higher than JPEG at quality 80, and that surprised me until it did not. GIF quantises to 256 colours, and on flat artwork 256 colours is often simply enough: screenshots came back at 58.0 dB and transparency at 68.0 dB, both close to visually perfect. Feed it a photograph and it collapses, at 38.9 dB on phone photos while being 142% larger than the JPEG source.

So GIF is a fine still format for exactly the content people no longer use it for, and a terrible one for photos. Its real remaining job is animation, which is why the only place it appears prominently on this site is turning an animated SVG into an animated GIF.

The thing that broke: sharp will not open an iPhone photo

A benchmark is mostly plumbing, and the plumbing failed in an interesting way. Our image pipeline is sharp, which handles every format here. It cannot read the HEIC files. Not “does not support”: it reads the container, starts parsing, and refuses.

Input buffer has corrupt header: heif: Invalid input:
Security limit exceeded: Number of references in iref box (25)
exceeds the security limits of 16 references. (2.1000)

That is a denial-of-service hardening limit in libheif, and it fires while parsing the file structure, before any decoding is attempted. The file is an ordinary photo from an ordinary iPhone, and every Apple device opens it without comment. The same buffer handed to heic-convert, a pure JavaScript decoder, came back as a 2,554 by 2,554 image in about a second.

Twenty-five references against a limit of sixteen. Chasing that number down turned out to be the most interesting thing in the whole benchmark, and it has nothing to do with codecs: it is about how an iPhone stores a photograph. That, and the licensing reason your browser will not open one, is the next article.

What this does not tell you

  • PSNR is not your eyes. It measures squared pixel error, which punishes a slight global shift more than it punishes a nasty local artefact. It is the right tool for proving losslessness and a blunt one for ranking two lossy encoders that both score in the low forties.
  • One machine, one run. Every timing is a single pass on an 8 GB M1. The ratios between encoders should travel; the absolute milliseconds will not.
  • The corpus is mine, and so is the repository. These are my own files, so the images could not ship with the harness even if the repository were public, and it is not. You cannot reproduce this exact table. What travels is the method: the harness takes any directory, so the check worth running is the same one against your own photos.
  • Alpha was flattened before encoding. Every source was reduced to three channels so that all eight encoders were handed identical pixels. The transparency category therefore measures how each format compresses that artwork, not how well it preserves an alpha channel.

What I actually changed my mind about

I went in expecting the interesting result to be WebP versus AVIF. It was not. The interesting results were that our own lossless default is a bad fit for the most common thing people convert, that PNG is a trap for anyone who has been told it is the quality option, and that HEIC is quietly doing a better job than most of the formats people replace it with.

If you want one rule out of 477 megapixels of measurement: convert for the destination, not for the word “quality”. Sending a photo somewhere that will not take HEIC means JPG. Putting a graphic on a website means WebP. Choosing PNG for a photograph means a file six to eleven times larger that no human being can tell apart from the original.

Try it on your own files

Most image conversions run in your browser and never leave your device.

Open the converter

Read next

The attachment limit is not the number you were told