Редактирование файлов SVG в C#

Aspose.SVG for .NET редактирует SVG как структурированный векторный документ. Загрузите SVG-файл в SVGDocument, найдите или создайте SVG-элементы с помощью DOM API, измените их геометрию, атрибуты, текст, стили или данные пути и сохраните отредактированный файл без растеризации.

Типичный процесс редактирования SVG:

  1. Загрузите существующий SVG-файл или создайте новый SVGDocument.
  2. Найдите элемент с помощью CSS-селектора или создайте новый элемент методом CreateElementNS().
  3. Измените свойства или атрибуты элемента и вставьте новое содержимое в дерево SVG.
  4. Сохраните отредактированный SVG-документ методом Save().

Быстрый старт: добавление фигуры в SVG-файл

В следующем примере загружается SVG-файл, в его корневой элемент <svg> добавляется синий круг, а измененный документ сохраняется:

 1using System.IO;
 2using Aspose.Svg;
 3
 4string inputPath = Path.Combine(DataDir, "shapes.svg");
 5string outputPath = Path.Combine(OutputDir, "shapes-with-circle.svg");
 6const string SvgNamespace = "http://www.w3.org/2000/svg";
 7
 8using (SVGDocument document = new SVGDocument(inputPath))
 9{
10    // Access the root <svg> element, which is present in an SVG document.
11    SVGSVGElement svgElement = document.RootElement;
12
13    // Create a circle and define its geometry and appearance.
14    SVGCircleElement circle = (SVGCircleElement)document.CreateElementNS(SvgNamespace, "circle");
15    circle.Cx.BaseVal.Value = 50;
16    circle.Cy.BaseVal.Value = 50;
17    circle.R.BaseVal.Value = 40;
18    circle.SetAttribute("fill", "#3A86FF");
19
20    // Add the circle to the document tree and save the edited SVG file.
21    svgElement.AppendChild(circle);
22    document.Save(outputPath);
23}

Если местоположение элемента для редактирования еще не известно, в статье Навигация и проверка SVG показаны примеры CSS-селекторов и XPath. Способы загрузки документа рассмотрены в статье Создание и загрузка документов SVG.

Добавление элементов и установка атрибутов

Свойство RootElement возвращает корневой элемент <svg>. Новые SVG-элементы необходимо создавать в пространстве имен SVG; затем их можно добавить в контейнер или вставить в выбранное место дерева документа.

Этот фрагмент создает элемент <g> и вставляет его первым дочерним элементом корневого узла:

 1const string SvgNamespace = "http://www.w3.org/2000/svg";
 2
 3SVGSVGElement svgElement = document.RootElement;
 4SVGGElement groupElement = (SVGGElement)document.CreateElementNS(SvgNamespace, "g");
 5
 6// Apply common styles to every graphic element later added to the group.
 7groupElement.SetAttribute("fill", "#8A8D8F");
 8groupElement.SetAttribute("stroke", "magenta");
 9groupElement.SetAttribute("stroke-width", "4");
10
11svgElement.InsertBefore(groupElement, svgElement.FirstChild);

Используйте SetAttribute(), чтобы задавать или обновлять такие SVG-атрибуты созданных или существующих элементов, как fill, stroke, transform, class или d.

Значениями атрибутов можно управлять с помощью методов SetAttribute(name, value), GetAttribute(name), HasAttribute(name) и RemoveAttribute(name) класса Element.

Добавление и изменение фигур SVG

Aspose.SVG for .NET предоставляет типизированные DOM-классы для стандартных фигур SVG, включая SVGCircleElement, SVGEllipseElement, SVGRectElement, SVGLineElement, SVGPolylineElement, SVGPolygonElement и SVGPathElement. Их типизированные свойства позволяют изменять геометрию напрямую: например, Cx.BaseVal.Value, Cy.BaseVal.Value и R.BaseVal.Value задают круг, а содержимое остается редактируемой векторной графикой.

Добавление круга

Круг управляется типизированными свойствами Cx, Cy и R. В следующем полном примере круг добавляется в существующий документ SVG:

