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

# SVG na Canvas: wczytaj grafikę przed eksportem PNG

> Wczytaj całe SVG przez Image.decode, narysuj w wybranym rozmiarze bitmapy, sprawdź CORS i odczyt PNG oraz oddziel edytowalne źródło od eksportowanych pikseli.

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

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

Aby narysować całe SVG na canvas, wczytaj je jako obraz, poczekaj na `image.decode()` i przekaż obraz do `drawImage()`. Potem osobno sprawdź eksport PNG: obraz może pojawić się na canvas, choć przeglądarka blokuje odczyt lub zapis jego pikseli.

Ta metoda maluje dokument SVG jako obraz. Nie udostępnia canvas edytowalnych ścieżek SVG. Jeśli chcesz odtworzyć wybrane kontury, użyj [poradnika SVG Path2D](https://perfectvector.com/pl/blog/canvas-path2d-svg). Zachowaj oryginalny SVG niezależnie od wybranej metody wyświetlania.

## Oddziel dekodowanie, malowanie i eksportowanie

`HTMLImageElement` jest akceptowanym wejściem [canvas drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage). Docelowa szerokość i wysokość kontrolują rozmiar malowania. [Image.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) zwraca promise spełnianą po zdekodowaniu obrazu; błędne żądanie lub problem dekodowania może ją odrzucić.

Udane dekodowanie to tylko pierwsza kontrola. Obraz z innego źródła wczytany bez uprawnienia CORS nadal może zostać narysowany, ale zanieczyszcza canvas. Odczyt pikseli i eksport wtedy zawodzą. [Poradnik obrazów z CORS MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/How_to/CORS_enabled_image) wyjaśnia różnicę.

**Zachowaj źródło, sprawdź piksele**

![Schemat koncepcyjny pustego rombu i koła jako konturów źródłowych, gładkiej renderowanej grafiki i wyniku w siatce pikseli](https://perfectvector.com/blog/svg-canvas-image-export/image-and-png.webp)

*Ilustracja: kontury źródłowe i namalowane piksele są różnymi reprezentacjami. Ramki, strzałki i zgrubne siatki są koncepcyjne; wyniki przeglądarkowe poniżej pochodzą z niezależnie wykonanego oryginalnego testu.*

## Zbuduj samowystarczalny oryginalny SVG

Zapisz go jako `master.svg`. Zawiera jedną ścieżkę i jedno koło, bez osadzonego obrazu, fontu lub zewnętrznej zależności. Wewnętrzny romb i otaczający obszar są przezroczyste w źródle.

```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>
```

Używamy całego pliku jako obrazu, razem z oboma kształtami i `viewBox`. W przeciwieństwie do wyodrębnienia samego `d` ścieżki prosimy renderer obrazów SVG przeglądarki o namalowanie dokumentu.

Przykład jest celowo samowystarczalny. SVG używany jako obraz ma ograniczenia, między innymi zasobów zewnętrznych i skryptów; zobacz [poradnik SVG jako obraz MDN](https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG_as_an_image). Nie traktuj udanego dekodowania małego pliku jako dowodu, że dowolny SVG wczyta zewnętrzne fonty, style lub powiązaną grafikę. Wybierając sposób przekazania, porównaj [SVG inline z elementem obrazu](https://perfectvector.com/pl/blog/inline-svg-vs-img).

## Uruchom dwa lokalne źródła z różnymi odpowiedziami CORS

Źródło obejmuje port. Poniższy wyłącznie lokalny serwer udostępnia te same bajty SVG przez dwa źródła. W drugim `/cors/master.svg` zawiera `Access-Control-Allow-Origin: *`, a `/plain/master.svg` nie. Izoluje to uprawnienie odpowiedzi od grafiki.

Zapisz kod jako `serve-proof.py` obok SVG i HTML poniżej. Uruchom `python3 serve-proof.py`, a potem otwórz `http://127.0.0.1:8770/starter.html`. Oba porty muszą być wolne; jeśli je zmienisz, zaktualizuj serwer i HTML razem. Naciśnij Enter w terminalu, aby zatrzymać oba serwery.

```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()
```

Ten liberalny nagłówek należy do lokalnego testu udostępniającego naszą własną grafikę. Dla produkcyjnego hosta obrazów skonfiguruj odpowiednie dozwolone źródło na serwerze, który kontrolujesz. Ustawienie atrybutu obrazu nie daje dostępu do zawartości innego serwera.

## Zdekoduj obraz przed rysowaniem

Zapisz kompletną stronę jako `starter.html`. Każdy przypadek ma własny canvas, więc zanieczyszczony przypadek nie wpływa na udane. Ustaw `crossOrigin` przed `src` dla żądań wymagających CORS, zgodnie z [opisem crossOrigin MDN](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin).

Bitmapa canvas ma jawnie `480 × 320`, a rozmiar wyświetlania CSS `240 × 160`. Wewnętrzne wymiary oryginalnego obrazu to `240 × 160`, a `drawImage()` skaluje go do wybranej bitmapy. To wybrane wymiary, a nie pomiar współczynnika pikseli urządzenia.

```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>
```

Funkcja eksportu obsługuje zarówno zgłoszony wyjątek, jak i wynik blob równy null. [Canvas.toBlob()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) obsługuje PNG i może zgłosić `SecurityError`, gdy canvas nie jest czysty względem źródła. Dwa udane przypadki dodają odnośnik Save PNG; widoczny raport pomija dane base64.

## Odczytaj etap błędu przed zmianą SVG

Wykonaliśmy dokładnie ten przykład w jednym środowisku Chrome, a potem ponownie otworzyliśmy oba zapisane PNG. Obserwacje dotyczą oryginalnego samowystarczalnego pliku i tych dwóch lokalnych źródeł.

| Przypadek                          | Żądanie obrazu                        | Zaobserwowane rysowanie/odczyt/eksport                              |
| ---------------------------------- | ------------------------------------- | ------------------------------------------------------------------- |
| To samo źródło                     | Lokalny SVG, brak atrybutu CORS       | Zdekodowano w 240 × 160; namalowano; odczyt i PNG udane             |
| Inne źródło, uprawnienie przyznane | `anonymous` i nagłówek odpowiedzi     | Zdekodowano; namalowano; odczyt i PNG udane                         |
| Inne źródło, brak żądania CORS     | Brak atrybutu i nagłówka odpowiedzi   | Zdekodowano i namalowano; odczyt i eksport zgłosiły `SecurityError` |
| Inne źródło, uprawnienie odrzucone | `anonymous`, brak nagłówka odpowiedzi | Dekodowanie odrzucono z `EncodingError`; nie próbowano rysować      |
| Brakujący plik                     | 404 z tego samego źródła              | Dekodowanie odrzucono z `EncodingError`; nie próbowano rysować      |

Przypadek bez CORS widocznie pokazywał grafikę. Wygląd nie oznaczał prawa do jej odczytu lub eksportu. Przypadek odrzuconego CORS i brakującego pliku zawiodły wcześniej, więc przepisanie geometrii nie naprawiłoby żadnego błędu żądania.

Oba eksportowane PNG otworzyły się ponownie jako `480 × 320`. W tym wykonaniu były identyczne bajtowo, każdy miał 10509 bajtów. We współrzędnej bitmapy `(192,160)` otwór miał `RGBA (0,0,0,0)`; narożnik także miał alfa zero. Morskozielona próbka w `(192,80)` wynosiła `(23,107,91,255)`. Próbki sprawdzają otwór i wypełnienie tego pliku, nie każdy piksel krawędzi ani każdą funkcję SVG.

Białe prostokąty na stronie przeglądarki są tłami CSS za canvas. Nie są białym malowaniem dodanym do PNG. Jeśli wynik wymaga nieprzezroczystego tła, namaluj je jawnie przed narysowaniem obrazu i ponownie sprawdź eksportowany plik.

## Zachowaj edytowalny wzorzec oddzielnie od PNG

Zapisany PNG zawiera piksele. Nie przenosi oryginalnej ścieżki, koła ani edytowalnego konturu wewnętrznego. Zachowaj `master.svg` jako wektorowe źródło i wybierz wymiary bitmapy canvas dla miejsca docelowego, które faktycznie potrzebuje PNG. Późniejsze powiększanie istniejącego PNG nie odtwarza geometrii źródła.

Sama nazwa SVG także nie dowodzi, że cała grafika wewnątrz jest wektorowa; użyj [poradnika kontroli osadzonego rastra](https://perfectvector.com/pl/blog/svg-contains-raster-image), gdy plik zawiera powiązane lub osadzone obrazy.

Jeśli grafika źródłowa istnieje tylko jako raster i potrzebujesz edytowalnych konturów, [procedura zamiany obrazu na wektor PerfectVector](https://perfectvector.com/pl/image-to-vector) może przygotować wzorzec SVG. Sprawdź kontur, kolory i otwory przed użyciem go w tej procedurze wczytywania. Wektoryzacja nie naprawia nagłówków CORS ani nie daje prawa do odczytu canvas.

## Najczęstsze pytania

**Czy mogę przekazać kod SVG bezpośrednio do drawImage()?**
Nie. Przykład wczytuje plik SVG do HTMLImageElement i przekazuje zdekodowany obraz do drawImage(). Ciąg znaczników nie jest tym obiektem obrazu. Oddziel wczytywanie dokumentu od budowania danych ścieżek Path2D.

**Dlaczego obraz jest widoczny, ale eksport PNG nie działa?**
Obraz z innego źródła wczytany bez uprawnień CORS może zanieczyścić canvas po narysowaniu. W naszym przypadku bez CORS malowanie się udało, ale odczyt pikseli i eksport zgłosiły SecurityError. Sprawdź tryb żądania i odpowiedź serwera, zamiast zakładać uszkodzenie geometrii SVG.

**Czy crossOrigin anonymous naprawia każdy adres obrazu?**
Nie. Ustaw go przed src, a serwer obrazu musi dostarczyć zgodną odpowiedź CORS. Ta sama grafika nie przeszła dekodowania, gdy żądano anonymous z punktu bez nagłówka uprawnienia.

**Czy eksport canvas do PNG zachowuje edytowalne ścieżki SVG?**
Nie. PNG jest wynikiem rastrowym. Zachowaj oryginalny SVG oddzielnie do edycji ścieżek, kształtów lub otworów i sprawdź PNG w docelowym rozmiarze przekazania.

## Źródła

1. [MDN: CanvasRenderingContext2D.drawImage()](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) — Akceptowane obiekty obrazu, wymiary docelowe i wewnętrzne.
2. [MDN: HTMLImageElement.decode()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/decode) — Promise gotowości obrazu i odrzucanie żądania/dekodowania.
3. [MDN: Obrazy z CORS](https://developer.mozilla.org/en-US/docs/Web/HTML/How_to/CORS_enabled_image) — Ograniczenia czystości źródła przy odczycie i eksporcie narysowanych obrazów.
4. [MDN: HTMLImageElement.crossOrigin](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/crossOrigin) — Tryb żądania CORS przy wczytywaniu obrazu.
5. [MDN: HTMLCanvasElement.toBlob()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) — Generowanie blob PNG, wynik null i SecurityError.
6. [MDN: SVG jako obraz](https://developer.mozilla.org/en-US/docs/Web/SVG/Guides/SVG_as_an_image) — Konteksty obrazu SVG i ograniczenia zasobów zewnętrznych.

***

Pracujesz z rastrowym oryginałem wymagającym edytowalnej grafiki? [Utwórz wzorzec SVG przez PerfectVector](https://perfectvector.com/pl/image-to-vector), sprawdź kontur i otwory, a potem zachowaj wzorzec, kontrolując osobno renderowanie canvas oraz eksportowany PNG.

## Explore

- [Read the HTML article](https://perfectvector.com/pl/blog/svg-canvas-image-export)
- [Ikony SVG MapLibre: sprawdź piksele i rozmiar symbolu](https://perfectvector.com/pl/blog/maplibre-svg-symbol-image.md)
- [Obrazy SVG w p5.js: wczytaj, skaluj i zachowaj źródło](https://perfectvector.com/pl/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)
