Artigos aprofundados sobre a tecnologia que molda o que vem a seguir.

Como a Compressão JPEG Realmente Funciona

Um passeio visual pela compressão JPEG: transformadas DCT, tabelas de quantização e por que algumas imagens comprimem melhor que outras.

Uma imagem de flor se dissolvendo em blocos de pixels e depois em padrões de ondas em espiral

JPEG é a barata dos formatos de arquivo. Foi padronizado em 1992, é anterior ao navegador web e sobreviveu a todas as tentativas de substituí-lo. WebP, AVIF, HEIC — todos comprimem melhor, mas o JPEG continua sendo o formato de imagem mais usado na internet. Parte disso é inércia. Mas outra parte é que o pipeline de compressão do JPEG é genuinamente brilhante — uma aula magistral de processamento de sinais aplicado, que vale a pena entender mesmo que você nunca escreva um encoder.

A maioria dos desenvolvedores trata o JPEG como uma caixa-preta: coloca uma imagem, recebe um arquivo menor e aumenta o controle de qualidade até ficar aceitável. Mas entender o que acontece dentro dessa caixa muda a forma como você pensa sobre imagens, compressão e os trade-offs entre tamanho do arquivo e qualidade visual.

O Pipeline de Relance

A compressão JPEG é um pipeline de cinco etapas, cada uma fazendo algo inteligente. A mágica está na composição: cada etapa prepara a seguinte para ser mais eficaz.

  1. Conversão de espaço de cor — RGB para YCbCr (separa brilho de cor)
  2. Subamostragem de crominância — reduz a resolução dos canais de cor
  3. Transformada Discreta do Cosseno (DCT) — converte dados espaciais em dados de frequência
  4. Quantização — descarta detalhes de alta frequência (esta é a etapa com perda)
  5. Codificação de entropia — compressão sem perdas dos dados quantizados

As etapas 1 e 2 exploram como a visão humana funciona. As etapas 3 e 4 exploram propriedades de imagens naturais. A etapa 5 é compressão de dados padrão. Cada etapa é simples individualmente. O segredo está na sequência.

Etapa 1: Conversão de Espaço de Cor

Sua câmera captura imagens em RGB — canais vermelho, verde e azul, cada um com 8 bits por pixel. O primeiro movimento do JPEG é converter isso em YCbCr: um canal de luminância (brilho) e dois canais de crominância (cor). Isso ainda não é compressão — nenhum dado é perdido. É uma transformação de coordenadas, como girar os eixos.

Por que se preocupar? Porque os olhos humanos são muito mais sensíveis ao brilho do que à cor. Você consegue ver detalhes incrivelmente finos em uma fotografia em preto e branco, mas sua percepção de resolução de cor é bem mais grosseira. Ao separar brilho de cor, o JPEG pode tratá-los de forma diferente — preservando o detalhe do brilho e reduzindo agressivamente o detalhe da cor.

RGB to YCbCr conversion (simplified):
Y  =  0.299R + 0.587G + 0.114B    (luminance — brightness)
Cb = -0.169R - 0.331G + 0.500B    (blue chrominance)
Cr =  0.500R - 0.419G - 0.081B    (red chrominance)
Note: green dominates the luminance calculation because
human eyes have far more green-sensitive cone cells.
This isn't arbitrary — it matches the physiology.

Etapa 2: Subamostragem de Crominância

Aqui acontece a primeira grande redução de dados. Como humanos não percebem cor na resolução espacial total, o JPEG reduz a resolução dos canais Cb e Cr — tipicamente pela metade em ambas as dimensões. Isso é chamado de subamostragem 4:2:0. Para cada quatro pixels de luminância, há uma amostra de crominância.

O resultado: você acabou de cortar pela metade os dados brutos (de 3 canais em resolução total para 1 canal total + 2 canais em um quarto da resolução), e a imagem fica praticamente idêntica à original. Teste você mesmo — pegue qualquer fotografia, reduza a resolução do canal de cor em 4x, e você vai ter dificuldade para notar a diferença. Seu cérebro preenche o detalhe de cor a partir da informação de luminância.