1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Dom;
 1// Add a circle element to an existing SVG document in C#
 2
 3// Set the SVG namespace URI
 4string SvgNamespace = "http://www.w3.org/2000/svg";
 5
 6// Load an SVG document from a file
 7using (SVGDocument document = new SVGDocument(Path.Combine(DataDir, "basic-shapes.svg")))
 8{
 9    // Get the root <svg> element of the document
10    SVGSVGElement svgElement = document.RootElement;
11
12    // Create a <circle> element
13    SVGCircleElement circleElement = (SVGCircleElement)document.CreateElementNS(SvgNamespace, "circle");
14    circleElement.Cx.BaseVal.Value = 100F;
15    circleElement.Cy.BaseVal.Value = 100F;
16    circleElement.R.BaseVal.Value = 50F;
17    circleElement.SetAttribute("fill", "Salmon");
18
19    // Add the <circle> element as the first child to <svg> element
20    svgElement.InsertBefore(circleElement, svgElement.FirstChild);
21
22    // Work with the document here...
23    // Add a polyline and change stroke attributes for all circle and ellipse elements (see later)
24
25    // Save the document
26    document.Save(Path.Combine(OutputDir, "basic-shapes_add-circle.svg"));
27}

Эллипс (Cx, Cy, Rx, Ry), прямоугольник (X, Y, Width, Height, Rx, Ry) и линия (X1, Y1, X2, Y2) имеют собственные атрибуты, которые можно задавать аналогичным образом.

Добавление полилинии и изменение существующих фигур

SVG-элемент <polyline> хранит координаты вершин в атрибуте points. В Aspose.SVG список SVGPolylineElement.Points предоставляет типизированный доступ к этим координатам. С помощью CreateSVGPoint() можно добавлять точки, не составляя строку атрибута вручную:

 1const string SvgNamespace = "http://www.w3.org/2000/svg";
 2
 3SVGSVGElement svgElement = document.RootElement;
 4SVGPolylineElement polylineElement = (SVGPolylineElement)document.CreateElementNS(SvgNamespace, "polyline");
 5
 6SVGPoint point1 = svgElement.CreateSVGPoint();
 7point1.X = 270;
 8point1.Y = 240;
 9SVGPoint point2 = svgElement.CreateSVGPoint();
10point2.X = 290;
11point2.Y = 220;
12SVGPoint point3 = svgElement.CreateSVGPoint();
13point3.X = 310;
14point3.Y = 240;
15
16polylineElement.Points.AppendItem(point1);
17polylineElement.Points.AppendItem(point2);
18polylineElement.Points.AppendItem(point3);
19polylineElement.SetAttribute("stroke", "grey");
20polylineElement.SetAttribute("stroke-width", "5");
21polylineElement.SetAttribute("fill", "none");
22
23// Add the new polyline to the SVG root element
24svgElement.AppendChild(polylineElement);
25
26// Update strokes of circle and ellipse elements already in the SVG document
27foreach (Element element in svgElement.Children)
28{
29    if (element is SVGCircleElement || element is SVGEllipseElement)
30    {
31        element.SetAttribute("stroke-width", "6");
32        element.SetAttribute("stroke", "#C8102E");
33    }
34}

На изображении ниже показаны исходный файл basic-shapes.svg и результат после добавления фигур и изменения атрибутов обводки.

Исходные и отредактированные фигуры SVG

Редактирование данных пути SVG

Геометрия элемента <path> хранится в его атрибуте d. Создайте типизированный SVGPathElement, обновите данные пути и добавьте его в документ SVG, как любой другой элемент:

 1const string SvgNamespace = "http://www.w3.org/2000/svg";
 2
 3SVGPathElement pathElement =
 4    (SVGPathElement)document.CreateElementNS(SvgNamespace, "path");
 5
 6// Set the path geometry and its visible style.
 7pathElement.SetAttribute("d", "M 10 200 Q 25 210 180 200 T 300 250 T 420 250 T 490 150");
 8pathElement.SetAttribute("stroke", "magenta");
 9pathElement.SetAttribute("fill", "none");
10pathElement.SetAttribute("stroke-width", "4");
11
12document.RootElement.InsertBefore(pathElement, document.RootElement.FirstChild);

Если код создает или изменяет команды пути посегментно, SVGPathElement также предоставляет операции с сегментами пути. В следующем примере создается путь и изменяются координаты выбранных команд в существующем SVG-файле:

