Back

Convertendo Imagens para Base64 com Canvas

Convertendo Imagens para Base64 com Canvas

Quando você precisa exportar dados de imagem do navegador—seja para pré-visualizações no lado do cliente, incorporar pequenos gráficos ou processar imagens antes do upload—a API HTML Canvas é a ferramenta mais direta disponível. Este artigo explica como funciona a conversão de canvas para Base64 em JavaScript, quando usá-la e onde estão as armadilhas comuns.

Pontos-Chave

  • O método toDataURL() do canvas retorna um URI de dados completo (com prefixo MIME), não uma string Base64 bruta. Remova o prefixo quando precisar apenas dos dados codificados.
  • Prefira toBlob() ao invés de toDataURL() para uploads de arquivos e imagens grandes, pois é assíncrono e mais eficiente em termos de memória.
  • PNG é o único formato de saída universalmente suportado. O suporte a JPEG e WebP varia conforme o navegador.
  • Imagens de origem cruzada (cross-origin) contaminarão o canvas a menos que o servidor envie os cabeçalhos CORS apropriados e você defina crossOrigin = 'anonymous' antes de atribuir o src da imagem.

O Fluxo de Trabalho Básico

Converter uma imagem para Base64 usando canvas segue três etapas: carregar a imagem, desenhá-la em um elemento canvas e então exportar os dados do canvas como uma string codificada.

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');
const image = new Image();

image.onload = function () {
  canvas.width = image.width;
  canvas.height = image.height;
  ctx.drawImage(image, 0, 0);

  const dataURL = canvas.toDataURL('image/png');
  console.log(dataURL); // "data:image/png;base64,iVBORw0KGg..."
};

image.src = '/path/to/local-image.jpg';

Esta é a base da codificação de imagem baseada em canvas. O método toDataURL() retorna um URI de dados completo, não uma string Base64 bruta.

Data URL vs. String Base64 Bruta

Entender a diferença é importante. canvas.toDataURL() retorna uma string neste formato:

data:image/png;base64,iVBORw0KGg...

Inclui um prefixo de tipo MIME, o rótulo de codificação e então os dados Base64 reais. Se você precisar apenas da porção Base64 bruta—por exemplo, para enviá-la como JSON para um servidor—remova o prefixo:

const base64String = canvas.toDataURL('image/jpeg').split(',')[1];

Isso divide na primeira vírgula e pega tudo depois dela. O prefixo é descartado e os dados codificados brutos permanecem.

toDataURL vs. toBlob: Qual Você Deve Usar?

Esta é a decisão que a maioria dos artigos ignora. Aqui está uma comparação direta:

RecursotoDataURL()toBlob()
Tipo de retornoString (síncrono)Blob (assíncrono, baseado em callback)
Uso de memóriaMaior (Base64 adiciona ~33% de overhead)Menor (representação binária)
Melhor paraImagens pequenas, incorporações rápidasUploads, imagens grandes

toDataURL() é síncrono e conveniente, mas carrega toda a string codificada na memória de uma vez. A codificação Base64 aumenta o tamanho dos dados em aproximadamente 33% comparado ao binário original. Para imagens grandes, isso importa.

toBlob() é assíncrono e produz um Blob binário diretamente, o que é mais eficiente para uploads:

canvas.toBlob((blob) => {
  const formData = new FormData();
  formData.append('image', blob, 'export.jpg');
  fetch('/upload', { method: 'POST', body: formData });
}, 'image/jpeg', 0.85);

Use Base64 apenas quando você especificamente precisar de uma string—para incorporar em JSON, armazenar em um campo de texto ou gerar um URI de dados para uma tag <img>. Para uploads de arquivos, toBlob() é a melhor escolha.

Suporte a Formatos e o Parâmetro de Qualidade

PNG é o único formato de saída garantido em todos os navegadores. O suporte a JPEG e WebP depende do ambiente:

canvas.toDataURL('image/jpeg', 0.85); // qualidade: 0 a 1, apenas JPEG/WebP
canvas.toDataURL('image/webp', 0.9);  // não suportado em todos os navegadores

O parâmetro de qualidade não tem efeito em PNG, que é sempre sem perdas. Para JPEG, 0.85 é um padrão razoável que equilibra tamanho de arquivo e qualidade visual. Se você passar um formato não suportado, o navegador silenciosamente retorna para PNG.

O Problema do Canvas Contaminado

Se você desenhar uma imagem de origem cruzada (cross-origin) em um canvas sem a configuração adequada de CORS, o canvas se torna “contaminado”. Chamar toDataURL() ou toBlob() em um canvas contaminado lança um SecurityError.

Para evitar isso, o servidor que hospeda a imagem deve enviar os cabeçalhos CORS apropriados (Access-Control-Allow-Origin), e você deve definir crossOrigin no elemento de imagem antes de atribuir seu src:

const image = new Image();
image.crossOrigin = 'anonymous';
image.src = 'https://other-origin.com/image.png';

A ordem aqui é crítica. Definir crossOrigin depois de src pode fazer com que o navegador comece a buscar sem a flag CORS, o que ainda contamina o canvas. Imagens carregadas da mesma origem nunca são um problema. Imagens de origem cruzada sem cabeçalhos CORS não podem ser exportadas—não há solução alternativa no lado do cliente.

Quando a Codificação Baseada em Canvas Faz Sentido

Use a abordagem de canvas quando você precisar:

  • Redimensionar ou recortar uma imagem no lado do cliente antes da codificação
  • Aplicar filtros ou transformações antes de exportar
  • Incorporar pequenas imagens processadas como URIs de dados

Se você só precisa ler um arquivo local como Base64 sem nenhuma manipulação de canvas, FileReader.readAsDataURL() é mais simples e pula o canvas completamente.

Conclusão

A API Canvas oferece controle preciso sobre a codificação de imagens no navegador. Use toDataURL() para imagens pequenas e casos de uso baseados em string, prefira toBlob() para uploads e trabalhos sensíveis ao desempenho, e sempre considere CORS ao trabalhar com imagens externas. Quando nenhuma manipulação de pixel for necessária, pule o canvas completamente e use FileReader em vez disso.

Perguntas Frequentes

Sim, você pode desenhar um SVG em um canvas e chamar toDataURL(). No entanto, o SVG deve ser carregado primeiro como um elemento Image, e as restrições de origem cruzada ainda se aplicam. O resultado exportado é um bitmap rasterizado, não um vetor escalável. Quaisquer recursos externos referenciados pelo SVG, como fontes ou imagens vinculadas, podem não renderizar corretamente no canvas.

Isso geralmente acontece porque toDataURL() é chamado antes que a imagem termine de carregar. Certifique-se de chamá-lo dentro do manipulador onload da imagem. Uma imagem preta também pode resultar de não definir a largura e altura do canvas para corresponder às dimensões da imagem de origem antes de desenhar, o que deixa o canvas em seu tamanho padrão de 300 por 150 pixels.

Não há limite formal na especificação, mas os navegadores impõem restrições práticas. Canvas muito grandes podem produzir strings Base64 que consomem memória significativa ou fazem com que a aba do navegador fique lenta ou trave. Para imagens grandes, toBlob() é a alternativa mais segura e eficiente em termos de memória.

Elementos canvas padrão não estão disponíveis em Web Workers porque dependem do DOM. No entanto, você pode usar OffscreenCanvas, que é suportado em navegadores modernos, para realizar o desenho e chamar seu método convertToBlob() dentro de um worker. Note que OffscreenCanvas não suporta toDataURL(), então você precisaria converter o Blob resultante para Base64 usando um FileReader se uma string for necessária.

Complete picture for complete understanding

Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.

Check our GitHub repo and join the thousands of developers in our community.

OpenReplay