Isso não funciona igualmente bem para todas as imagens. Fotografias comprimem muito bem porque cenas naturais têm gradientes de cor suaves. Mas imagens com bordas de cor nítidas — como texto sobre fundo colorido, um círculo vermelho sobre branco ou pixel art — mostram franjas de cor visíveis após a subamostragem. É por isso que o JPEG é ruim com texto: as bordas de cor nítidas vazam.

Etapa 3: A Transformada Discreta do Cosseno

A DCT é onde o JPEG fica interessante. A imagem é dividida em blocos de 8×8 pixels, e cada bloco é transformado do domínio espacial (valores de brilho dos pixels) para o domínio da frequência (quanto de cada frequência espacial está presente).

Pense assim: um bloco 8×8 de pixels pode ser representado como uma soma ponderada de 64 padrões de base. O primeiro padrão é um bloco uniforme (o valor médio). Os seguintes adicionam gradientes horizontais e verticais. Padrões de numeração mais alta adicionam detalhes cada vez mais finos — oscilações rápidas de brilho.

An 8x8 DCT block conceptually:
DC ──► Low frequency ──────────────► High frequency
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ AVG │  →  │  →  │  →  │  →  │  →  │  →  │  →  │ Low freq
│     │     │     │     │     │     │     │     │   ↓
│  ↓  │  ↘  │     │     │     │     │     │     │
│     │     │  ↘  │     │     │     │     │     │
│     │     │     │  ↘  │     │     │     │     │
│     │     │     │     │  ↘  │     │     │     │
│     │     │     │     │     │  ↘  │     │     │
│     │     │     │     │     │     │  ↘  │     │
│     │     │     │     │     │     │     │ FINE │ High freq
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
Top-left = low frequency (smooth gradients)
Bottom-right = high frequency (sharp edges, fine detail)
Natural images: most energy concentrated in top-left
Text/line art: significant energy in bottom-right

A DCT em si não tem perdas — você pode reconstruir perfeitamente o bloco 8×8 original a partir de seus 64 coeficientes DCT. Mas aqui está a propriedade crítica: em imagens naturais (fotografias, gradientes, texturas orgânicas), a maior parte da energia fica concentrada nos coeficientes de baixa frequência. Os coeficientes de alta frequência — que representam detalhes finos — tendem a ser pequenos. É isso que faz a próxima etapa funcionar.

Por que 8×8? É um compromisso. Blocos maiores (16×16, 32×32) concentrariam melhor a energia, mas são mais caros de calcular e causam artefatos de 'blocagem' visíveis em configurações de qualidade baixa. Blocos menores (4×4) reduziriam a blocagem, mas não concentrariam a energia tão bem. O 8×8 se mostrou um ponto ideal que resistiu por mais de 30 anos.

Etapa 4: Quantização — Onde os Dados Morrem

Esta é a etapa com perda. Cada coeficiente DCT é dividido por um valor correspondente de uma tabela de quantização e depois arredondado para o inteiro mais próximo. Divisores grandes (para coeficientes de alta frequência) arredondam valores pequenos para zero. Esses zeros se perdem para sempre — é aqui que a informação é descartada permanentemente.

Example quantization (quality ~50):
DCT coefficient: 42.7    Quantization divisor: 16    Result: round(42.7/16) = 3
DCT coefficient: 8.3     Quantization divisor: 40    Result: round(8.3/40)  = 0
DCT coefficient: -2.1    Quantization divisor: 99    Result: round(-2.1/99) = 0
The quality slider in your image editor controls the quantization table.
Quality 100: divisors close to 1 (almost no rounding, huge file)
Quality 75:  moderate divisors (good balance, typical web use)
Quality 50:  large divisors (noticeable artifacts, small file)
Quality 10:  very large divisors (blocky mess, tiny file)

