Measured: choosing the JPG quality setting
The JPG quality slider on the converter runs from 10% to 100%. Where should it stop? We took two real photographs through the site's own conversion pipeline at five settings and measured size, peak signal-to-noise ratio and mean colour difference. Every figure below is measured, and the scripts to reproduce it are in the repository.
How we measured
To keep the results tied to real usage, the whole run went through the site's own conversion pipeline with nothing simulated: a headless browser opened the converter page, the .heic file was handed to it, the quality slider was moved, convert was clicked, and the genuine output file was collected.
- Source material: two publicly available photographs (Unsplash licence, fetched via picsum.photos), each 3200×2400 pixels.
- HEIC sample: encoded with HEVC at quality 90, standing in for an iPhone original.
- Settings tested: JPG quality 60%, 70%, 80%, 90% and 100%, with output dimensions unchanged.
- Size: the byte count of the actual output file.
- Quality: PSNR and mean colour difference, referenced against the pixels decoded from the HEIC.
- Environment: headless Chrome, the page opened locally with the network disconnected; libheif for the reference decode.
The three scripts used are in tools/testkit/ (bench_make_heic.py, bench_run_quality.js and bench_report.py). Swap in your own photograph and re-run to produce the same table.
Size: what each step up costs
| JPG quality | Sample A size | A vs HEIC | Sample B size | B vs HEIC |
|---|---|---|---|---|
| 60% | 516.4 KB | 33% | 610.9 KB | 28% |
| 70% | 569.3 KB | 36% | 683.1 KB | 31% |
| 80% | 620.1 KB | 40% | 740.2 KB | 34% |
| 90% | 718.5 KB | 46% | 866.6 KB | 39% |
| 100% | 2265.1 KB | 144% | 2961.5 KB | 134% |
Both samples behave the same way, and two things stand out:
- Between 60% and 90% it is a gentle slope — from 516 KB to 718 KB, about 39% more. This is the normal trade of a little size for a little quality.
- From 90% to 100% it is a cliff — the size jumps to 3.3 times. At quality 1.0 the browser maps the value to the encoder's top setting, quantisation collapses, and compression effectively stops happening.
Image quality: what PSNR says
| JPG quality | Sample A PSNR | Sample B PSNR | Mean colour difference | Pixels differing by more than 2 levels |
|---|---|---|---|---|
| 60% | 41.8 dB | 39.2 dB | 1.40 / 1.76 | 9.7% / 14.3% |
| 70% | 45.7 dB | 44.3 dB | 0.81 / 0.94 | 2.0% / 4.2% |
| 80% | 47.2 dB | 45.7 dB | 0.60 / 0.69 | 1.0% / 3.2% |
| 90% | 49.3 dB | 47.7 dB | 0.41 / 0.51 | 0.09% / 1.3% |
| 100% | 59.3 dB | 57.6 dB | 0.07 / 0.10 | 0.00% / 0.00% |
This also validated one assumption: PSNR at the 100% setting came out at 59.3 dB, a very high figure. That means the pixels decoded by the browser pipeline and by the Python-side libheif reference agree closely — the two implementations introduce no colour management drift — so the column above can be read as the true loss against the original.
How to read these numbers
PSNR is the peak signal-to-noise ratio: higher means closer to the original. As a rough scale:
- Above 45 dB — no discernible difference at normal viewing distance.
- 40 to 45 dB — a very slight difference may become visible at 100% zoom.
- 35 to 40 dB — block artefacts become noticeable on close inspection, especially across smooth gradients.
- Below 35 dB — clearly visible, and no longer suitable for photos you intend to keep.
Closer to human perception is the last column: the share of pixels differing by more than two colour levels. A two-level difference is imperceptible to the eye in virtually all situations, so lower is better. At 90% it is 0.09% for sample A; at 60% it approaches 10%.
Conclusions and recommendations
| Use case | Recommended quality | Reasoning |
|---|---|---|
| Everyday use (the default) | 90% | 48–49 dB at about a third of the size of the top setting. The default is well chosen |
| Web images and social sharing | 80% | Another 15% off the size, still 46–47 dB and firmly in the indistinguishable range |
| Size first, minor loss acceptable | 70% | Around 45 dB, the edge of what the eye tolerates; below this it degrades noticeably |
| No human viewer involved | 60% or lower | Nearly 10% of pixels differ visibly — not recommended for photos worth keeping |
| — | 100% | Not recommended: 3.3 times the size for about 10 dB, and that range is already beyond what the eye can resolve |
There is also a better lever than quality for reducing size: scale down first. Pixel count scales with area, so reducing the longest edge from 3200 to 1600 quarters the pixels and roughly quarters the file — whereas dropping quality from 90% to 60% saves only about half, and does so with a visible quality cost. The output size options on the converter do exactly this.
One less intuitive finding: the JPGs from these samples ended up smaller than the source HEIC (39%–46% of it at 90%). The reason is that the source photographs had already been JPEG-compressed once, and the HEIC merely preserved those existing artefacts at high fidelity. HEIC's size advantage comes from encoding raw pixels in the first place — that is, when the camera captures the photo. Re-encoding an already-compressed image does not reproduce that advantage.
Cite this data
Every figure on this page is measured, produced by the scripts in tools/testkit/ — nothing here is estimated. You are free to reuse it; just credit the source and link back to this page.
Citation format
HEIC to JPG quality benchmark (2026-10-14). HEIC to JPG, https://heic.xunidd.com/guide/benchmark/
Data table (Markdown)
| JPG quality | Sample A size | Sample A PSNR | Sample B size | Sample B PSNR |
| --- | --- | --- | --- | --- |
| 60% | 516.4 KB | 41.8 dB | 610.9 KB | 39.2 dB |
| 70% | 569.3 KB | 45.7 dB | 683.1 KB | 44.3 dB |
| 80% | 620.1 KB | 47.2 dB | 740.2 KB | 45.7 dB |
| 90% | 718.5 KB | 49.3 dB | 866.6 KB | 47.7 dB |
| 100% | 2265.1 KB | 59.3 dB | 2961.5 KB | 57.6 dB |
How to reproduce
The three scripts are in tools/testkit/ and run in order: bench_make_heic.py → bench_run_quality.js → bench_report.py. The first encodes a photograph to HEIC and writes a reference PNG; the second drives the real converter page in a headless browser, stepping through each setting and collecting the output; the third computes PSNR, mean colour difference and the share of differing pixels. bench_report.py also accepts a --selftest flag that pins the PSNR calculation against fixed inputs, so the metric cannot quietly regress.
Terms of use: attribution with a link is all that is required — no permission needed in advance. The samples are real photographs chosen to stand in for HEIC files straight off an iPhone, so absolute numbers shift with the texture complexity of the scene. That is exactly why samples A and B differ systematically: the busier image loses more.