浏览代码

Added text and fixes, so cartman.svg parses correctly

Krzysztof Krysiński 5 月之前
父节点
当前提交
4f53125c49

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/Data/ShapeVectorData.cs

@@ -11,7 +11,7 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes.Data;
 
 public abstract class ShapeVectorData : ICacheable, ICloneable, IReadOnlyShapeVectorData
 {
-    private float strokeWidth = 1;
+    private float strokeWidth = 0;
 
     public Matrix3X3 TransformationMatrix { get; set; } = Matrix3X3.Identity;
 

+ 41 - 0
src/PixiEditor.SVG/Elements/SvgText.cs

@@ -0,0 +1,41 @@
+using System.Xml;
+using PixiEditor.SVG.Units;
+
+namespace PixiEditor.SVG.Elements;
+
+public class SvgText() : SvgPrimitive("text")
+{
+    public SvgProperty<SvgStringUnit> Text { get; } = new("");
+    public SvgProperty<SvgNumericUnit> X { get; } = new("x");
+    public SvgProperty<SvgNumericUnit> Y { get; } = new("y");
+
+    public override void ParseData(XmlReader reader)
+    {
+        base.ParseData(reader);
+        Text.Unit = new SvgStringUnit(ParseContent(reader));
+    }
+
+    protected override IEnumerable<SvgProperty> GetProperties()
+    {
+        yield return X;
+        yield return Y;
+    }
+
+    private string ParseContent(XmlReader reader)
+    {
+        string content = string.Empty;
+        while (reader.Read())
+        {
+            if (reader.NodeType == XmlNodeType.Text)
+            {
+                content = reader.Value;
+            }
+            else if (reader is { NodeType: XmlNodeType.EndElement, Name: "text" })
+            {
+                break;
+            }
+        }
+
+        return content;
+    }
+}

+ 1 - 0
src/PixiEditor.SVG/StyleContext.cs

@@ -20,6 +20,7 @@ public struct StyleContext
         StrokeWidth = new("stroke-width");
         Stroke = new("stroke");
         Fill = new("fill");
+        Fill.Unit = new SvgColorUnit?(new SvgColorUnit("black"));
         Transform = new("transform");
         StrokeLineCap = new("stroke-linecap");
         StrokeLineJoin = new("stroke-linejoin");

+ 2 - 1
src/PixiEditor.SVG/SvgParser.cs

@@ -19,7 +19,8 @@ public class SvgParser
         { "g", typeof(SvgGroup) },
         { "mask", typeof(SvgMask) },
         { "image", typeof(SvgImage) },
-        { "svg", typeof(SvgDocument) }
+        { "svg", typeof(SvgDocument) },
+        { "text", typeof(SvgText) }
     };
 
     public string Source { get; set; }

+ 1 - 1
src/PixiEditor.SVG/Units/SvgNumericUnit.cs

