A fórmula
Para uma entrada de n bytes, o Base64 com preenchimento (o padrão da RFC 4648) tem exatamente:
length = 4 × ceil(n / 3)
Sem preenchimento, como no Base64URL dos JWTs, tem:
length = ceil(4n / 3)
As duas diferem pelo número de sinais =, que é 0, 1 ou 2, dependendo de n mod 3. O guia de preenchimento explica de onde eles vêm.
No sentido inverso, uma string Base64 com preenchimento de comprimento L decodifica para:
bytes = 3 × L / 4 − (number of trailing "=")
Então TWFu são 3 bytes, TWE= são 2 e TQ== é 1. Remova espaços em branco e quebras de linha antes de contar. A calculadora de tamanho Base64 faz as duas direções, incluindo quebras de linha e prefixos de data URI.
Em código:
import base64, math, os
for n in [1, 2, 3, 100, 1000]:
data = os.urandom(n)
assert len(base64.b64encode(data)) == 4 * math.ceil(n / 3)
const b64Len = (n) => 4 * Math.ceil(n / 3);
const rawLen = (s) => (s.length * 3) / 4 - (s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0);
b64Len(1000); // 1336
rawLen("TWE="); // 2
Por que o aumento é de 33%
Um byte tem 8 bits. Um caractere Base64 carrega 6 bits de dados, porque é um entre 64 = 2⁶ símbolos, mas é armazenado como um byte ASCII de 8 bits. Assim, cada byte de saída guarda 6 bits úteis, e a saída precisa ter 8/6 = 4/3 da entrada. São 33,3% a mais, e esse é um piso rígido: nenhuma implementação de Base64 faz melhor sem abandonar o alfabeto. (Como os bits são reagrupados é mostrado passo a passo em como o Base64 funciona.)
Em entradas pequenas, o preenchimento piora a proporção, já que a saída sempre vem em blocos de 4. Um byte vira 4 caracteres, um aumento de 300%. A partir de algumas centenas de bytes, o preenchimento fica desprezível e a proporção se estabiliza em 4/3.
Existem codificações de texto mais densas. O Base85 guarda 4 bytes em 5 caracteres (25% de aumento), e o Base91 fica um pouco abaixo disso. Elas têm suporte menos amplo, e os alfabetos delas incluem caracteres que causam problemas em alguns contextos. A comparação está em Base64 vs hex, Base32, Base58, Base85.
Quebras de linha: MIME, PEM e ferramentas de linha de comando
Alguns formatos quebram o Base64 em linhas, e os finais de linha entram na conta do tamanho.
| Formato | Comprimento da linha | Final de linha | Aumento total |
|---|---|---|---|
| Base64 simples (RFC 4648) | sem quebra | nenhum | 33,3% |
| E-mail MIME (RFC 2045) | 76 | CRLF (2 bytes) | 36,8% |
base64 do GNU, encodebytes do Python | 76 | LF (1 byte) | 35,1% |
| Certificados e chaves PEM | 64 | LF | 35,4% |
O número do MIME vem de 4/3 × 78/76: cada 76 caracteres de Base64 trazem mais 2 bytes de CRLF. Com L = 4 × ceil(n / 3), o tamanho incluindo um CRLF depois de cada linha, inclusive a última, é:
mime_length = L + 2 × ceil(L / 76)
Cada linha completa de 76 caracteres guarda exatamente 57 bytes de entrada, e é por isso que os codificadores MIME processam os dados em blocos de 57 bytes. Mais sobre e-mail em Base64 em e-mail, e o codificador Base64 MIME gera saída quebrada em linhas.
Tabela de tamanhos
Calculada com as fórmulas acima e conferida com o módulo base64 do Python.
| Entrada | Base64 com preenchimento | Sem preenchimento | MIME (76 + CRLF) | Aumento (com preenchimento) |
|---|---|---|---|---|
| 1 byte | 4 | 2 | 6 | 300% |
| 2 bytes | 4 | 3 | 6 | 100% |
| 3 bytes | 4 | 4 | 6 | 33,3% |
| 10 bytes | 16 | 14 | 18 | 60% |
| 57 bytes | 76 | 76 | 78 | 33,3% |
| 100 bytes | 136 | 134 | 140 | 36% |
| 1.000 bytes | 1.336 | 1.334 | 1.372 | 33,6% |
| 1 KiB (1.024) | 1.368 | 1.366 | 1.404 | 33,6% |
| 1 MB (10⁶) | 1.333.336 | 1.333.334 | 1.368.424 | 33,3% |
| 1 MiB (1.048.576) | 1.398.104 | 1.398.102 | 1.434.898 | 33,3% |
| 10 MiB | 13.981.016 | 13.981.014 | 14.348.938 | 33,3% |
| 25 MB (25 × 10⁶) | 33.333.336 | 33.333.334 | 34.210.530 | 33,3% |
A última linha é o caso do e-mail. Os limites de tamanho do SMTP (a extensão SIZE, RFC 1870) contam a mensagem como ela é transmitida, com a codificação, então um arquivo de 25 MB vira cerca de 34,2 MB na transmissão e não passa por um servidor com limite de 25 MB. Alguns provedores descrevem os limites em termos do anexo, então confira como o seu faz a conta.
O que a compressão faz
A compressão interage com o Base64 de duas formas, e a ordem importa.
Compacte antes de codificar sempre que você controlar as duas pontas. O Base64 de dados compactados é 4/3 de um número menor. Para o texto da licença GPL-3 (35.149 bytes), medimos com o zlib do Node.js no nível 9 do gzip:
| Pipeline | Tamanho |
|---|---|
| Texto bruto | 35.149 |
| Só Base64 | 46.868 |
| Base64, depois gzip | 17.465 |
| gzip, depois Base64 | 16.124 |
| Só gzip | 12.091 |
A ferramenta Gzip + Base64 faz o pipeline “gzip, depois Base64” no navegador.
A compressão no transporte recupera a maior parte do aumento em dados binários. Se uma string Base64 viaja dentro de uma resposta HTTP compactada com gzip ou Brotli, o compressor espreme os caracteres de 6 bits de volta para perto de 6 bits cada. Para 1 MiB de bytes aleatórios, o Base64 cresceu para 1.398.104 caracteres; com gzip ficou em 1.053.023 bytes (0,4% acima dos dados brutos), e o Brotli chegou a 1.048.805. Os mesmos dados com quebras de linha MIME ficaram em 1.088.689 com gzip, então os CRLFs custam cerca de 3,4% mesmo depois da compressão.
Com texto é diferente. O Base64 quebra a repetição de que os compressores dependem, então texto em Base64 compacta bem pior que o próprio texto: 17.465 contra 12.091 bytes na tabela acima. O artigo sobre desempenho de data URIs traz medições para PNG, JPEG, WOFF2 e SVG.
Limites de URL, header e cookie
O Base64 incha tudo o que você coloca numa URL, num header ou num cookie, e os três têm limites.
- URLs. A RFC 9110 recomenda que remetentes e destinatários suportem URIs de pelo menos 8.000 octetos. Muitos servidores param perto disso por padrão: o nginx aloca buffers de header de 8 KB para a linha de requisição, e o
LimitRequestLinedo Apache tem padrão de 8.190 bytes. URLs mais longas costumam falhar com414 URI Too Long. Com Base64URL, isso dá espaço para uns 6.000 bytes de dados, descontado o resto da URL. - Headers. Os mesmos buffers do servidor valem para cada linha de header, o que importa para JWTs longos em headers
Authorization: Bearer ...e para credenciais Basic Auth grandes. - Cookies. A RFC 6265 pede que os navegadores suportem pelo menos 4.096 bytes por cookie, incluindo o nome e os atributos. Isso dá cerca de 3 KB de dados depois de codificados em Base64.
Se um payload Base64 está chegando perto de algum desses limites, envie-o no corpo da requisição ou guarde-o no servidor e passe um ID.
Informe uma quantidade de bytes ou cole uma string para ver os tamanhos codificado e decodificado, com ou sem quebras de linha.
Perguntas frequentes
Quanto o Base64 é maior que o arquivo original?
Cerca de 33,3% para qualquer coisa com mais de alguns bytes. Com quebras de linha MIME (76 caracteres mais CRLF), são cerca de 36,8%.
Como calcular o tamanho original a partir de uma string Base64?
Pegue o comprimento sem espaços em branco, multiplique por 3/4 e subtraia o número de sinais = no final. Por exemplo, TWE= dá 4 × 3/4 − 1 = 2 bytes.
Por que uma entrada de 1 byte gera 4 caracteres?
Com preenchimento, o Base64 sempre gera blocos completos de 4 caracteres. Um byte ocupa 2 caracteres e os outros 2 são =, então entradas minúsculas têm um aumento relativo bem maior.
Dá para deixar o Base64 menor?
Compacte os dados antes de codificar, por exemplo com gzip, e dispense o preenchimento se o destinatário permitir. O Base64 em si tem uma proporção fixa; existem codificações de texto mais densas, como o Base85, mas com suporte menos amplo.