Why Most Compressors Can't Hit 50KB
The form says “photo must be under 50KB”. You drop one in, the tool hands back 178KB. So you lower the quality and try again — this time 31KB, so soft you can barely recognise it. Four or five round trips later you submit an image you are neither sure is compliant nor sure is legible.
That is not your fault. It is how most compressors work.
The common approach: guess once, retry if it misses
The logic of most online compressors is a single encode: resize once by some preset rule, compress once at some fixed quality, hand you the result. They never converge on your target size — because they have no idea which direction to adjust in.
The underlying conflict is that the final size is governed by two variables at once:
- Resolution — more pixels, bigger file
- Quality — higher quality, bigger file
These two trade against each other. The same 50KB can be “large resolution + low quality” or “small resolution + high quality”. A single encode picks exactly one point on that curve, so of course it misses.
Measured: one-shot vs two-stage search
I generated a synthetic 2400×1600 photo (gradients plus noise, so it compresses about as hard as a real photograph) and ran both approaches locally:
| Target | One-shot (common defaults: fixed 1920 width, quality 80) | Two-stage search |
|---|---|---|
| No limit | 255.3KB | — |
| 20KB | unreachable | 1560px wide / quality 43 / 18.0KB |
| 50KB | unreachable | 2040px wide / quality 40 / 47.7KB |
| 100KB | unreachable | 2400px wide (original resolution) / quality 41 / 99.4KB |
The left column is the whole point: compressed at generic settings, the result is 255KB — it misses all three targets, 20 / 50 / 100KB, and it never tells you how far off you are.
The right column is what Pic2KB does instead:
- Find the largest resolution that still fits — probe downward until you hit the point where one step higher overflows
- Then find the highest usable quality at that resolution — binary search toward the boundary, wasting no bytes
Methodology: the numbers above were produced locally with the libvips encoder. Pic2KB runs the same search strategy in the browser via Canvas, so exact values shift with image content and encoder. For real photos the advice is: test your own image, don’t trust any “universal setting”.
Why it protects resolution before quality
Seeing “quality 40” in that table may make you hesitate: is that even viewable?
There is a reality here that is easy to miss — most situations that cap file size also secretly impose a floor. Visa photo specs require a minimum pixel dimension. Exam registration systems validate resolution server-side and reject anything too small. In those cases “not enough pixels but each pixel very clean” is fatal, while the reverse still leaves room.
So the default strategy is: keep as many pixels as possible, then spend whatever budget is left on quality. That is also why, at a 100KB target, it can preserve the original 2400px resolution untouched.
(If what you actually want is “small image + high quality”, that is a different objective function — and it is adjustable.)
Why this can run entirely in the browser
There is no shortcut on size: a two-stage search has to encode repeatedly. Do it on a server and you upload the original and wait. Do it in the browser and the entire round trip disappears.
The side effects are worth listing: photos never leave your device (privacy risk goes to zero), there is no server cost (which is why it can stay free), and the most stubborn limits vanish — no maximum file size, no waiting queue.
One byproduct worth knowing about: re-encoding strips EXIF data, including things you did not know were in there — capture time, and GPS coordinates.
When it doesn’t fit, say so
One last thing that I think matters most and is most often skipped:
Some targets are genuinely unreachable. A photo dense with detail cannot be squeezed into 8KB at maximum compression. At that moment there are two options: quietly hand back an image that is still over the limit (and let the submission fail on you), or tell you plainly “this image cannot fit into ××KB even at maximum compression” while still giving you the closest achievable result.
We chose the second. The value of a tool is not pretending every attempt succeeds — it is letting you know where the boundary is when it fails.