Lossy vs Lossless Compression: When to Use Each
The first time I had to argue about compression in a serious meeting, it was over a 14 MB hero image a designer wanted in a marketing email. I had compressed his original PSD into a 280 KB JPEG that, at email viewing distance, looked identical to me, identical to him, identical to the QA team, and identical to the three other people we asked. The mail client could still tell the difference between 14 MB and 280 KB. The campaign shipped because we picked the smaller file.
That is the whole question of compression in one sentence. It is never "which is better." It is "what is the smallest file your audience will not notice?"
Most engineers I work with treat compression as a checkbox somewhere in sips, ffmpeg, or Photoshop. The defaults usually work, so nobody bothers reading the underlying papers, and that is fine until you ship at CDN scale, hand a file to a print shop, or watch a 30 MB PNG ruin a Lighthouse score. Then the defaults are not good enough anymore, and you need a real model of what is actually happening to your bytes.
Table of Contents
This post is the reference I wish I had been handed on day one. The theory under the hood, the math that matters in production, and the decisions that come up when "just compress it" stops being a sufficient answer.
The Two Worlds
Every compression algorithm in existence belongs to one of two camps.
Lossless algorithms guarantee that decompressing the output gives you back the exact original bytes. Bit for bit. PNG, FLAC, ZIP, gzip, Brotli, lossless WebP, and the Apple ProRes family all live here. If the input was the integer 42, the output is the integer 42, every time.
Lossy algorithms throw away information you are unlikely to notice. They produce smaller files at the cost of mathematical fidelity to the original. JPEG, MP3, AAC, H.264, AV1, and lossy WebP all live here. The output of a lossy round trip is visually or audibly close to the input, but it is no longer the same file.
The interesting design fact is that lossy compression is not a hack. It is a deliberate exploitation of the gap between what humans can perceive and what a sensor can record. JPEG does not throw away pixels. It throws away the parts of each pixel that the human visual system is bad at seeing. That is what makes it so much more efficient than any lossless scheme could possibly be.
If you take one thing from this post: lossless is bounded by entropy, lossy is bounded by perception. Those are different limits. Different limits give you different best-case ratios.
How Lossy Compression Actually Works (JPEG as the case study)
Almost every lossy image format follows the same four-step recipe that JPEG codified in 1992. The details have improved (AVIF replaces DCT with a more clever transform, JPEG XL adds variable-block encoding) but the architecture is the same.
Step 1: Color space conversion
The image is converted from RGB to YCbCr. Y is brightness (luma). Cb and Cr are color difference channels (chroma). The split exists because the human eye is much sharper at detecting brightness changes than color changes. Your retina has roughly 6 million cones (color) and 120 million rods (brightness). The format follows the biology.
Step 2: Chroma subsampling
Because the eye is bad at detecting fine color detail, JPEG can throw away three-quarters of the chroma channel before anyone notices. A 4:2:0 subsampling, which is the default in most encoders, keeps full luma resolution but stores one Cb and one Cr value per 2x2 pixel block. That is a 50% size reduction with almost no perceptual cost on photographs.
This is also why JPEG is a terrible choice for screenshots of code. Code is high-contrast text, which is mostly luma edges. When the chroma channel goes to half resolution, anti-aliased text edges acquire a faint colored halo. Your eye notices immediately because text is exactly the kind of high-frequency detail the format was designed to discard.
Step 3: Discrete Cosine Transform (DCT)
The image is broken into 8x8 pixel blocks. Each block is transformed from the spatial domain (pixel values) into the frequency domain (cosine waves). The result is 64 coefficients per block: one DC coefficient (the block's average value) and 63 AC coefficients (how much each frequency contributes).
The transform is mathematically lossless. No information has been thrown away yet. What it has done is separate low-frequency content (smooth gradients) from high-frequency content (fine detail). Now we can throw away one and not the other.
Step 4: Quantization (where the lossy part actually happens)
Each of those 64 coefficients is divided by a quantization value and rounded to the nearest integer. The quantization values come from a quality table. Higher frequencies get bigger divisors. Bigger divisors mean more zeros after rounding. Zeros are extremely cheap to encode.
This is the entire trick. JPEG does not delete pixels. It rounds frequency coefficients toward zero, throwing away high-frequency detail first because that is the part the eye is least sensitive to. The "quality" slider in your image editor is just a multiplier on the quantization table.
A few practical implications fall out of this directly:
- Quality 80 is almost always the right answer for photographs. Below 75 the rounding gets aggressive enough to produce visible artifacts (the famous "blocky" look at 8x8 boundaries). Above 90 you are spending bytes for detail nobody can see at typical viewing distances.
- Sharp edges are expensive. A solid red square next to a solid blue square has a near-infinite frequency at the boundary. JPEG handles that by smearing the edge across multiple blocks. This is why text screenshots, logos, and pixel art belong in PNG.
- Smooth gradients are cheap. A sunset has almost no high-frequency content. JPEG eats sunsets for breakfast.
That is also the source of the most common JPEG mistake I see in production: shipping a logo or icon as JPEG. The format is mathematically wrong for the content. The artifacts are the format doing exactly what it was designed to do.
How Lossless Compression Actually Works (PNG and DEFLATE)
Lossless compression cannot reach JPEG-level ratios because it has no perceptual budget to spend. Everything has to come back. The best it can do is exploit redundancy: the parts of the file that are predictable from the parts you have already seen.
PNG: filters plus DEFLATE
PNG runs a two-stage pipeline. First, it applies a per-row "filter" that replaces each pixel with the difference between it and a predicted value, usually the pixel above, the pixel to the left, or the average of both. On a smooth gradient, that turns a sequence of values like 127, 128, 129, 130 into 127, 1, 1, 1. Most of the bytes are now small or zero, which compresses much better.
Then DEFLATE runs over the filtered data. DEFLATE is two ideas glued together:
- LZ77 scans for repeated byte sequences and replaces later occurrences with a back-reference: "go back 240 bytes and copy 12 bytes." This is why repetitive content (a screenshot with large flat regions, a code listing with the same indentation everywhere) compresses dramatically.
- Huffman coding assigns shorter bit patterns to common bytes and longer patterns to rare ones. Frequent symbols become 3 bits, rare symbols become 12 bits, total file size drops.
The same algorithm powers gzip, ZIP, the HTTP Content-Encoding: deflate header, and .zip archives generally. When people say "ZIP a folder," they are running DEFLATE over a tar-like manifest of files. Modern variants (Brotli, Zstandard) replace LZ77 with smarter dictionary-matching strategies but the core idea is the same: find redundancy, encode it once.
The ratios are bounded by Shannon entropy. You cannot compress random data losslessly. If somebody hands you a file that is already JPEG, MP3, or encrypted, throwing it into ZIP buys you almost nothing. The randomness has been spent.
Why "compress my JPEG with PNG" produces a bigger file
This is the question I have been asked more times than any other. Someone exports a photograph as JPEG, loads it in an editor, and re-saves as PNG hoping for a smaller file. The result is usually 4x larger. The reason is straightforward: JPEG already compressed the image lossily. PNG has to encode the result of that compression losslessly, including all the artifacts. There is no redundancy left to exploit, and the lossless format pays a header tax on top.
The mental model that fixes this for good: lossy formats reduce information, lossless formats reduce redundancy. Once information has been removed, redundancy is also gone. You cannot get it back.
Generation Loss (Why Saving Twice Is Worse Than Saving Once)
Open a JPEG in your photo editor. Add a tiny tweak. Save it again at the same quality setting. Repeat ten times.
The image will look noticeably worse than the original. This is generation loss, and it is mechanical, not anecdotal. Every save runs the quantization step again, and the quantization step is not idempotent. Round 0.51 to 0, then re-round 0 toward something else, and you do not get back to 0.51. Each round-trip throws away a small amount of detail that the format already considers expendable.
Lossy video formats have the same property, which is why every codec engineer obsesses over the "intra-frame" reference. Each generation of re-encoding compounds the loss. If you have ever wondered why your favorite meme looks like it was photographed off a 1998 CRT, the answer is that it has been re-saved and re-shared dozens of times, and JPEG quantization compounds.
The defensive practice is simple. Keep a lossless master (PNG, TIFF, the original RAW). Export a lossy delivery copy. Never edit the delivery copy. If you need to make a change, go back to the master.
Audio and Video, Same Pattern
The image case generalizes neatly.
MP3 and AAC do for audio what JPEG does for images. They convert from time domain to frequency domain (via MDCT, a DCT cousin), then exploit psychoacoustic masking: the fact that a loud sound at one frequency makes nearby quieter sounds inaudible. The encoder allocates bits where the ear can hear, and zeros where it cannot. FLAC is the lossless counterpart, and on typical music it lands at 50-60% of the original size, where MP3 at 192 kbps lands at 10-15%. The factor of three is the perceptual budget.
H.264, H.265, AV1 stack lossy image compression on top of motion estimation. Most frames are encoded as differences from a nearby reference frame, because adjacent video frames are almost identical. The encoder finds blocks that "moved" between frames and stores a motion vector instead of the block. The residual (what the prediction got wrong) goes through the same DCT-and-quantize pipeline that JPEG uses. AV1 simply does this with smarter prediction and a more efficient transform. Everything else is the same architecture.
ZIP and tar.gz are pure lossless. They have to be. You cannot perceptually round a binary executable.
Real-World Bandwidth Math
This is where the abstract decision becomes a budget line.
Suppose you serve a 2 MB hero image to 100,000 daily visitors. That is 200 GB of egress per day, or roughly 6 TB per month. Egress on most CDNs runs $0.02 to $0.08 per GB depending on region and tier. Call it $0.05 average.
- 2 MB PNG: 6 TB/month, ~$300/month
- 280 KB JPEG (quality 80): 840 GB/month, ~$42/month
- 180 KB AVIF (similar quality): 540 GB/month, ~$27/month
That is the same image, the same audience, the same perceived quality, and a 10x difference in bill. Multiply across an entire site of images and the difference between "we ship lossless because it is safer" and "we ship lossy at the right quality" is a real number on a real invoice.
The math also runs the other way for users on mobile. A 2 MB image on a 4 Mbps connection takes four seconds to load. The same image at 280 KB takes 0.6 seconds. Lighthouse penalizes you for the difference. So does your bounce rate.
A Decision Matrix That Holds Up
After enough production fights, the rules collapse to a small table.
| Content | Use | Why |
|---|---|---|
| Photographs, screenshots with photos | JPEG q80, AVIF, or WebP lossy | Perceptual budget is huge, ratios are 10-20x |
| Logos, icons, charts, diagrams | PNG (or SVG if vector) | Hard edges, flat colors, lossless required |
| Screenshots of text or code | PNG | High-frequency luma, JPEG produces visible halos |
| Animations, short loops | WebP, AVIF, or H.264 MP4 | GIF is structurally lossless but absurdly inefficient |
| Audio masters | FLAC or WAV | Edit lossless, deliver lossy |
| Audio delivery | AAC at 128-192 kbps | MP3 still works, AAC is better at the same bitrate |
| Video delivery | H.264, H.265, or AV1 | Pick by client compatibility, not pride |
| Documents and code | gzip, Brotli, Zstandard | Lossless required, redundancy is high, ratios are excellent |
| Already-compressed binary | Do not recompress | No redundancy left, you are paying overhead for nothing |
The decision is almost always driven by the content type, not by personal preference. The format follows the data.
The Mistakes I See Most Often
A short list, because they keep coming up in code review and asset audits.
- Saving icons and logos as JPEG. The format is mathematically wrong for hard-edge content. Use PNG or SVG.
- Saving photographs as PNG "for quality." PNG cannot exploit perceptual redundancy. The file will be 5-15x larger for no visible benefit.
- Re-encoding a lossy file as lossy. Generation loss is real. Always edit the master.
- Zipping JPEGs to "make them smaller." Already compressed. ZIP saves bytes only on the directory structure.
- Lossless WebP for photos. It exists, but it is almost never the right choice. Use lossy WebP or AVIF instead.
- Quality 100 JPEG. This produces enormous files for negligible perceptual gain over quality 90. The quantization table is still applied; you are just spending bits on coefficients nobody can see.
Closing Thoughts
Lossy compression is not a degradation. It is a deliberate exchange of mathematical fidelity for the parts of a file your audience cannot perceive. Lossless compression is not "safer." It is a different tool with a different ceiling. The interesting engineering happens when you stop thinking of them as good and bad, and start thinking of them as suited or unsuited to the content.
The same byte that ruins a logo is invisible inside a photograph. The same algorithm that compresses a sunset to 5% of its original size makes a screenshot of code unreadable. There is no universal "best." There is only a match between what is in the file and how the algorithm decides what to throw away.
If you take one practical habit from this post: keep masters lossless, deliver lossy, and never edit the delivery copy. Every other rule in the table above is a corollary.
If you want to see the difference yourself, the StackConvert image converter lets you round-trip the same source through JPEG, PNG, WebP, and AVIF in the browser and compare the file sizes side by side. The PDF compressor and ZIP creator cover the same trade-offs for documents and archives. The bytes do not lie.
What is the worst compression decision you have inherited from a previous developer or designer?