PerfectVector
Автор: Irene Kim7 мин чтения

Булевы операции SVG в Paper.js: вырезание и объединение

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

На этой странице

Импортируйте SVG, найдите нужные объекты контуров, затем вызовите unite() для объединения заполненных областей или subtract() для удаления одной области из другой. Сохраните операнды до проверки результата и заново откройте экспортированный SVG перед использованием в другом месте.

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

Начните с распознаваемой геометрии с заливкой

Импортер SVG Paper.js принимает разметку SVG, элемент SVG или URL. Этим способам нужна разная обработка загрузки: этот пример импортирует встроенную строку; удаленный файл следует обрабатывать в обратном вызове импорта после загрузки.

Для этой задачи операндами должны быть объекты Path или CompoundPath. Группа — контейнер, а растровое изображение не дает границы, необходимой для булевой операции контуров. Если файл ведет себя только как одна картинка, сначала проверьте почему SVG не разгруппировывается.

Используйте ID для частей, которыми управляете. Не предполагайте, что children[0] означает «логотип» в произвольных экспортированных файлах. Проверяйте незнакомую графику и назначайте части намеренно. Сохраняйте существующий составной контур, если его подконтуры уже задают нужные отверстия.

Запустите небольшой импорт, объединение и вычитание

Мы проверили следующий код с Paper.js 0.12.18 в браузере. Графика — исходный SVG, созданный вручную: квадратное тело, перекрывающийся выступ и белый квадрат, отмечающий нужное отверстие. Это не образец преобразования PerfectVector.

В пустой папке установите библиотеку закрепленной версии:

npm install --save-exact paper@0.12.18

Сохраните это как index.html:

<!doctype html>
<meta charset="utf-8">
<title>SVG Boolean example</title>
<canvas id="work" width="300" height="220" hidden></canvas>
<div id="result" style="background:#d8e8e0; width:300px"></div>
<pre id="svg-output"></pre>
<script src="node_modules/paper/dist/paper-full.min.js"></script>
<script src="example.js"></script>

Сохраните это как example.js, затем откройте HTML в браузере:

paper.setup(document.getElementById('work'));
const source = `<svg xmlns="http://www.w3.org/2000/svg" width="300" height="220" viewBox="0 0 300 220">
  <path id="body" fill="#176b62" d="M40 40H180V180H40Z"/>
  <path id="tab" fill="#ee9852" d="M160 80H260V140H160Z"/>
  <path id="hole" fill="#ffffff" d="M80 80H130V130H80Z"/>
</svg>`;
const imported = paper.project.importSVG(source, { insert: false, expandShapes: true });
function operand(name) {
  const item = imported.getItem({ name });
  if (!(item instanceof paper.Path || item instanceof paper.CompoundPath)) {
    throw new Error(`Expected path geometry for ${name}`);
  }
  return item;
}
const joined = operand('body').unite(operand('tab'), { insert: false });
const cut = joined.subtract(operand('hole'), { insert: false });
cut.fillColor = '#176b62';
cut.strokeColor = null;
paper.project.activeLayer.addChild(cut);
const output = paper.project.exportSVG({ asString: true, bounds: new paper.Rectangle(0, 0, 300, 220) });
document.getElementById('result').innerHTML = output;
document.getElementById('svg-output').textContent = output;

Импорт остается вне сцены благодаря insert: false. expandShapes: true просит импортер превратить поддерживаемые примитивные фигуры в контуры; наш образец уже содержит элементы path. Явная проверка класса все равно важна, поскольку импортированный ID может обозначать контейнер или другой тип объекта.

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

joined.subtract(hole) удаляет отверстие из объединенного силуэта. Перестановка операндов задает другой вопрос и может дать пустой или неожиданный результат. Режим вычитания по умолчанию в Paper.js рассматривает операнды как области. Его параметр trace относится к булевой геометрии; он не связан с трассировкой PNG в векторы.

Браузерное сравнение трех импортированных контуров SVG, объединенного силуэта с прозрачным квадратным отверстием и заново открытого экспортированного результата
Полосатый фон остается скрытым за исходной белой заплаткой и просвечивает через вычтенное отверстие. Экспорт сохраняет это отверстие при повторном импорте.

Проверьте результат как геометрию и как файл

В этом примере объединение вернуло Path; вычитание вернуло CompoundPath с двумя контурами. Итоговые границы были x = 40, y = 40, ширина = 220, высота = 140 в единицах SVG. Изображение расположено внутри экспортной области просмотра 300 × 220, поэтому границы и размер документа намеренно различаются.

Мы проверили центр отверстия (105, 105): он был внутри объединенного силуэта и снаружи результата вычитания. Точка в сплошном теле (60, 60) осталась внутри. Повторный импорт экспортированного SVG сохранил границы и снова исключил центр отверстия. Это результаты для данного простого образца, а не гарантия для любого импортированного файла.

API экспорта может вернуть строку SVG и принять явные границы. Скопируйте разметку, отображенную под результатом, в result.svg, затем откройте этот файл самостоятельно. Наш сохраненный экспорт содержал один элемент path с двумя замкнутыми подконтурами; он также правильно отображался при прямом открытии в браузере.

Для собственной графики проверьте:

  • силуэт и каждое отверстие относительно оригинала;
  • не был ли случайно включен фон или скрытая вспомогательная фигура;
  • нужную заливку, поскольку одна объединенная фигура не может сохранять две независимо редактируемые однотонные заливки;
  • экспортированную область просмотра, особенно если графика достигает края документа;
  • файл в приложении, которое реально будет его использовать.

Белое наложение может выглядеть как отверстие на белой бумаге. Поместите результат на контрастный фон для проверки прозрачности. Руководство по заполненным отверстиям SVG объясняет связанные проблемы составных контуров и fill-rule.

Когда операция дает неверную фигуру

Метод отсутствует. Проверьте класс выбранного объекта. Найдите нужный контур внутри группы или преобразуйте поддерживаемые примитивные фигуры при импорте. Не решайте это объединением всех потомков: составные контуры тоже содержат дочерние элементы, и связи их отверстий важны.

Результат выглядит неизменным. Убедитесь, что отображаете возвращенный объект. Оставленные видимыми оригиналы могут закрыть успешное вычитание. В примере только окончательный результат входит в активный слой.

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

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

Когда исходник все еще PNG или JPG

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

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

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

Можно ли вызвать unite для импортированной группы SVG? Сначала выберите нужные операнды Path или CompoundPath внутри группы. Группа описывает организацию, а объединение всех дочерних элементов может включить фоны или уничтожить нужные разделения.

Удаляет ли subtract исходные контуры? Он возвращает новый объект контура. Этот пример использует insert: false для импорта и результатов булевых операций, затем вставляет только окончательный результат. Исходные операнды остаются доступными в импортированном контейнере.

Почему отверстие все еще выглядит белым? Проверьте его на цветном фоне. Белый объект с заливкой закрывает то, что находится за ним; вычтенное отверстие показывает этот фон. Откройте экспортированный файл заново, чтобы подтвердить сохранение этого отношения.

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

Источники

  1. Paper.js — Project reference — Описывает импорт и экспорт SVG, границы и содержимое проекта.
  2. Paper.js — Path reference — Определяет объединение и вычитание, возвращаемые объекты контуров и параметры булевых операций.
  3. Paper.js — CompoundPath reference — Описывает составную геометрию и входящие в нее контуры.

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

Ещё из блога

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