A tabela de quantização é o fator mais importante na qualidade do JPEG. O padrão JPEG define uma tabela padrão, mas os encoders podem usar qualquer tabela que quiserem. Encoders modernos como o MozJPEG usam tabelas otimizadas que extraem mais qualidade de arquivos menores, ajustando os divisores à sensibilidade perceptual humana — sendo mais agressivos nas frequências às quais humanos são menos sensíveis.

Após a quantização, um bloco 8×8 típico em qualidade moderada tem talvez 6 a 10 coeficientes não nulos de 64. O resto é zero. Essa enorme redução de valores não nulos é o que torna a etapa final de compressão eficaz.

Etapa 5: Codificação de Entropia

A etapa final é a compressão sem perdas dos coeficientes quantizados. O JPEG usa uma combinação de run-length encoding (RLE) e codificação Huffman. Os coeficientes são lidos em padrão zigue-zague a partir do bloco 8×8 — começando pelo coeficiente DC (canto superior esquerdo) e percorrendo frequências crescentes em zigue-zague. Isso agrupa todos os zeros finais, que o RLE trata com eficiência: em vez de armazenar '0, 0, 0, 0, 0, 0, ..., 0', ele armazena 'quarenta e sete zeros.'

A codificação Huffman então atribui sequências de bits mais curtas a valores mais comuns e mais longas a valores raros. Como a maioria dos coeficientes não nulos são inteiros pequenos (1, -1, 2, -2), eles recebem códigos bem curtos. O resultado: o bloco 8×8 quantizado, que começou com 64 valores, normalmente é comprimido para 20 a 40 bytes, dependendo do conteúdo da imagem e da configuração de qualidade.

Por Que Algumas Imagens Comprimem Melhor Que Outras

Entender o pipeline explica comportamentos de compressão que de outra forma pareceriam misteriosos.

  • Fotografias comprimem bem porque têm gradientes de cor suaves (a subamostragem de crominância funciona muito bem) e a maior parte da energia está nos coeficientes DCT de baixa frequência (a quantização zera muitos coeficientes sem impacto visível).
  • Texto e arte em traço comprimem mal porque bordas nítidas produzem coeficientes DCT de alta frequência significativos que não podem ser zerados sem artefatos visíveis. As bordas dos blocos 8×8 ficam visíveis como um 'ringing' ao redor das bordas do texto.
  • Ruído destrói a compressão porque o ruído do sensor é um dado aleatório de alta frequência. Cada pixel ruidoso adiciona coeficientes de alta frequência não nulos que resistem à quantização. Uma foto ruidosa com qualidade 80 pode ser de 3 a 5 vezes maior que uma foto limpa da mesma cena com a mesma qualidade.
  • Gradientes são quase gratuitos porque um gradiente suave em um bloco 8×8 é representado por apenas 2 ou 3 coeficientes DCT. O resto é zero mesmo sem quantização.
  • Salvar de novo degrada a qualidade porque cada ciclo de salvamento aplica a quantização novamente. Os erros de arredondamento se acumulam. Salvar um JPEG 10 vezes com qualidade 75 fica notavelmente pior do que salvar uma única vez com qualidade 75. Por isso você deve sempre editar a partir do arquivo original.

O Controle de Qualidade Não é Linear

A maioria dos desenvolvedores trata o controle de qualidade do JPEG como se fosse um trade-off linear: qualidade 50 é metade da qualidade de 100, e metade do tamanho do arquivo. Nenhuma das duas coisas é verdade.

Qualidade 100 não é 'sem perdas' — ainda aplica quantização, só que com divisores pequenos. O arquivo fica enorme (muitas vezes maior que um PNG) e visualmente indistinguível da qualidade 95. A qualidade 95 é visualmente indistinguível da 90 em fotografias. A diferença perceptual entre a qualidade 85 e a 75 é maior do que entre 100 e 85. Abaixo de 50, os artefatos se tornam severos e a redução do tamanho do arquivo desacelera.

