Редактирование SVG через CSS-селекторы в C#

CSS-селекторы – практичный способ точно выбрать SVG-элементы перед редактированием. В Aspose.SVG for .NET C#-код может использовать QuerySelector() и QuerySelectorAll(), чтобы находить элементы по имени тега, иерархии, атрибутам или позиции в SVG-дереве, а затем изменять атрибуты, заменять узлы или обновлять данные пути.

В статье используется пример owl.svg. Примеры выбирают круги и пути в SVG DOM и создают отредактированные версии исходного векторного изображения.

Рабочий процесс редактирования через CSS-селекторы

Обычно редактирование через селекторы состоит из четырех шагов:

  1. Загрузить исходный SVG-файл в SVGDocument.
  2. Использовать QuerySelector() для одного элемента или QuerySelectorAll() для списка элементов.
  3. Изменить атрибуты, стили, текст, геометрию или данные пути выбранных элементов.
  4. Сохранить отредактированный SVG-документ.

Краткое введение в DOM-навигацию, XPath и фильтры узлов смотрите в статье Инспекция и навигация SVG в C#.

Выбор и редактирование SVG-элементов

Первый пример редактирует исходный файл owl.svg. Иллюстрация совы построена из элементов path и circle. Код использует CSS-селекторы, чтобы:

1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Dom;
4using Aspose.Svg.Collections;
 1// Edit SVG elements with CSS selectors in C#
 2
 3// Load an SVG document
 4using (SVGDocument document = new SVGDocument(new Url("https://docs.aspose.com/svg/files/owl.svg")))
 5{
 6    // Get the root <svg> element of the document
 7    SVGSVGElement svgElement = document.RootElement;
 8
 9    // Find the first element that matches the specified in selector
10    SVGGElement gElement = svgElement.QuerySelector("g") as SVGGElement;
11
12    // Find all <circle> elements in a <g> element
13    NodeList circleNodes = gElement.QuerySelectorAll("circle");
14
15    // Make big blue eyes
16    foreach (Node circleNode in circleNodes)
17    {
18        SVGCircleElement circleElement = circleNode as SVGCircleElement;
19        circleElement.R.BaseVal.Value *= 1.5F;
20        circleElement.SetAttribute("stroke", "blue");
21    }
22
23    // Get a path for the owl's wing
24    SVGPathElement wingPath = gElement.QuerySelector("path:nth-child(2)") as SVGPathElement;
25
26    // Apply style attributes to the wing
27    wingPath.SetAttribute("stroke-width", "16");
28    wingPath.SetAttribute("stroke-dasharray", "2 8");
29
30    document.Save(Path.Combine(OutputDir, "owl-edited1.svg"));
31}

Отредактированный SVG-файл можно открыть здесь: owl-edited1.svg.

Замена выбранных SVG-элементов

Второй пример продолжает работу с тем же исходным файлом owl.svg. Он выбирает исходные круглые глаза и заменяет их квадратными:

  1. Создать новый элемент <g> для прямоугольников, которые заменят глаза.
  2. Использовать QuerySelectorAll("g:first-child > circle"), чтобы выбрать круги в первой группе.
  3. Создать элементы <rect> с нужными атрибутами размера и стиля.
  4. Вставить прямоугольники в новую группу.
  5. Удалить выбранные элементы <circle> из документа.
1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Dom;
4using Aspose.Svg.Collections;
 1// Replace SVG circles with rectangles using CSS selectors in C#
 2
 3// Load an SVG document
 4using (SVGDocument document = new SVGDocument(new Url("https://docs.aspose.com/svg/files/owl.svg")))
 5{
 6    // Get the root <svg> element of the document
 7    SVGSVGElement svgElement = document.RootElement;
 8
 9    // Create a new <g> element with style attributes and append it as the last child of the <svg> element
10    SVGGElement gElement = (SVGGElement)document.CreateElementNS(SvgNamespace, "g");
11    gElement.SetAttribute("fill", "none");
12    gElement.SetAttribute("stroke-width", "2");
13    svgElement.AppendChild(gElement);
14
15    // Find all <circle> elements from the first <g> element
16    NodeList circleNodes = svgElement.QuerySelectorAll("g:first-child > circle");
17
18    // Make square sky-blue eyes
19    foreach (Node circleNode in circleNodes)
20    {
21        SVGCircleElement circleElement = circleNode as SVGCircleElement;
22
23        float cx = circleElement.Cx.BaseVal.Value;
24        float cy = circleElement.Cy.BaseVal.Value;
25        float r = circleElement.R.BaseVal.Value;
26
27        SVGRectElement rectElement = (SVGRectElement)document.CreateElementNS(SvgNamespace, "rect");
28        rectElement.X.BaseVal.Value = cx - r;
29        rectElement.Y.BaseVal.Value = cy - r;
30        rectElement.Width.BaseVal.Value = 3 * r;
31        rectElement.Height.BaseVal.Value = 3 * r;
32        rectElement.SetAttribute("stroke", "SkyBlue");
33
34        // Add a <rectangle> element into the second (new) <g> element and remove <circle> elements
35        gElement.AppendChild(rectElement);
36        circleElement.Remove();
37    }
38    // Recolor last rectangle in the second (new) <g> element
39    Element lastRect = gElement.LastElementChild;
40    lastRect.SetAttribute("stroke", "red");
41
42    document.Save(Path.Combine(OutputDir, "owl-svg-eyes.svg"));
43}

