Lossless vs Lossy Compression: The Core Difference Explained

The Essence of Compression: Expressing the Same Information with Less Data

Before diving into the distinction between lossless and lossy compression, we need to understand what compression actually does.

At its core, compression is about expressing the same information with less data. Any piece of data—whether text, images, audio, or video—contains "redundancy." Redundancy refers to parts that can be removed without losing the meaning of the information. A compression algorithm's job is to identify and eliminate this redundancy.

Consider a simple example. The character string AAAAABBBCC occupies 10 bytes. But we can represent the same information more compactly by recording "each character and how many times it repeats consecutively," yielding 5A3B2C—only 6 bytes. The data size drops by 40%, yet the meaning is identical. This is the most primitive form of compression, known as Run-Length Encoding (RLE).

From an information theory perspective, Claude Shannon introduced the concept of "information entropy": the minimum average encoding length of a data stream is bounded by its entropy. No lossless algorithm can break this theoretical limit. This means that re-compressing already-compressed data yields almost no benefit—the redundancy has already been stripped away.

Understanding this essence reveals two fundamentally different technical paths: lossless compression strives for perfect fidelity, while lossy compression deliberately discards details that the human eye or ear cannot easily perceive, trading them for a much higher compression ratio.


Lossless Compression: Restoring Every Bit

The core promise of lossless compression is that the decompressed data is byte-for-byte identical to the original—not a single bit may differ. These algorithms eliminate only "statistical redundancy" and "structural redundancy," never touching the semantic content of the information.

DEFLATE: The Most Widely Used Lossless Algorithm

DEFLATE is the algorithm underlying ZIP, gzip, zlib, and many other tools. It elegantly combines two classic techniques:

  1. LZ77: Uses a sliding window to search for repeated substrings in already-processed data, replacing them with "distance + length" pointers. For example, the word "compression" appearing repeatedly in a text file can be replaced with a back-reference to its first occurrence.
  2. Huffman coding: Applies variable-length encoding to the symbol stream produced by LZ77. Frequently occurring symbols get short codes; rare symbols get long codes. This pushes the encoding closer to the entropy limit.

DEFLATE's strengths are its simplicity, speed, and universal compatibility—nearly every programming language's standard library includes an implementation.

LZMA: Higher Ratios Through Context Modeling

LZMA (Lempel-Ziv-Markov chain Algorithm) builds on LZ77 with a much larger sliding window (up to several GB), a more refined probability model, and range coding. Compared to DEFLATE, LZMA typically achieves higher compression ratios, at the cost of slower compression speed and greater memory usage. The 7z format is based on LZMA.

The key improvement in LZMA is that it does not rely on a static probability table. Instead, it dynamically predicts the probability of the next symbol based on context. This "context modeling" brings the encoding much closer to the theoretical entropy limit.

PNG Filtering: Preprocessing for Image Data

PNG is a lossless image format, but it does not apply DEFLATE directly to raw pixel values. Before compression, PNG applies a "filter" to each row of pixels to make the data more amenable to DEFLATE.

A common filter stores the difference between each pixel and its neighbor to the left, above, or upper-left. Since natural images have locally similar pixels, these differences tend to cluster around zero. This transformed data has higher redundancy, allowing DEFLATE to compress it far more effectively.

This also explains why ZIP cannot effectively compress JPEG images: JPEG is already highly compressed through DCT and entropy coding, leaving almost no statistical redundancy for DEFLATE to exploit. Running ZIP on a JPEG typically adds a few bytes of header overhead with no size reduction.


Lossy Compression: Trading Below the Perception Threshold

The central idea of lossy compression is that human perception has limits. If the discarded details fall below the perceptual threshold, the visual or auditory difference is negligible—but the data reduction can be enormous.

DCT: The Mathematical Foundation of JPEG

The Discrete Cosine Transform (DCT) is the heart of JPEG image compression. Its role is to convert an image from the "spatial domain" to the "frequency domain."

In the spatial domain, an image is represented by pixel brightness values. In the frequency domain, the image is decomposed into a sum of cosine wave components at different frequencies: low-frequency components represent large smooth areas, while high-frequency components represent edges and fine detail.

The DCT itself is reversible and loses no information. The actual "loss" happens in the next step—quantization.

Quantization: The Source of Loss

Quantization maps high-precision DCT coefficients to a limited set of discrete values. In practice, each coefficient is divided by a value from a quantization table and then rounded to an integer. Because the human eye is less sensitive to high-frequency detail, the quantization table applies larger divisors to high-frequency coefficients, causing many of them to become zero.

This step causes irreversible information loss—once a coefficient is rounded to zero, it cannot be recovered. But it also creates massive compression opportunity: long runs of zeros can be encoded very efficiently with run-length encoding.

Designing the quantization table is an art: larger divisors yield higher compression but more visible quality loss. This is exactly what the JPEG quality parameter (e.g., quality=80) controls—it scales the quantization table up or down.

Inter-Frame Prediction: The Key to Video Compression

Video compression goes a step beyond still images. Consecutive frames in a video often change very little (for example, a static background with a moving person), so there is no need to store every frame in full.