O ponto ideal para imagens na web costuma ficar entre 75 e 85. Abaixo de 75, os artefatos são visíveis em tamanhos normais de visualização. Acima de 85, o tamanho do arquivo aumenta bastante com ganho perceptual insignificante. O padrão de qualidade 75 do MozJPEG foi bem escolhido — ele atinge o joelho da curva qualidade-versus-tamanho para a maioria das fotografias.

Encoders JPEG Modernos São Mais Inteligentes do Que Parece

O padrão JPEG define o formato de decodificação, não o encoder. Isso significa que implementações de encoder podem ser muito diferentes em eficiência de compressão, mantendo arquivos compatíveis com a especificação. O MozJPEG, desenvolvido pela Mozilla, gera arquivos de 5 a 15% menores que o libjpeg com a mesma qualidade visual, graças a várias técnicas.

  • Quantização trellis — em vez de arredondar cada coeficiente DCT de forma independente, a quantização trellis considera como as decisões de arredondamento afetam a etapa de codificação de entropia e faz escolhas globalmente melhores.
  • Tabelas Huffman otimizadas — as tabelas Huffman padrão do JPEG são genéricas. O MozJPEG gera tabelas personalizadas ajustadas à distribuição real dos coeficientes de cada imagem.
  • Codificação progressiva — JPEGs progressivos armazenam coeficientes em múltiplas passagens (primeiro grosseiro, depois refinamento). Isso costuma comprimir melhor que a codificação sequencial, porque a passagem grosseira tem distribuições de coeficientes mais previsíveis.
  • Tabelas de quantização adaptativas — em vez de uma única tabela de quantização para a imagem inteira, encoders adaptativos ajustam a quantização por região, sendo mais agressivos em áreas movimentadas (onde os artefatos são menos visíveis) e mais conservadores em áreas suaves.

Se você serve imagens na web, trocar o encoder padrão libjpeg pelo MozJPEG é uma das melhorias de performance mais fáceis disponíveis. A maioria dos CDNs de imagens e bibliotecas de processamento já suporta. A codificação é mais lenta (irrelevante para imagens estáticas pré-processadas) e a saída fica menor na mesma qualidade.

JPEG vs. Os Novos Formatos

WebP, AVIF e HEIC usam técnicas de compressão mais modernas — blocos de transformada maiores, filtros de deblocking dentro do loop, predição intra (usando blocos vizinhos para prever o bloco atual). Eles comprimem de 20 a 50% melhor que o JPEG na mesma qualidade visual. O AVIF, em particular, baseado no codec de vídeo AV1, é impressionantemente eficiente.

Então por que o JPEG ainda está em todo lugar? Suporte universal. Todo navegador, todo visualizador de imagens, todo sistema operacional, toda câmera, todo celular, todo software que lida com imagens suporta JPEG. O WebP tem quase suporte universal em navegadores, mas falta suporte nativo nos sistemas operacionais. O suporte ao AVIF ainda é inconsistente. O HEIC é principalmente do ecossistema da Apple. Para um formato que precisa funcionar em qualquer lugar, o JPEG ainda é a única escolha segura.

O conselho prático: use AVIF ou WebP com fallback para JPEG se sua infraestrutura de entrega suportar isso (a maioria dos CDNs suporta via negociação de conteúdo). Se você só pode usar um formato, JPEG codificado com MozJPEG na qualidade 80 é difícil de superar para fotografias. Para capturas de tela, diagramas e imagens com muito texto, o PNG continua sendo a melhor escolha — ou explore abordagens mais criativas para representação de imagens.

O Bloco 8×8 que Conquistou o Mundo

O pipeline de compressão do JPEG é um exemplo clássico de engenharia que trabalha com a percepção humana em vez de contra ela. Cada etapa explora uma propriedade específica — insensibilidade à cor, distribuição de frequências de imagens naturais, mascaramento perceptual do ruído de quantização — e elas se combinam em um sistema que reduz arquivos em 10 a 20 vezes com impacto visível mínimo. Trinta e quatro anos depois, os mesmos blocos DCT 8×8 que rodavam em hardware de 1992 ainda carregam a maior parte das imagens da internet. Essa é a marca de um design que acertou os fundamentos.