@@ -77,7 +77,7 @@ public struct SvgNumericUnit(double value, string postFix) : ISvgUnit
         
         for (int i = readerValue.Length - 1; i >= 0; i--)
         {
-            if (!char.IsDigit(readerValue[i]))
+            if (!char.IsDigit(readerValue[i]) && readerValue[i] != '.')
             {
                 postFixStartIndex = i + 1;
                 break;

+ 58 - 27
src/PixiEditor/Models/IO/CustomDocumentFormats/SvgDocumentBuilder.cs

@@ -1,4 +1,5 @@
 using System.Diagnostics.CodeAnalysis;
+using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Backend.Core.Vector;
 using Drawie.Numerics;
@@ -26,7 +27,13 @@ internal class SvgDocumentBuilder : IDocumentBuilder
 
         StyleContext styleContext = new(document);
 
-        builder.WithSize((int)document.ViewBox.Unit.Value.Value.Width, (int)document.ViewBox.Unit.Value.Value.Height)
+        VecI size = new((int)document.ViewBox.Unit.Value.Value.Width, (int)document.ViewBox.Unit.Value.Value.Height);
+        if (size.ShortestAxis < 1)
+        {
+            size = new VecI(1024, 1024);
+        }
+
+        builder.WithSize(size)
             .WithGraph(graph =>
             {
                 int? lastId = null;
@@ -74,6 +81,11 @@ internal class SvgDocumentBuilder : IDocumentBuilder
             shapeData = AddRect(rect);
             name = VectorRectangleToolViewModel.NewLayerKey;
         }
+        else if (element is SvgText text)
+        {
+            shapeData = AddText(text);
+            name = TextToolViewModel.NewLayerKey;
+        }
 
         AddCommonShapeData(shapeData, styleContext);
 
@@ -95,15 +107,15 @@ internal class SvgDocumentBuilder : IDocumentBuilder
         return lastId;
     }
 
-    private int? AddGroup(SvgGroup group, NodeGraphBuilder graph, StyleContext style, int? lastId, string connectionName = "Background")
+    private int? AddGroup(SvgGroup group, NodeGraphBuilder graph, StyleContext style, int? lastId,
+        string connectionName = "Background")
     {
         int? childId = null;
         var connectTo = "Background";
-        
         foreach (var child in group.Children)
         {
             StyleContext childStyle = style.WithElement(child);
-            
+
             if (child is SvgPrimitive primitive)
             {
                 childId = AddPrimitive(child, childStyle, graph, childId, connectTo);
@@ -117,18 +129,30 @@ internal class SvgDocumentBuilder : IDocumentBuilder
         NodeGraphBuilder.NodeBuilder nBuilder = graph.WithNodeOfType<FolderNode>(out int id)
             .WithName(group.Id.Unit != null ? group.Id.Unit.Value.Value : new LocalizedString("NEW_FOLDER"));
 
+        int connectionsCount = 0;
+        if (lastId != null) connectionsCount++;
+        if (childId != null) connectionsCount++;
+
+        PropertyConnection[] connections = new PropertyConnection[connectionsCount];
         if (lastId != null)
         {
-            nBuilder.WithConnections([
-                new PropertyConnection()
-                {
-                    InputPropertyName = connectionName, OutputPropertyName = "Output", OutputNodeId = lastId.Value
-                },
-                new PropertyConnection()
-                {
-                    InputPropertyName = "Content", OutputPropertyName = "Output", OutputNodeId = childId.Value
-                }
-            ]);
+            connections[0] = new PropertyConnection()
+            {
+                InputPropertyName = connectionName, OutputPropertyName = "Output", OutputNodeId = lastId.Value
+            };
+        }
+
+        if (childId != null)
+        {
+            connections[^1] = new PropertyConnection()
+            {
+                InputPropertyName = "Content", OutputPropertyName = "Output", OutputNodeId = childId.Value
+            };
+        }
+
+        if (connections.Length > 0)
+        {
+            nBuilder.WithConnections(connections);
         }
 
         lastId = id;
@@ -175,17 +199,17 @@ internal class SvgDocumentBuilder : IDocumentBuilder
                 _ => PathFillType.Winding
             };
         }
-        
+
         StrokeCap strokeLineCap = StrokeCap.Round;
         StrokeJoin strokeLineJoin = StrokeJoin.Round;
-        
-        if(element.StrokeLineCap.Unit != null)
+
+        if (element.StrokeLineCap.Unit != null)
         {
-            strokeLineCap = (StrokeCap)element.StrokeLineCap.Unit.Value.Value;
-            strokeLineJoin = (StrokeJoin)element.StrokeLineJoin.Unit.Value.Value;
+            strokeLineCap = (StrokeCap)(element.StrokeLineCap.Unit?.Value ?? SvgStrokeLineCap.Butt);
+            strokeLineJoin = (StrokeJoin)(element.StrokeLineJoin.Unit?.Value ?? SvgStrokeLineJoin.Miter);
         }
 
-        return new PathVectorData(path) { StrokeLineCap = strokeLineCap, StrokeLineJoin = strokeLineJoin };
+        return new PathVectorData(path) { StrokeLineCap = strokeLineCap, StrokeLineJoin = strokeLineJoin, };
     }
 
     private RectangleVectorData AddRect(SvgRectangle element)
@@ -194,6 +218,16 @@ internal class SvgDocumentBuilder : IDocumentBuilder
             element.Width.Unit.Value.Value, element.Height.Unit.Value.Value);
     }
 
+    private TextVectorData AddText(SvgText element)
+    {
+        return new TextVectorData(element.Text.Unit.Value.Value)
+        {
+            Position = new VecD(
+                element.X.Unit?.Value ?? 0,
+                element.Y.Unit?.Value ?? 0)
+        };
+    }
+
     private void AddCommonShapeData(ShapeVectorData? shapeData, StyleContext styleContext)
     {
         if (shapeData == null)
@@ -202,7 +236,7 @@ internal class SvgDocumentBuilder : IDocumentBuilder
         }
 
         bool hasFill = styleContext.Fill.Unit is { Color.A: > 0 };
-        bool hasStroke = styleContext.Stroke.Unit is { Color.A: > 0 };
+        bool hasStroke = styleContext.Stroke.Unit is { Color.A: > 0 } || styleContext.StrokeWidth.Unit is { Value: > 0 };
         bool hasTransform = styleContext.Transform.Unit is { MatrixValue.IsIdentity: false };
 
         shapeData.Fill = hasFill;
@@ -216,12 +250,9 @@ internal class SvgDocumentBuilder : IDocumentBuilder
         {
             var targetColor = styleContext.Stroke.Unit;
             var targetWidth = styleContext.StrokeWidth.Unit;
-            
-            shapeData.StrokeColor = targetColor.Value.Color;
-            if (targetWidth != null)
-            {
-                shapeData.StrokeWidth = (float)targetWidth.Value.Value;
-            }
+
+            shapeData.StrokeColor = targetColor?.Color ?? Colors.Black;
+            shapeData.StrokeWidth = (float)(targetWidth?.Value ?? 1);
         }
 
         if (hasTransform)

+ 2 - 1
src/PixiEditor/ViewModels/Tools/Tools/TextToolViewModel.cs

@@ -13,6 +13,7 @@ namespace PixiEditor.ViewModels.Tools.Tools;
 [Command.Tool(Key = Key.T)]
 internal class TextToolViewModel : ToolViewModel, ITextToolHandler
 {
+    public const string NewLayerKey = "TEXT_LAYER_NAME";
     public override string ToolNameLocalizationKey => "TEXT_TOOL";
     public override Type[]? SupportedLayerTypes => [];
     public override Type LayerTypeToCreateOnEmptyUse => typeof(VectorLayerNode);
@@ -23,7 +24,7 @@ internal class TextToolViewModel : ToolViewModel, ITextToolHandler
     public override bool IsErasable => false;
     public override bool StopsLinkedToolOnUse => false;
 
-    public string? DefaultNewLayerName { get; } = new LocalizedString("TEXT_LAYER_NAME");
+    public string? DefaultNewLayerName { get; } = new LocalizedString(NewLayerKey);
 
     [Settings.Inherited]
     public double FontSize