Inter-frame prediction uses "motion estimation" to find the displacement between the current frame and a reference frame, storing only "motion vectors" and "residuals." This elimination of temporal redundancy allows video compression ratios to reach hundreds or even thousands to one—far beyond what single-frame image compression can achieve.


Lossless vs Lossy: Comparison Diagram

The flowchart below illustrates the core branches and typical applications of the two compression families:

流程图 1

DCT Principle Diagram

The diagram below simplifies how DCT transforms an 8x8 pixel block from the spatial domain to the frequency domain, then preserves low frequencies while discarding high frequencies through quantization:

流程图 2

Code Examples

Lossless Compression with zlib


import zlib

# Original text data with heavy repetition
original = b"compression compression compression " * 50

# Compress
compressed = zlib.compress(original, level=9)
print(f"Original size: {len(original)} bytes")
print(f"Compressed size: {len(compressed)} bytes")
print(f"Ratio: {len(original) / len(compressed):.2f}x")

# Decompress and verify the data is identical
decompressed = zlib.decompress(compressed)
assert decompressed == original, "Data mismatch!"
print("Verification passed: decompressed data is identical to original")

Running this code, you will typically see a compression ratio above 10x, and the decompressed data is byte-for-byte identical to the original. This is what "lossless" means.

Lossy Compression with PIL


from PIL import Image
import io

# Create a test image rich in high-frequency detail
img = Image.new("RGB", (512, 512))
pixels = img.load()
for x in range(512):
    for y in range(512):
        # Generate a pattern with high-frequency detail
        pixels[x, y] = ((x * 7) % 256, (y * 5) % 256, ((x + y) * 3) % 256)

# Save as lossless PNG
img.save("test_lossless.png")
png_size = len(open("test_lossless.png", "rb").read())
print(f"PNG (lossless) size: {png_size} bytes")

# Save as lossy JPEG with quality 20 to amplify the effect
buffer = io.BytesIO()
img.save(buffer, format="JPEG", quality=20)
jpeg_size = buffer.tell()
print(f"JPEG (lossy) size: {jpeg_size} bytes")
print(f"Ratio: {png_size / jpeg_size:.2f}x")

# Reload the JPEG and compare pixel differences
buffer.seek(0)
img_jpeg = Image.open(buffer)
diff_count = sum(
    1 for x in range(512) for y in range(512)
    if img.getpixel((x, y)) != img_jpeg.getpixel((x, y))
)
print(f"Pixels that changed: {diff_count} / {512 * 512}")
print("Conclusion: JPEG compression alters pixel values irreversibly")

This code demonstrates the hallmark of lossy compression: a smaller file, but with pixel values changed irreversibly.


Comparison Table

DimensionLossless CompressionLossy Compression
Core PrincipleEliminates statistical & structural redundancyDiscards info below perception threshold
Fidelity100% reversible, identical after decompressionIrreversible, unrecoverable loss
Typical AlgorithmsDEFLATE, LZMA, Brotli, ZstandardDCT+quantization, wavelet, MDCT
Key TechniquesLZ77, Huffman coding, range codingTransform coding, quantization, prediction
Typical ApplicationsZIP, GZIP, 7Z, PNG, FLACJPEG, WebP, H.264, MP3, AAC
Best Suited ForText, source code, archives, medical imagingPhotos, video, music, streaming
Typical RatioUsually 2x to 5xUsually 10x to 100x or higher
Not Suitable ForAlready-compressed data (e.g., JPEG files)Data requiring exact reproduction (e.g., legal text)

FAQ

Q1: Why can't ZIP compress a JPEG image?

By the time a JPEG is created, it has already gone through DCT, quantization, and entropy coding. The statistical redundancy in the data has been almost entirely eliminated. DEFLATE cannot find exploitable repetition patterns, so running ZIP on a JPEG not only fails to reduce the size but may actually add a few bytes of header overhead.

Q2: Is PNG always larger than JPEG for the same image?

Not necessarily. For images with large areas of solid color or a limited palette (such as logos, icons, or screenshots), PNG's filter-plus-DEFLATE combination is often smaller than JPEG and preserves perfect quality. But for color-rich natural photographs, JPEG's DCT-plus-quantization typically achieves compression ratios above 10x, making it far smaller than PNG.

Q3: Can you repeatedly compress the same file with a lossless algorithm?

No. Each pass of lossless compression pushes the data closer to its entropy limit. After the first pass, redundancy is largely gone, and a second pass has almost nothing left to exploit—it may even grow slightly due to added metadata. This is why "compressing an already-compressed file" is futile.


Summary

Lossless and lossy compression are not opposing camps but optimal choices made for different information characteristics:

  • Lossless compression serves data where "not a single bit can be wrong"—text, code, archives. It uses techniques like LZ77 and Huffman coding to eliminate statistical redundancy while guaranteeing perfect reconstruction.
  • Lossy compression serves details "the eye and ear cannot perceive"—photos, video, music. It uses DCT, quantization, and inter-frame prediction to make trade-offs below the perception threshold, exchanging controlled information loss for order-of-magnitude improvements in compression ratio.

Understanding the fundamental difference between these two paths is the cornerstone of mastering all compression technology. In subsequent articles, we will dive into the specific algorithm implementations along each path, understanding the elegance of compression line by line.

Related Reading: