PerfectVector
Автор: Irene Kim

SVG.js: импорт графики, правка контура и экспорт SVG

Импортируйте доверенную разметку SVG в SVG.js, перекрасьте именованный контур и проверьте полный корень и экспорт дочерних элементов. Сохраняйте геометрию и проверяйте файлы.

9 мин чтения
На этой странице

Чтобы импортировать графику в SVG.js для правки отдельной части, передайте доверенную разметку SVG в .svg(), найдите нужный элемент по заданному при создании ID и измените его заливку. Для самостоятельного файла экспортируйте полный корень SVG графики. Экспорт только дочерних элементов — фрагмент: ему нужен корень с нужными размерами и viewBox, прежде чем передавать его как документ.

Это руководство использует оригинальный полый ромб и отдельный треугольник. Треугольник меняет охристый цвет на коралловый, а ромб сохраняет бирюзовую заливку и отверстие. Мы проверили полный пример ниже с SVG.js 3.2.6, закреплённым на официальном выпуске 3.2.6. Наблюдения относятся к двум простым созданным контурам, а не всем функциям другого SVG.

Решите, нужны ли живые фигуры или изображение

Оператор import JavaScript, дающий URL ресурса, решает задачу загрузки. Сам по себе он не помещает контуры файла в живое дерево SVG вашего редактора. Текущая документация SVG.js по импорту/экспорту описывает импорт разметки и получение внешнего элемента SVG либо его дочерних элементов.

ПредставлениеК чему даёт доступ наш примерПроверка передачи
Доверенная разметка в живом корне SVGИменованный контур accentПроверить отредактированный корень и заново открыть его экспорт
SVG, загруженный через элемент изображенияЭлемент изображения целикомПроверить содержимое изображения отдельно
Разметка только дочерних элементовДва элемента path без исходного корняОсознанно задать корень, размеры и viewBox

SVG внутри изображения всё ещё является содержимым SVG. Однако в нашем контрольном варианте с оболочкой изображения внешнее дерево SVG содержит один элемент image и не содержит прямых контуров; поиск accent в этом дереве ничего не находит. Он не проникает в документ встроенного изображения. MDN описывает отдельный контекст изображения SVG и его ограничения. Не выводите модель редактирования из резкой на вид отрисовки.

Для более широкого выбора встраивания прочитайте встроенный SVG и изображение. Если нужна объектная модель canvas в Fabric, разбор импорта Fabric.js описывает другой парсер и API редактирования.

Выполните правку именованного контура и сохраните каждое представление

Сохраните полный код ниже как starter.html в пустой папке. Раздавайте по HTTP, например через python3 -m http.server 8000, затем откройте http://localhost:8000/starter.html. Сценарий загружает закреплённый пакет из CDN, поэтому этому примеру нужна сеть.

Страница показывает исходную графику, живую отредактированную копию и контрольную оболочку изображения. Ссылки скачивают исходный мастер, полные корни до/после, текстовый фрагмент дочерних элементов, копию в новой оболочке и оболочку изображения. Отчёт читает пиксели SVG-изображений, нарисованных на canvas, а не экспортирует 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>
 

Импортированная разметка содержит вложенный корень с именем original-artwork. Пример выбирает этот корень перед экспортом, чтобы передаваемая копия имела созданную для неё область просмотра 240 × 160, не полагаясь на посторонний родительский контейнер. Затем выбирается accent внутри этого корня. SVG.js описывает ссылки по селекторам и методы элементов; явные имена частей устраняют зависимость от порядка контуров.

Код намеренно ограничен собственной фиксированной разметкой. Он не очищает загружаемые SVG от опасного содержимого. Разбор или вставка произвольной строки не устанавливает её безопасность; справочник MDN по DOMParser различает разбор и риски вставки недоверенного содержимого. Перед адаптацией этой процедуры к загрузкам разработайте отдельные правила проверки и доверия.

Проверяйте сохранённый результат, а не только живой предпросмотр

Наш реальный браузерный запуск дал следующие проверки:

Сохранённое представлениеКонтуры в дереве документаИзображенияЗаливка треугольника
Исходный мастер20#d4a53a
Полный корень до правки20#d4a53a
Полный корень после правки20#b95434
Дочерние элементы в новом полном корне20#b95434
Оболочка изображения01Исходная охра внутри данных изображения

Обе исходные строки d контуров оставались одинаковыми в экспорте до/после. Образец внутри треугольника изменился с RGBA (212, 165, 58, 255) на (185, 84, 52, 255). Образец внутри ромба остался (23, 107, 91, 255), а отверстие и внешний угол сохранили альфа-канал 0. Все пять самостоятельных файлов SVG заново открылись как изображения с собственными размерами 240 × 160.

Измените одну именованную часть
Концептуальное сравнение одинаковой графики полого ромба, где только отдельный треугольник меняет золотой цвет на коралловый
Концептуальная иллюстрация изменения цвета отдельной части. Декоративные границы и стрелки — подсказки схемы; фактические доказательства дают выполненный пример, перечень сохранённых исходных элементов и проверки пикселей браузера.

Результаты устанавливают нужную правку для этого примера. Они не устанавливают побайтового сохранения XML, поддержки всех фильтров или CSS либо пригодности для производственного процесса. Сериализация библиотеки может менять разметку документа, сохраняя именно эти строки контуров. Храните исходный мастер рядом с передаваемой копией.

Для своей графики проверяйте реально используемые структуры: имена и группы, обрезку, градиенты, преобразования, обводки и текст. Заново откройте экспортированный файл в принимающем приложении и повторите нужную правку. Руководство по редактированию SVG поможет диагностировать исходную структуру до изменения кода импорта.

Считайте экспорт дочерних элементов осознанным фрагментом

В этом запуске artwork.svg(false) вернул два контура без внешнего тега svg. Он опустил область просмотра корня графики. Отдельный корень SVG rewrapped задаёт размеры 240 × 160 и тот же viewBox перед приёмом дочерних элементов; затем экспортированный файл отрисовывает проверенный коралловый треугольник.

Выбирайте полный документ или фрагмент по целевой среде. Для самостоятельного скачивания сохраняйте полный нужный корень. Для вставки в существующий рисунок решите, какую родительскую систему координат, наследуемые стили и определения будут использовать дочерние элементы. В этом простом примере нет внешних ресурсов или общих определений, поэтому он не проверяет, переносит ли фрагмент со ссылками все нужные зависимости.

Наш экспорт оболочки изображения сохранил закодированный SVG, чьи декодированные байты совпали с исходным мастером. Этот контроль показывает различие представлений, а не преобразование растра. Если исходник уже содержит пригодную векторную геометрию, исправьте выбор элемента или границу экспорта, прежде чем трассировать заново.

Если в исходнике нет контуров для правки

Если вашей плоской PNG- или JPG-иллюстрации нужны отдельно перекрашиваемые области, подготовьте вариант SVG с PerfectVector. Проверьте контуры и отверстия, затем задайте имена частей для приложения. Векторизация не знает, что область нужно назвать accent, и не гарантирует соответствия импортированного документа модели данных редактора.

Храните подходящий мастер SVG, если эти фигуры уже существуют. Используйте обзор векторизации, чтобы решить, нужна ли вообще подготовка растра к вектору до вашего кода.

Частые вопросы

Может ли SVG.js импортировать строку SVG для редактирования? Да. Пример импортирует собственную доверенную разметку в живой контейнер SVG, выбирает созданный контур и меняет заливку. Произвольные загрузки требуют отдельных правил доверия и проверки; API разметки не является средством очистки.

Почему графика видна, но контур акцента не находится? Проверьте, импортировали ли вы живую разметку или поместили изображение. Наша оболочка изображения показывает SVG-графику, но не предоставляет прямой контур accent в своём дереве. Также проверьте выбранного родителя и реальные ID исходника.

Является ли экспорт только дочерних элементов полным файлом SVG? Не в этом примере. Он содержит два контура без внешней области просмотра SVG. Используйте полный нужный корень для самостоятельного файла либо явно задайте целевой корень и систему координат при вставке фрагмента.

Доказывает ли успешная правка сохранение всех функций SVG при экспорте? Нет. Мы проверили два простых контура, значения заливки, точные данные контуров и пять заново открытых файлов. Проверяйте конкретные функции и принимающее приложение, нужные вашей графике, и сохраняйте исходный мастер.

Источники

  1. SVG.js — Импорт / Экспорт, версия 3.2 — Импорт разметки и сериализация полного корня либо дочерних элементов.
  2. SVG.js — Ссылки / Создание элементов, версия 3.2 — Поиск именованных элементов и изменение их свойств.
  3. SVG.js — Выпуск 3.2.6 — Официальный выпуск, закреплённый в выполненном примере.
  4. MDN — SVG как изображение — Контекст встраивания изображения и ограничения.
  5. MDN — DOMParser.parseFromString — Разбор разметки и отдельная обработка недоверенного входа.

Если иллюстрация существует лишь как растровые пиксели и нуждается в правках отдельных частей, подготовьте векторный вариант своей графики. Проверьте очертание и отверстия, сохраните мастер, затем подтвердите правку именованной части и сохранённый SVG в принимающем процессе.

Ещё из блога

PerfectVector

Начните с более чистого SVG,
который проще редактировать

Без банковской карты