Trilha 15 · Gráficos 2D e 3D

Pixels, cores e representação

Como monitores representam cor com três números, o que significam RGB e HSL, e por que uma imagem Full HD ocupa 8 MB por frame.

① Intuição

Tudo é um grid de números

Um monitor nada mais é que uma grade de pequenos pontos de luz — os pixels (picture elements). Cada pixel emite três cores primárias de luz: vermelho (R), verde (G) e azul (B). Controlando a intensidade de cada uma (0 a 255), o olho humano percebe praticamente qualquer cor.

Um pixel é armazenado na memória como 4 bytes contíguos: R, G, B e A (transparência). Uma tela Full HD (1920×1080) tem 2.073.600 pixels — cerca de 8 MB de dados por frame. A 60 fps, isso é quase 480 MB/s de dados sendo escritos na memória de vídeo.

Por que luz soma diferente de tinta? Monitores usam síntese aditiva: R+G+B = branco. Tintas e pigmentos usam síntese subtrativa (CMYK): misturar tudo dá preto. É por isso que cores de tela jamais ficam idênticas na impressão.
② Visualização interativa

Misturador de cores

Ajuste os sliders R/G/B das duas cores e veja a mistura linear. Observe os valores em hex, RGB e HSL.

Presets:
COR A
R91
G157
B255
hex: #5b9dff
rgb: (91, 157, 255)
hsl: (216°, 100%, 68%)
Mix: 50%
#51b1b5
COR B
R70
G196
B106
hex: #46c46a
rgb: (70, 196, 106)
hsl: (137°, 52%, 52%)
0%
25%
50%
75%
100%
Profundidade de cor: 8 bits por canal → 256 valores → 256³ = 16.777.216 cores (24-bit / "true color"). Displays HDR usam 10 bits por canal → 1.073.741.824 cores.
③ Explicação técnica

Pixels em memória e modelos de cor

// Representação de pixels em memória

// Imagem RGBA: 4 bytes por pixel
const largura = 1920, altura = 1080;
const bytesTotal = largura * altura * 4;  // 8.294.400 bytes ≈ 8 MB por frame

// Acessar o pixel (x=100, y=50):
const offset = (y * largura + x) * 4;
const r = imageData[offset];      // Red   0-255
const g = imageData[offset + 1];  // Green 0-255
const b = imageData[offset + 2];  // Blue  0-255
const a = imageData[offset + 3];  // Alpha 0-255

// CSS no fundo usa a mesma representação:
// #ff6b6b  = r:255, g:107, b:107
// rgb(255, 107, 107)  = mesma coisa, mais legível
// hsl(0°, 100%, 71%)  = mesma cor, modelo diferente

Por que HSL existe?

RGB é ótimo para hardware, mas terrível para humanos. Para "escurecer" um vermelho em RGB você teria que reduzir R=255 para R=128 — não intuitivo. Em HSL você só mexe no Lightness (L). O H (Hue/matiz) é o ângulo na roda de cores (0°=vermelho, 120°=verde, 240°=azul), S (Saturation) controla a vivacidade e L (Lightness) a luminosidade.

// Conversão RGB → HSL
function rgbToHsl(r, g, b) {
  r /= 255; g /= 255; b /= 255;
  const max = Math.max(r, g, b);
  const min = Math.min(r, g, b);
  const l = (max + min) / 2;      // Luminosidade

  if (max === min) return [0, 0, l]; // Cinza

  const d = max - min;
  const s = l > 0.5
    ? d / (2 - max - min)
    : d / (max + min);             // Saturação

  // Hue: qual canal domina?
  let h;
  if (max === r) h = (g - b) / d + (g < b ? 6 : 0);
  else if (max === g) h = (b - r) / d + 2;
  else               h = (r - g) / d + 4;

  return [h / 6 * 360, s * 100, l * 100]; // Hue°, Sat%, Light%
}
Profundidade de cor: 8 bits por canal = 256 valores = 256³ = 16.777.216 cores ("true color"). Monitores HDR usam 10 bits (1.024 valores por canal = 1 bilhão de cores). A diferença é perceptível em gradientes suaves: com 8 bits você vê "degraus" de tom (banding); com 10 bits, a transição é imperceptível.
④ Projeto para programar

Manipulação de pixels com Canvas

Mini projeto: use ctx.getImageData() do Canvas para inverter as cores de uma imagem: para cada pixel, faça R = 255 - R, G = 255 - G, B = 255 - B. Use ctx.putImageData() para atualizar.

Projeto principal: implemente um filtro "sepiatone" (tons sépia): para cada pixel, calcule newR = 0.393R + 0.769G + 0.189B, newG = 0.349R + 0.686G + 0.168B, newB = 0.272R + 0.534G + 0.131B. Clamp em 255. Aplique em tempo real em um stream de câmera (getUserMedia).

Desafio extra: implemente um seletor de cores no estilo "Color Picker" que converte em tempo real entre RGB, HSL e CMYK — tudo sem usar bibliotecas, só as fórmulas matemáticas de conversão.

⑤ Exercícios rápidos

Teste sua intuição

Quantos bytes ocupa um pixel no formato RGBA padrão (como no Canvas 2D)?
Em síntese aditiva (monitores RGB), qual combinação produz branco?
No modelo HSL, o que representa o componente H (Hue)?
⑥ Aplicações no mundo real

Onde você encontra isso

📸

Filtros de foto/vídeo

Instagram, Photoshop e DaVinci Resolve manipulam pixels com matrizes de cor (color grading). Um "filtro de filme" é literalmente uma transformação matemática aplicada a cada pixel — às vezes com uma lookup table (LUT) de 33³ entradas.

🎮

HDR em jogos

Jogos modernos renderizam internamente em espaço de cor linear com 16 bits float por canal (HDR), depois aplicam tone mapping para converter para o display de 8 bits. Sem isso, áreas muito brilhantes ficam "queimadas" — sem detalhe.

🌐

CSS Color Level 5

CSS moderno suporta oklch(), lab() e display-p3 — espaços de cor perceptualmente uniformes que cobrem 25% mais cores que sRGB. Monitores Apple (P3) e OLED modernos exibem essas cores extras.

← Trilha: Gráficos 2D e 3D Próxima: Transformações 2D →