Why some files come back the same size — when our compressor returns the original
Drop a file into the compressor, hit go, and sometimes the result is "0% smaller — original returned". This is intentional. The pipeline contains several guards that detect when re-compression is pointless or harmful and short-circuit to handing back the input unchanged. Knowing which guard fired explains the size that comes out.
Guard 1: JPEG already at target quality
Before re-encoding a JPEG, we read its existing quantization tables and back-compute its quality (covered in detail in the JPEG quality detection article). If the source's measured quality is already at or below the slider value, we skip the re-encode entirely.
The reasoning: re-encoding a quality-72 photo at slider quality 80 would produce a file that's bigger AND a generation worse. Both axes go the wrong way. Recompressing only makes sense when the source is at higher quality than the target.
This guard fires often. About 30% of real-world JPEG inputs hit it — many photos people upload have already been compressed by a phone, social-media platform, or messaging app, and arrive at quality 65–78.
Guard 2: PNG already palette-quantized
If the input is a palette PNG with fewer than 256 colours in its PLTE chunk, the size is dominated by the deflate-compressed pixel grid. Re-running palette quantization wouldn't help (the palette is already the small one). Re-running deflate optimisation might gain 1–2%, but the cost of the full decode/re-encode cycle isn't worth that small saving.
We detect this by reading the PLTE length: under 768 bytes (256 entries × 3 RGB bytes) means the palette is sub-256. We hand back the original file with a flag indicating no compression was done.
If you specifically want a deflate-optimised version of an already-palette PNG, the right tool is a dedicated PNG optimiser run separately. Our compressor is tuned for "make this meaningfully smaller", not "squeeze the last 1%".
Guard 3: GIF re-encode under 3% gain
GIF compression is mostly determined by the input file's existing palette and frame layout. A well-encoded GIF doesn't have much room for improvement. We try to compress it with the GIF entropy optimiser and palette reducer, then check the result:
savings = 1 − compressedSize / originalSize
if savings ≤ 0.03:
return original GIF unchanged
3% is the threshold. Below that, the compressed file is essentially the same size, and the output isn't byte-identical (which is jarring for users who expect "no compression" to mean "no changes"). Returning the original keeps modification times and exact bytes intact.
Guard 4: encoder produced something bigger
Sometimes — usually with already-heavily-compressed inputs — the encoder runs successfully and produces a "compressed" file that's actually larger than the source. This can happen when:
- The source uses non-standard quantization tables tuned for size that our standard tables can't beat.
- The source uses progressive JPEG layout, which is sometimes a few percent smaller than the baseline layout we encode to.
- The source has large embedded ICC profiles that our encoder copies into the output without reduction.
If output.length ≥ input.length, returning the larger output would be silly. We hand back the original.
Guard 5: format we can't process
The compressor accepts JPEG, PNG, WebP, GIF, BMP and ICO via the browser's native decoder, plus AVIF where the browser supports it. Inputs in any other format fail at the decode step before compression has a chance to run.
For HEIC, RAW formats (CR2, NEF, ARW), TIFF, PSD, and so on, we fall back to one of two paths. If the file can be decoded by a converter (HEIC, TIFF), we offer a converter route in the UI. If it can't (RAW formats), we ask you to convert to JPEG or PNG first in your photo editor.
How the skip path looks in the UI
When a guard fires, the file panel shows "Original (smallest)" or "0% reduction — already optimised". The download button still works, but the file you download is byte-identical to what you uploaded. We do this rather than display "compression failed" because for the user the outcome is the same: the file is already as small as we can make it without losing visible quality.
If you specifically want to force a re-encode (because you don't care about quality, or you want to strip metadata, or you want the file to be bit-different from the original for some workflow reason), you can override the slider to a lower quality. That bypasses the guards and runs the encoder unconditionally.
In batch processing
If you drop 50 photos at once, expect a meaningful fraction (often 20–40%) to come back unchanged. They aren't broken — they're files that were already at or below the requested quality target. The total bytes saved is what matters, and the skipped files contribute zero bytes saved either way. The other 60–80% deliver the bulk of the size reduction.