PerfectVector
Oleh Irene Kim

SVG.js: Impor Gambar, Edit Path, dan Ekspor SVG

Impor markup SVG tepercaya ke SVG.js, warnai ulang path bernama, dan periksa ekspor root lengkap versus anak saja. Simpan geometri asli dan periksa berkas tersimpan.

9 menit baca
Di halaman ini

Untuk mengimpor gambar ke SVG.js demi mengedit satu bagian, teruskan markup SVG tepercaya ke .svg(), temukan elemen yang dimaksud melalui ID yang dibuat, lalu ubah fill elemen itu. Ekspor root SVG lengkap gambar untuk berkas mandiri. Ekspor anak saja merupakan fragmen: fragmen membutuhkan root dengan dimensi dan viewBox yang dimaksud sebelum diserahkan sebagai dokumen.

Panduan ini memakai wajik berlubang asli dan segitiga terpisah. Segitiga berubah dari oker menjadi koral, sementara wajik mempertahankan fill hijau kebiruan dan bukaannya. Kami menguji contoh lengkap di bawah dengan SVG.js 3.2.6, dikunci ke rilis 3.2.6 resmi. Pengamatan ini berkaitan dengan dua path sederhana yang dibuat sendiri, bukan setiap fitur yang mungkin ada di SVG lain.

Tentukan apakah Anda membutuhkan bentuk hidup atau gambar

Pernyataan import JavaScript yang menghasilkan URL aset menjawab persoalan pemuatan. Pernyataan itu sendiri tidak memasukkan path berkas ke pohon SVG hidup editor Anda. Dokumentasi impor/ekspor SVG.js saat ini menjelaskan impor markup dan pengambilan elemen SVG luar atau anak-anaknya.

RepresentasiYang bisa diakses dalam contoh kamiPemeriksaan penyerahan
Markup tepercaya diimpor ke root SVG hidupPath bernama accentPeriksa root yang diedit dan buka kembali hasil ekspornya
SVG dimuat melalui elemen gambarElemen gambar secara keseluruhanPeriksa payload gambar secara terpisah
Markup anak sajaDua elemen path tanpa root asliSediakan root, dimensi, dan viewBox dengan sengaja

SVG di dalam gambar tetap konten SVG. Namun dalam kontrol pembungkus gambar kami, pohon SVG wadah memiliki satu elemen image tanpa path langsung; mencari accent di pohon itu tidak menemukan apa pun. Pencarian tidak menjangkau dokumen gambar tertanam. MDN menjelaskan konteks gambar SVG yang terpisah serta pembatasannya. Jangan menyimpulkan model pengeditan dari rendering yang terlihat tajam.

Untuk keputusan penyematan yang lebih luas, baca SVG inline versus gambar. Jika Anda menginginkan model objek canvas Fabric, panduan impor Fabric.js membahas parser dan API pengeditan berbeda.

Jalankan satu pengeditan path bernama dan simpan tiap representasi

Simpan kode lengkap di bawah sebagai starter.html dalam folder kosong. Sajikan melalui HTTP, misalnya dengan python3 -m http.server 8000, lalu buka http://localhost:8000/starter.html. Skrip memuat paket versi terkunci dari CDN-nya, sehingga contoh ini membutuhkan koneksi jaringan.

Halaman menampilkan gambar asli, salinan hidup yang diedit, dan kontrol pembungkus gambar. Tautannya mengunduh master asli, root lengkap sebelum/sesudah, fragmen teks anak saja, salinan yang dibungkus ulang, dan pembungkus gambar. Laporan membaca piksel dari gambar SVG yang dilukis ke canvas; laporan tidak mengekspor PNG.

<!doctype html>
<html lang="en">
<meta charset="utf-8">
<title>Original SVG.js artwork import and export</title>
<style>
  body { margin: 24px; font: 16px system-ui; background: #f6f2e8; }
  main { display: grid; grid-template-columns: repeat(3, 260px); gap: 20px; }
  figure { margin: 0; }
  svg, img { display: block; background: white; border: 1px solid #bbb; }
  pre { white-space: pre-wrap; font-size: 12px; }
</style>
<h1>Trusted artwork, one fill edit and two export forms</h1>
<main>
  <figure><img id="original" alt="Original artwork"><figcaption>Original SVG image</figcaption></figure>
  <figure><div id="live"></div><figcaption>Imported live SVG, accent edited</figcaption></figure>
  <figure><div id="wrapper"></div><figcaption>Image wrapper, original artwork</figcaption></figure>
</main>
<p id="downloads"></p>
<pre id="report"></pre>
<script src="https://cdn.jsdelivr.net/npm/@svgdotjs/svg.js@3.2.6/dist/svg.min.js"></script>
<script>
  const markup = '<svg xmlns="http://www.w3.org/2000/svg" id="original-artwork" width="240" height="160" viewBox="0 0 240 160">'
    + '<path id="body" d="M80 20 L140 80 L80 140 L20 80 Z M80 56 L104 80 L80 104 L56 80 Z" fill="#176b5b" fill-rule="evenodd"/>'
    + '<path id="accent" d="M172 48 L220 80 L172 112 Z" fill="#d4a53a"/></svg>';
  const url = text => 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(text);
  async function pixels(text) {
    const image = new Image();
    image.src = url(text);
    await image.decode();
    const canvas = document.createElement('canvas');
    canvas.width = 240;
    canvas.height = 160;
    const ctx = canvas.getContext('2d');
    ctx.drawImage(image, 0, 0);
    const rgba = (x, y) => [...ctx.getImageData(x, y, 1, 1).data];
    return { naturalWidth: image.naturalWidth, naturalHeight: image.naturalHeight,
      opening: rgba(80, 80), body: rgba(80, 40), accent: rgba(188, 80), corner: rgba(0, 0) };
  }
  function inventory(text) {
    const node = new DOMParser().parseFromString(text, 'image/svg+xml').documentElement;
    return { root: node.localName, viewBox: node.getAttribute('viewBox'),
      paths: [...node.querySelectorAll('path')].map(p => ({ id: p.id, d: p.getAttribute('d'), fill: p.getAttribute('fill') })),
      imageCount: node.querySelectorAll('image').length };
  }
  async function run() {
    document.getElementById('original').src = url(markup);
    const host = SVG().addTo('#live').size(240, 160).viewbox(0, 0, 240, 160);
    host.svg(markup);
    const artwork = host.findOne('#original-artwork');
    const before = artwork.svg();
    const accent = artwork.findOne('#accent');
    const beforeD = accent.attr('d');
    accent.fill('#b95434');
    const full = artwork.svg();
    const children = artwork.svg(false);
    const rewrapped = SVG().size(240, 160).viewbox(0, 0, 240, 160);
    rewrapped.svg(children);
    const wrappedFull = rewrapped.svg();
    const imageWrapper = SVG().addTo('#wrapper').size(240, 160).viewbox(0, 0, 240, 160);
    imageWrapper.image(url(markup)).size(240, 160);
    const wrapperFull = imageWrapper.svg();
    const files = { 'master.svg': markup, 'before.svg': before, 'edited.svg': full,
      'children-only.txt': children, 'rewrapped.svg': wrappedFull, 'image-wrapper.svg': wrapperFull };
    for (const [name, text] of Object.entries(files)) {
      const a = document.createElement('a');
      a.href = name.endsWith('.txt') ? 'data:text/plain;charset=utf-8,' + encodeURIComponent(text) : url(text);
      a.download = name;
      a.textContent = name;
      a.style.marginRight = '12px';
      document.getElementById('downloads').append(a);
    }
    const results = {};
    for (const [name, text] of Object.entries(files)) {
      if (name.endsWith('.svg')) results[name] = { inventory: inventory(text), pixels: await pixels(text) };
    }
    document.getElementById('report').textContent = JSON.stringify({
      requestedPackageVersion: '3.2.6',
      scriptURL: document.querySelector('script[src]').src,
      selectedAccentFound: Boolean(accent), selectedAccentDUnchanged: beforeD === accent.attr('d'),
      allPathDUnchanged: JSON.stringify(inventory(before).paths.map(p => p.d)) === JSON.stringify(inventory(full).paths.map(p => p.d)),
      childrenHasOuterSVG: /<svg[\s>]/i.test(children),
      wrapperDirectPathCount: imageWrapper.find('path').length,
      wrapperAccentFound: Boolean(imageWrapper.findOne('#accent')), results
    }, null, 2);
  }
  run();
</script>
</html>
 

Markup yang diimpor berisi root bersarang bernama original-artwork. Contoh memilih root itu sebelum mengekspor, sehingga salinan penyerahan memiliki viewport 240 × 160 yang dibuat untuknya, bukan bergantung pada wadah induk yang tidak terkait. Kemudian contoh memilih accent di dalam root itu. SVG.js mendokumentasikan referensi berbasis selector dan metode elemen; nama bagian eksplisit menghindari ketergantungan pada urutan path.

Kode sengaja dibatasi pada markup tetapnya sendiri. Ini bukan pembersih unggahan SVG. Mengurai atau memasukkan string sembarang tidak membuktikannya aman; referensi DOMParser MDN membedakan penguraian dari risiko memasukkan konten tidak tepercaya. Rancang kebijakan validasi dan kepercayaan terpisah sebelum menyesuaikan prosedur ini untuk unggahan.

Periksa hasil tersimpan, bukan hanya pratinjau hidup

Eksekusi peramban sebenarnya menghasilkan pemeriksaan berikut:

Representasi tersimpanPath dalam pohon dokumennyaGambarFill segitiga
Master asli20#d4a53a
Root lengkap sebelum pengeditan20#d4a53a
Root lengkap setelah pengeditan20#b95434
Anak ditempatkan dalam root lengkap baru20#b95434
Pembungkus gambar01Oker asli di dalam payload gambarnya

Kedua string d path asli tetap identik dalam ekspor sebelum/sesudah. Sampel bagian dalam segitiga berubah dari RGBA (212, 165, 58, 255) menjadi (185, 84, 52, 255). Sampel bagian dalam wajik tetap (23, 107, 91, 255); bukaan dan sudut luarnya tetap memiliki alfa 0. Kelima berkas SVG mandiri dibuka kembali sebagai gambar dengan dimensi intrinsik 240 × 160.

Ubah satu bagian bernama
Perbandingan konseptual gambar wajik berlubang yang sama dengan hanya segitiga terpisah berubah dari emas menjadi koral
Ilustrasi konseptual pengeditan warna satu bagian. Batas dekoratif dan panah adalah petunjuk diagram; kode awal yang dijalankan, inventaris sumber tersimpan, dan pemeriksaan piksel peramban memberikan bukti sebenarnya.

Hasil tersebut membuktikan pengeditan yang dimaksud untuk contoh uji ini. Hasil tidak membuktikan pelestarian XML identik per byte, dukungan semua filter atau CSS, atau kesesuaian untuk alur manufaktur. Serialisasi pustaka dapat mengubah markup dokumen sambil menjaga string path tertentu ini tetap utuh. Simpan master asli bersama salinan penyerahan.

Untuk gambar sendiri, periksa struktur yang benar-benar dipakai: nama dan grup, clipping, gradien, transformasi, stroke, serta teks. Buka kembali berkas hasil ekspor dalam aplikasi penerima, lalu ulangi pengeditan yang dimaksud. Panduan pengeditan SVG dapat membantu mendiagnosis struktur sumber sebelum Anda mengubah kode impor.

Perlakukan ekspor anak saja sebagai fragmen yang disengaja

Dalam eksekusi ini, artwork.svg(false) mengembalikan dua path tanpa tag svg luar. Ekspor menghilangkan viewport root gambar. Root SVG rewrapped terpisah menyediakan dimensi 240 × 160 dan viewBox yang sama sebelum menerima anak tersebut; berkas ekspornya kemudian merender segitiga koral yang telah diperiksa.

Pilih dokumen lengkap atau fragmen berdasarkan tujuan. Untuk unduhan mandiri, pertahankan root lengkap yang dimaksud. Untuk penyisipan ke gambar yang ada, tentukan sistem koordinat induk, gaya warisan, dan definisi yang akan dipakai anak-anak itu. Contoh uji sederhana ini tidak memiliki sumber daya eksternal atau definisi bersama, sehingga tidak menguji apakah fragmen berisi referensi membawa setiap dependensi yang dibutuhkan.

Ekspor pembungkus gambar kami mempertahankan SVG terkode yang byte hasil dekodenya cocok dengan master asli. Kontrol itu menunjukkan perbedaan representasi, bukan konversi raster. Jika sumber sudah berupa geometri vektor yang bisa dipakai, perbaiki pemilihan elemen atau batas ekspor sebelum menjiplaknya ulang.

Ketika sumber tidak memiliki path untuk diedit

Jika ilustrasi PNG atau JPG datar Anda membutuhkan wilayah yang bisa diwarnai ulang secara terpisah, siapkan kandidat SVG dengan PerfectVector. Periksa kontur dan bukaan, lalu buat nama bagian yang dibutuhkan aplikasi. Vektorisasi tidak tahu bahwa satu wilayah seharusnya bernama accent atau menjamin dokumen impor sesuai model data editor.

Simpan master SVG yang sesuai ketika bentuk tersebut sudah ada. Gunakan ikhtisar vektorisasi untuk menentukan apakah persiapan raster-ke-vektor memang perlu berada sebelum kode Anda.

Pertanyaan umum

Bisakah SVG.js mengimpor string SVG untuk diedit? Bisa. Kode awal ini mengimpor markup tepercayanya sendiri ke wadah SVG hidup, memilih path yang dibuat, dan mengubah fill-nya. Unggahan sembarang memerlukan kebijakan kepercayaan serta validasi terpisah; API markup bukan pembersih.

Mengapa gambar terlihat tetapi path aksennya tidak ditemukan? Periksa apakah Anda mengimpor markup hidup atau menempatkan gambar. Kontrol pembungkus gambar kami menampilkan gambar SVG tetapi tidak memperlihatkan path accent langsung dalam pohon pembungkus. Periksa juga induk terpilih dan ID sumber yang sebenarnya.

Apakah ekspor anak saja merupakan berkas SVG lengkap? Tidak dalam contoh uji ini. Ekspor berisi dua path tanpa viewport SVG luar. Gunakan root lengkap yang dimaksud untuk berkas mandiri, atau sediakan root tujuan dan sistem koordinat secara eksplisit saat memasukkan fragmen.

Apakah pengeditan berhasil membuktikan ekspor mempertahankan semua fitur SVG? Tidak. Kami memeriksa dua path sederhana, nilai fill, data path persis, dan lima berkas yang dibuka kembali. Uji fitur khusus serta aplikasi penerima yang dibutuhkan gambar Anda, dan simpan master asli.

Sumber

  1. SVG.js — Impor / Ekspor, versi 3.2 — Impor markup dan serialisasi root lengkap versus anak saja.
  2. SVG.js — Merujuk / Membuat elemen, versi 3.2 — Menemukan elemen bernama dan mengubah propertinya.
  3. SVG.js — Rilis 3.2.6 — Rilis resmi yang dikunci oleh kode awal yang dijalankan.
  4. MDN — SVG sebagai gambar — Konteks penyematan gambar dan pembatasannya.
  5. MDN — DOMParser.parseFromString — Mengurai markup dan menangani masukan tidak tepercaya secara terpisah.

Jika ilustrasi hanya ada sebagai piksel raster dan memerlukan pengeditan per bagian, siapkan kandidat vektor dari gambar Anda sendiri. Periksa kontur dan bukaannya, simpan master, lalu buktikan pengeditan bagian bernama serta SVG tersimpan dalam alur penerima.

Lebih banyak dari blog

PerfectVector

Mulai dengan SVG yang lebih rapi
dan lebih mudah diedit

Tanpa kartu kredit