> [Site index](https://perfectvector.com/llms.txt) — available pages and descriptions.

# SVG para Canvas: carregue a arte antes de exportar PNG

> Carregue um SVG inteiro com Image.decode, desenhe no tamanho de bitmap escolhido, teste CORS e leitura PNG e separe a origem editável dos pixels exportados.

Source: https://perfectvector.com/pt-BR/blog/svg-canvas-image-export

Language: pt-BR
Author: Irene Kim
Published: 2026-10-06T08:00:00+09:00
Updated: 2026-10-06T08:00:00+09:00

Para desenhar um SVG inteiro em canvas, carregue-o como imagem, aguarde `image.decode()` e passe a imagem para `drawImage()`. Depois confira a exportação PNG separadamente: uma imagem pode aparecer no canvas enquanto o navegador bloqueia a leitura ou o salvamento de seus pixels.

Essa rota pinta o documento SVG como uma imagem. Não fornece ao canvas caminhos SVG editáveis. Se você quer reconstruir contornos selecionados, use o [guia de SVG com Path2D](https://perfectvector.com/pt-BR/blog/canvas-path2d-svg). Mantenha o SVG original, qualquer que seja a rota de exibição escolhida.

## Separe decodificação, pintura e exportação

Um `HTMLImageElement` é uma entrada aceita por [canvas drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage). Sua largura e altura de destino controlam o tamanho pintado. [Image.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) retorna uma promise resolvida quando a imagem é decodificada; uma requisição malsucedida ou problema de decodificação pode rejeitá-la.

Decodificação bem-sucedida é só a primeira verificação. Uma imagem de outra origem carregada sem permissão CORS ainda pode ser desenhada, mas contamina o canvas. A leitura de pixels e a exportação então falham. O [guia de imagens com CORS da MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/How_to/CORS_enabled_image) explica a distinção.

**Mantenha a origem, confira os pixels**

![Ilustração conceitual de um losango vazado e círculo como contornos de origem, arte renderizada suave e saída em grade de pixels](https://perfectvector.com/blog/svg-canvas-image-export/image-and-png.webp)

*Ilustração: contornos de origem e pixels pintados são representações diferentes. Quadros, setas e grades grossas são conceituais; os resultados do navegador abaixo vêm de um arquivo original executado de forma independente.*

## Crie um SVG original independente

Salve como `master.svg`. Ele contém um caminho e um círculo, sem imagem incorporada, fonte ou dependência externa. O losango interno e a tela ao redor são transparentes na origem.

```svg
<svg xmlns="http://www.w3.org/2000/svg" width="240" height="160" viewBox="0 0 240 160">
  <path d="M96 24 L152 80 L96 136 L40 80 Z M96 58 L118 80 L96 102 L74 80 Z" fill="#176b5b" fill-rule="evenodd"/>
  <circle cx="200" cy="80" r="24" fill="#d4a53a"/>
</svg>
```

Usamos o arquivo completo como imagem, incluindo as duas formas e o `viewBox`. Ao contrário de extrair apenas o valor `d` de um caminho, isso pede ao renderizador de imagens SVG do navegador para pintar o documento.

O exemplo é intencionalmente independente. SVG usado como imagem tem restrições, inclusive a recursos externos e scripts; veja o [guia da MDN sobre SVG como imagem](https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG_as_an_image). Não trate a decodificação bem-sucedida deste arquivo pequeno como prova de que qualquer SVG carregará fontes, estilos ou arte vinculada externos. Para escolhas de entrega, compare [SVG inline com elemento de imagem](https://perfectvector.com/pt-BR/blog/inline-svg-vs-img).

## Execute duas origens locais com respostas CORS diferentes

Uma origem inclui sua porta. O servidor apenas local abaixo expõe os mesmos bytes SVG por duas origens. Na segunda, `/cors/master.svg` inclui `Access-Control-Allow-Origin: *`; `/plain/master.svg` não. Isso isola a permissão da resposta da arte.

Salve como `serve-proof.py` junto do SVG e do HTML abaixo. Execute `python3 serve-proof.py` e abra `http://127.0.0.1:8770/starter.html`. As duas portas precisam estar livres; se mudá-las, atualize o servidor e o HTML juntos. Pressione Enter no terminal para parar os dois servidores.

```python
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
from threading import Thread

root = Path(__file__).parent
class Handler(SimpleHTTPRequestHandler):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, directory=str(root), **kwargs)
    def do_GET(self):
        if self.path in ['/cors/master.svg', '/plain/master.svg']:
            payload = (root / 'master.svg').read_bytes()
            self.send_response(200)
            self.send_header('Content-Type', 'image/svg+xml')
            self.send_header('Cache-Control', 'no-store')
            if self.path.startswith('/cors/'):
                self.send_header('Access-Control-Allow-Origin', '*')
            self.end_headers()
            self.wfile.write(payload)
        else:
            super().do_GET()

servers = [ThreadingHTTPServer(('127.0.0.1', port), Handler) for port in (8770, 8783)]
for server in servers:
    Thread(target=server.serve_forever, daemon=True).start()
try:
    input('Original SVG proof on 127.0.0.1:8770 and :8783. Enter to stop.\n')
finally:
    for server in servers:
        server.shutdown()
        server.server_close()
```

Esse cabeçalho permissivo pertence a um arquivo de teste local que serve nossa própria arte. Para um host de imagens em produção, configure a origem permitida adequada em um servidor que você controla. Definir um atributo de imagem não concede acesso ao conteúdo de outro servidor.

## Decodifique a imagem antes de desenhá-la

Salve esta página completa como `starter.html`. Cada caso recebe seu próprio canvas, assim o caso contaminado não afeta os bem-sucedidos. Defina `crossOrigin` antes de `src` nas requisições que precisam de CORS, como descreve a [referência de crossOrigin da MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin).

O bitmap do canvas é explicitamente `480 × 320`; seu tamanho de exibição CSS é `240 × 160`. As dimensões intrínsecas da imagem original são `240 × 160`, e `drawImage()` a escala para as dimensões de bitmap selecionadas. São dimensões escolhidas, não uma medida da razão de pixels do dispositivo.

```html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Original SVG to canvas export</title>
<style>
  body { margin: 24px; font: 16px system-ui; background: #f6f2e8; }
  main { display: grid; grid-template-columns: repeat(2, 280px); gap: 20px; }
  figure { margin: 0; }
  canvas { display: block; width: 240px; height: 160px; background: white; }
  figcaption { margin: 6px 0; }
  pre { white-space: pre-wrap; font-size: 12px; }
</style>
<h1>Decode, paint, then check PNG access</h1>
<main id="cases"></main>
<pre id="report"></pre>
<script>
  function pngBlob(canvas) {
    return new Promise((resolve, reject) => {
      try { canvas.toBlob(blob => blob ? resolve(blob) : reject(new Error('Empty PNG')), 'image/png'); }
      catch (error) { reject(error); }
    });
  }
  function dataURL(blob) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.onerror = () => reject(reader.error);
      reader.readAsDataURL(blob);
    });
  }
  async function render(test) {
    const figure = document.createElement('figure');
    const canvas = document.createElement('canvas');
    canvas.width = 480;
    canvas.height = 320;
    const caption = document.createElement('figcaption');
    figure.append(canvas, caption);
    document.getElementById('cases').append(figure);
    const result = { id: test.id, url: new URL(test.src, location.href).href,
      crossOrigin: test.crossOrigin ?? null, canvasWidth: canvas.width, canvasHeight: canvas.height };
    const image = new Image();
    if (test.crossOrigin) image.crossOrigin = test.crossOrigin;
    image.src = result.url;
    try { await image.decode(); }
    catch (error) {
      result.stage = 'decode';
      result.error = error.name;
      caption.textContent = test.id + ': decode ' + error.name;
      return result;
    }
    result.naturalWidth = image.naturalWidth;
    result.naturalHeight = image.naturalHeight;
    const context = canvas.getContext('2d');
    context.drawImage(image, 0, 0, canvas.width, canvas.height);
    result.stage = 'painted';
    try {
      result.opening = [...context.getImageData(192, 160, 1, 1).data];
      result.fill = [...context.getImageData(192, 80, 1, 1).data];
      result.corner = [...context.getImageData(0, 0, 1, 1).data];
    } catch (error) { result.readbackError = error.name; }
    try {
      const blob = await pngBlob(canvas);
      result.pngType = blob.type;
      result.pngBytes = blob.size;
      result.pngDataURL = await dataURL(blob);
      result.export = 'ok';
      const download = document.createElement('a');
      download.href = result.pngDataURL;
      download.download = test.id + '.png';
      download.textContent = 'Save PNG';
      figure.append(download);
    } catch (error) { result.export = 'failed'; result.exportError = error.name; }
    caption.textContent = test.id + ': ' + result.stage + ', PNG ' + result.export;
    return result;
  }
  async function run() {
    const tests = [
      { id: 'same-origin', src: 'master.svg' },
      { id: 'cors-allowed', src: 'http://127.0.0.1:8783/cors/master.svg', crossOrigin: 'anonymous' },
      { id: 'no-cors-image', src: 'http://127.0.0.1:8783/plain/master.svg' },
      { id: 'cors-denied', src: 'http://127.0.0.1:8783/plain/master.svg', crossOrigin: 'anonymous' },
      { id: 'missing-file', src: 'missing.svg' },
    ];
    const results = [];
    for (const test of tests) results.push(await render(test));
    document.getElementById('report').textContent = JSON.stringify({ pageOrigin: location.origin, results }, (key, value) => key === 'pngDataURL' ? undefined : value, 2);
  }
  run();
</script>
</html>
```

A função de exportação trata uma exceção lançada e um resultado blob nulo. [Canvas.toBlob()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) suporta saída PNG e pode lançar `SecurityError` quando o canvas não está limpo em relação à origem. Os dois casos bem-sucedidos adicionam um link Save PNG; o relatório visível omite o conteúdo base64.

## Leia a etapa de falha antes de mudar o SVG

Executamos exatamente esse exemplo em um ambiente de navegador Chrome e reabrimos os dois PNGs salvos. Essas observações dizem respeito ao arquivo original independente e às duas origens locais.

| Caso                              | Requisição de imagem                     | Desenho/leitura/exportação observados                                   |
| --------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------- |
| Mesma origem                      | SVG local, sem atributo CORS             | Decodificado a 240 × 160; pintado; leitura e PNG bem-sucedidos          |
| Outra origem, permissão concedida | `anonymous` mais cabeçalho de resposta   | Decodificado; pintado; leitura e PNG bem-sucedidos                      |
| Outra origem, sem requisição CORS | Sem atributo e sem cabeçalho de resposta | Decodificado e pintado; leitura e exportação lançaram `SecurityError`   |
| Outra origem, permissão negada    | `anonymous`, sem cabeçalho de resposta   | Decodificação rejeitada com `EncodingError`; nenhum desenho foi tentado |
| Arquivo ausente                   | 404 na mesma origem                      | Decodificação rejeitada com `EncodingError`; nenhum desenho foi tentado |

O caso sem CORS mostrava a arte visivelmente. Essa aparência não estabelecia permissão para ler ou exportar. Os casos de CORS negado e arquivo ausente falharam antes, portanto reescrever a geometria não resolveria nenhuma dessas falhas de requisição.

Os dois PNGs exportados reabriram a `480 × 320`. Nesta execução eram idênticos em bytes, com 10509 bytes cada. Na coordenada de bitmap `(192,160)`, a abertura era `RGBA (0,0,0,0)`; o canto também tinha alfa zero. A amostra verde-petróleo em `(192,80)` era `(23,107,91,255)`. Essas amostras verificam a abertura e o preenchimento deste arquivo, não todo pixel de borda ou recurso SVG.

Os retângulos brancos na página do navegador são fundos CSS atrás dos canvases. Não são tinta branca adicionada ao PNG. Se seu resultado precisa de fundo opaco, pinte esse fundo explicitamente antes de desenhar a imagem e verifique o arquivo exportado novamente.

## Mantenha o original editável separado do PNG

O PNG salvo contém pixels. Não carrega o caminho, círculo ou contorno interno editável originais. Mantenha `master.svg` como origem vetorial e escolha as dimensões do bitmap do canvas para o destino que realmente precisa de PNG. Ampliar um PNG existente depois não restaura a geometria de origem.

Um nome de arquivo SVG também não prova que toda a arte interna é geometria vetorial; use o [guia de inspeção de raster incorporado](https://perfectvector.com/pt-BR/blog/svg-contains-raster-image) quando um arquivo contém imagens vinculadas ou incorporadas.

Se sua arte de origem existe só como imagem raster e você precisa de contornos editáveis, o [fluxo de imagem para vetor do PerfectVector](https://perfectvector.com/pt-BR/image-to-vector) pode preparar um original SVG. Examine contorno, cores e aberturas antes de usá-lo nesta rotina de carregamento. A vetorização não corrige cabeçalhos CORS nem concede permissão de leitura do canvas.

## Perguntas frequentes

**Posso passar marcação SVG diretamente para drawImage()?**
Não. Este exemplo carrega um arquivo SVG em um HTMLImageElement e passa a imagem decodificada para drawImage(). Uma string de marcação não é esse objeto de imagem. Separe o carregamento do documento da construção de dados de caminhos Path2D.

**Por que a imagem aparece, mas a exportação PNG falha?**
Uma imagem de outra origem carregada sem permissão CORS pode contaminar o canvas depois de desenhada. No nosso caso sem CORS, a pintura funcionou, mas a leitura de pixels e a exportação lançaram SecurityError. Confira o modo da requisição e a resposta do servidor em vez de supor que a geometria SVG está quebrada.

**crossOrigin anonymous corrige qualquer URL de imagem?**
Não. Defina antes de src, e o servidor da imagem precisa fornecer uma resposta CORS compatível. Nossa mesma arte falhou na decodificação quando anonymous foi solicitado ao endpoint sem cabeçalho de permissão.

**Exportar canvas como PNG preserva caminhos SVG editáveis?**
Não. PNG é saída raster. Mantenha o SVG original separado se precisar editar caminhos, formas ou aberturas e examine o PNG no tamanho de entrega pretendido.

## Fontes

1. [MDN: CanvasRenderingContext2D.drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) — Objetos de imagem aceitos, tamanho de destino e dimensões intrínsecas.
2. [MDN: HTMLImageElement.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) — Promise de prontidão da imagem e rejeição de requisição/decodificação.
3. [MDN: Imagens com CORS](https://developer.mozilla.org/en-US/docs/Web/HTML/How_to/CORS_enabled_image) — Restrições de origem limpa para leitura e exportação de imagens desenhadas.
4. [MDN: HTMLImageElement.crossOrigin](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin) — Modo de requisição CORS para carregar imagens.
5. [MDN: HTMLCanvasElement.toBlob()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) — Geração de blob PNG, saída nula e SecurityError.
6. [MDN: SVG como imagem](https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG_as_an_image) — Contextos de imagem SVG e restrições de recursos externos.

***

Está trabalhando com um original raster que precisa virar arte editável? [Crie um original SVG com o PerfectVector](https://perfectvector.com/pt-BR/image-to-vector), examine contorno e aberturas e mantenha esse original enquanto verifica separadamente a renderização no canvas e o PNG exportado.

## Explore

- [Read the HTML article](https://perfectvector.com/pt-BR/blog/svg-canvas-image-export)
- [Ícones SVG no MapLibre: pixels e tamanho do símbolo](https://perfectvector.com/pt-BR/blog/maplibre-svg-symbol-image.md)
- [Imagens SVG no p5.js: carregue, escale e guarde a origem](https://perfectvector.com/pt-BR/blog/p5js-svg-artwork.md)
- [Product facts](https://perfectvector.com/product-facts.md)
- [FAQ](https://perfectvector.com/faq.md)
- [Pricing and credits](https://perfectvector.com/pricing.md)