Выбор пути и изменение его данных

Финальная часть меняет крыло совы: вместо кривой используется ломаная линия, а цвет обновляется. Пример выбирает элемент path, изменяет данные пути и сохраняет результат:

1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Dom;
4using Aspose.Svg.Collections;
 1// Modify SVG path data selected with CSS selectors in C#
 2
 3// Load an SVG document
 4using (SVGDocument document = new SVGDocument(Path.Combine(DataDir, "owl-svg-eyes.svg")))
 5{
 6    SVGSVGElement svgElement = document.RootElement;
 7
 8    // Get a path for owl's body from the first <g> element
 9    Element bodyPath = (svgElement.QuerySelector("g:first-child") as SVGGElement).FirstElementChild;
10    bodyPath.SetAttribute("stroke", "Teal");
11
12    // Get a path for the owl's wing from the first <g> element
13    SVGPathElement wingPath = svgElement.QuerySelector("g:first-child > path:nth-child(2)") as SVGPathElement;
14
15    // Form new wing path data based on the old
16    string d = "";
17    foreach (SVGPathSeg pathSeg in wingPath.PathSegList)
18    {
19        if (pathSeg is SVGPathSegMovetoAbs)
20        {
21            SVGPathSegMovetoAbs pathSegMovetoAbs = pathSeg as SVGPathSegMovetoAbs;
22
23            d += string.Format(" M {0} {1}", pathSegMovetoAbs.X, pathSegMovetoAbs.Y);
24        }
25        if (pathSeg is SVGPathSegCurvetoCubicAbs)
26        {
27            SVGPathSegCurvetoCubicAbs pathSegCurvetoCubicAbs = pathSeg as SVGPathSegCurvetoCubicAbs;
28
29            d += string.Format(
30                " L {0} {1} L {2} {3}",
31                (pathSegCurvetoCubicAbs.X1 + pathSegCurvetoCubicAbs.X2) / 2F,
32                (pathSegCurvetoCubicAbs.Y1 + pathSegCurvetoCubicAbs.Y2) / 2F,
33                pathSegCurvetoCubicAbs.X,
34                pathSegCurvetoCubicAbs.Y
35            );
36        }
37    }
38    // Set d attribute - new path data formation
39    wingPath.SetAttribute("d", d.Trim());
40    wingPath.SetAttribute("stroke", "Teal");
41
42    document.Save(Path.Combine(OutputDir, "owl-edited2.svg"));
43}

На изображении сравниваются исходная сова и две отредактированные версии.

Исходная SVG-иллюстрация совы и две версии после редактирования селекторами

Второй отредактированный SVG-файл можно открыть здесь: owl-edited2.svg.

FAQ

1. Когда использовать QuerySelector(), а когда QuerySelectorAll()?
Используйте QuerySelector(), когда нужен только первый подходящий элемент. Используйте QuerySelectorAll(), когда нужно проверить или изменить все подходящие элементы, например все круги внутри группы.

2. Могут ли CSS-селекторы сами изменять SVG-элементы?
Нет. Селекторы только находят элементы. После выбора элемента используйте DOM-методы и свойства, например SetAttribute(), AppendChild(), RemoveChild() или типизированные SVG-свойства, чтобы внести изменения.

3. Можно ли конвертировать SVG после редактирования через селекторы?
Да. После редактирования SVGDocument вызовите Converter.ConvertSVG(document, options, outputPath) с подходящими параметрами сохранения или сначала сохраните SVG-файл, а затем конвертируйте его.

Дальнейшие шаги

Close
Loading

Analyzing your prompt, please hold on...

An error occurred while retrieving the results. Please refresh the page and try again.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.