1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Paths;
 1// Edit SVG path data programmatically in C#
 2
 3// Set the SVG namespace URI
 4string SvgNamespace = "http://www.w3.org/2000/svg";
 5
 6using (SVGDocument document = new SVGDocument())
 7{
 8    SVGSVGElement svgElement = document.RootElement;
 9
10    // Create a <path> element
11    SVGPathElement pathElement = (SVGPathElement)document.CreateElementNS(SvgNamespace, "path");
12
13    // Set d attribute parameters – SVG path data
14    pathElement.SetAttribute("d", "M 10 200 Q 25 110 180 200 T 300 250 T 420 250 T 490 150");
15
16    // Edit SVG path
17    foreach (SVGPathSeg pathSeg in pathElement.PathSegList)
18    {
19        // Editing T commands parameters
20        if (pathSeg is SVGPathSegCurvetoQuadraticSmoothAbs)
21        {
22            SVGPathSegCurvetoQuadraticSmoothAbs pathSegCurvetoQuadraticSmoothAbs = pathSeg as SVGPathSegCurvetoQuadraticSmoothAbs;
23
24            pathSegCurvetoQuadraticSmoothAbs.X -= 60;
25            pathSegCurvetoQuadraticSmoothAbs.Y -= 65;
26        }
27
28        // Editing M command parameters
29        if (pathSeg is SVGPathSegMovetoAbs)
30        {
31            SVGPathSegMovetoAbs pathSegMovetoAbs = pathSeg as SVGPathSegMovetoAbs;
32
33            pathSegMovetoAbs.X = 200;
34            pathSegMovetoAbs.Y = 100;
35        }
36    }
37    // Set fill and stroke attributes
38    pathElement.SetAttribute("stroke", "red");
39    pathElement.SetAttribute("fill", "none");
40    pathElement.SetAttribute("stroke-width", "4");
41
42    // Add the <path> element as the first child to the <svg> element
43    svgElement.InsertBefore(pathElement, svgElement.FirstChild);
44
45    // Save the document
46    document.Save(Path.Combine(OutputDir, "edit-svg-path-data.svg"));
47}

На рисунке сравниваются исходный черный и отредактированный красный пути. Можно также открыть измененный файл примера: edit-svg-path-data.svg.

Исходный и отредактированный путь SVG

Синтаксис команд пути и особенности рисования описаны в статье Данные пути SVG.

Добавление SVG-содержимого поверх растрового изображения

SVG-документ может ссылаться на растровое изображение с помощью элемента <image> и размещать поверх него редактируемый векторный текст или фигуры. При этом пиксели растрового изображения не изменяются: фоновое изображение и SVG-наложение остаются отдельными частями векторного документа.

Этот подход удобен, если на фотографию, скан или другую растровую графику требуется добавить подписи, маркеры, значки или декоративные элементы, которые должны оставаться редактируемыми в SVG. В SVG порядок рисования соответствует порядку элементов: если сначала добавить <image>, а затем текст или фигуры, векторные элементы будут отображаться поверх растрового фона.

1<svg xmlns="http://www.w3.org/2000/svg">
2    <image href="/svg/images/api/seaside.jpg" height="480" width="640" x="20" y="20"/>
3    <text style="font-size: 1.4em;" x="420" y="280" fill="gold">The beach is beautiful...</text>
4    <circle cx="520" cy="120" r="60" stroke="gold" stroke-width="70" fill="none" stroke-dasharray="2,14"/>
5</svg>

Чтобы создать такую композицию с помощью Aspose.SVG for .NET:

  1. Создайте SVGDocument и получите доступ к корневому элементу <svg> через RootElement.
  2. Создайте SVGImageElement методом CreateElementNS(), укажите ссылку на изображение, его положение и размер, затем добавьте элемент в корень в качестве фона.
  3. Создайте SVGTextElement, задайте текст, положение, стиль шрифта и цвет заливки, затем добавьте его после изображения.
  4. Создайте SVGCircleElement, задайте положение, радиус и атрибуты обводки, затем добавьте его после фонового изображения. В этом примере широкая пунктирная обводка создает декоративный эффект солнца.
  5. Вызовите Save() для записи SVG-документа. В сохраненном файле ссылка на bitmap, текст и круг сохраняются как редактируемые элементы SVG.

Следующий пример выполняет эти шаги и сохраняет результат в SVG:

1using Aspose.Svg;
2using System.IO;
3using Aspose.Svg.Paths;
 1// Draw SVG shapes and text on an existing bitmap in C#
 2
 3// Set the SVG namespace URI
 4string SvgNamespace = "http://www.w3.org/2000/svg";
 5
 6using (SVGDocument document = new SVGDocument())
 7{
 8    SVGSVGElement svgElement = document.RootElement;
 9
10    // Create an <image> element and add it into svgElement
11    SVGImageElement imageElement = (SVGImageElement)document.CreateElementNS(SvgNamespace, "image");
12    imageElement.Href.BaseVal = "http://docs.aspose.com/svg/images/api/seaside.jpg";
13    imageElement.Height.BaseVal.ConvertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX);
14    imageElement.Width.BaseVal.ConvertToSpecifiedUnits(SVGLength.SVG_LENGTHTYPE_PX);
15    imageElement.Height.BaseVal.Value = 480;
16    imageElement.Width.BaseVal.Value = 640;
17    imageElement.X.BaseVal.Value = 20;
18    imageElement.Y.BaseVal.Value = 20;
19    svgElement.AppendChild(imageElement);
20
21    // Create a <text> element, set its attributes, and add it to the <svg> element
22    SVGTextElement textElement = (SVGTextElement)document.CreateElementNS(SvgNamespace, "text");
23    textElement.Style.FontSize = "1.4em";
24    textElement.SetAttribute("x", "420px");
25    textElement.SetAttribute("fill", "gold");
26    textElement.SetAttribute("y", "280px");
27    textElement.TextContent = "The beach is beautiful...";
28    svgElement.AppendChild(textElement);
29
30    // Create a <circle> element, set its attributes, and add it to the <svg> element
31    SVGCircleElement circleElement = (SVGCircleElement)document.CreateElementNS(SvgNamespace, "circle");
32    circleElement.Cx.BaseVal.Value = 520;
33    circleElement.Cy.BaseVal.Value = 120;
34    circleElement.R.BaseVal.Value = 60;
35    circleElement.SetAttribute("stroke", "gold");
36    circleElement.SetAttribute("stroke-width", "70");
37    circleElement.SetAttribute("fill", "none");
38    circleElement.SetAttribute("stroke-dasharray", "2,14");
39    svgElement.AppendChild(circleElement);
40
41    // Save the document
42    document.Save(Path.Combine(OutputDir, "svg-drawing-on-bitmap.svg"));
43}

Подробнее о ширине обводки, шаблонах штрихов и других атрибутах оформления SVG см. в статье Заливка и обводка в SVG.

Растровый фон с редактируемым текстом SVG и наложенным кругом

FAQ

1. Преобразует ли Aspose.SVG файл в bitmap при редактировании SVG?

Нет. При редактировании через SVGDocument изменяются SVG-элементы, атрибуты и данные пути, но документ остается векторным. Растровый результат создается только при явной конвертации или рендеринге SVG в формат изображения, например PNG, JPEG или WebP.

2. Как изменить существующий SVG-элемент, а не добавлять новый?

Найдите нужный элемент с помощью CSS-селектора или XPath-запроса, затем измените его атрибуты или типизированные свойства SVG. Например, выбрав <circle>, код может изменить его радиус, положение, заливку или обводку. См. статьи Навигация и проверка SVG и Как изменить цвет SVG.

3. Можно ли изменить SVG-документ и сразу конвертировать измененный результат?

Да. Загрузите исходный файл в SVGDocument, внесите изменения, создайте параметры сохранения для целевого формата и вызовите Converter.ConvertSVG(document, options, outputPath). Например, используйте PdfSaveOptions для PDF или ImageSaveOptions для PNG, JPEG, TIFF, GIF, BMP или WebP. Полные примеры приведены в статье Конвертация SVG-файлов в C#.

4. Можно ли заменить существующую фигуру SVG другим элементом?

Да. Найдите существующий элемент с помощью селектора или XPath-запроса, создайте замену методом CreateElementNS(), вставьте новый элемент в тот же родительский узел и удалите старый. Например, можно заменить круглые маркеры прямоугольниками, не изменяя остальную часть SVG-документа. Пример приведен в статье Навигация и проверка SVG.

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