Skip to content

Commit

Permalink
Extend SKSvg and Svg controls
Browse files Browse the repository at this point in the history
  • Loading branch information
wieslawsoltes committed Nov 23, 2023
1 parent 5c1a924 commit 4e7f5b8
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 32 deletions.
54 changes: 48 additions & 6 deletions src/Avalonia.Svg.Skia/Svg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ public class Svg : Control
public static readonly StyledProperty<string?> PathProperty =
AvaloniaProperty.Register<Svg, string?>(nameof(Path));

/// <summary>
/// Defines the <see cref="Source"/> property.
/// </summary>
public static readonly StyledProperty<string?> SourceProperty =
AvaloniaProperty.Register<Svg, string?>(nameof(Source));

/// <summary>
/// Defines the <see cref="Stretch"/> property.
/// </summary>
Expand Down Expand Up @@ -57,6 +63,15 @@ public string? Path
set => SetValue(PathProperty, value);
}

/// <summary>
/// Gets or sets the Svg source.
/// </summary>
public string? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
}

/// <summary>
/// Gets or sets a value controlling how the image will be stretched.
/// </summary>
Expand Down Expand Up @@ -101,8 +116,8 @@ public bool EnableCache

static Svg()
{
AffectsRender<Svg>(PathProperty, StretchProperty, StretchDirectionProperty);
AffectsMeasure<Svg>(PathProperty, StretchProperty, StretchDirectionProperty);
AffectsRender<Svg>(PathProperty, SourceProperty, StretchProperty, StretchDirectionProperty);
AffectsMeasure<Svg>(PathProperty, SourceProperty, StretchProperty, StretchDirectionProperty);
}

/// <summary>
Expand Down Expand Up @@ -135,7 +150,6 @@ protected override Size MeasureOverride(Size availableSize)
: default;

return Stretch.CalculateSize(availableSize, sourceSize, StretchDirection);

}

protected override Size ArrangeOverride(Size finalSize)
Expand Down Expand Up @@ -201,7 +215,14 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
if (change.Property == PathProperty)
{
var path = change.GetNewValue<string?>();
Load(path);
LoadFromPath(path);
InvalidateVisual();
}

if (change.Property == SourceProperty)
{
var source = change.GetNewValue<string?>();
LoadFromSource(source);
InvalidateVisual();
}

Expand All @@ -219,7 +240,7 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
}
}

private void Load(string? path)
private void LoadFromPath(string? path, Dictionary<string, string>? entities = null)
{
if (path is null)
{
Expand All @@ -243,7 +264,7 @@ private void Load(string? path)

try
{
_svg = SvgSource.Load<SvgSource>(path, _baseUri);
_svg = SvgSource.Load<SvgSource>(path, _baseUri, entities);

if (_enableCache && _cache is { } && _svg is { })
{
Expand All @@ -257,6 +278,27 @@ private void Load(string? path)
}
}

private void LoadFromSource(string? source)
{
if (source is null)
{
_svg?.Dispose();
_svg = null;
DisposeCache();
return;
}

try
{
_svg = SvgSource.LoadFromSvg<SvgSource>(source);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Warning, LogArea.Control)?.Log(this, "Failed to load svg image: " + e);
_svg = null;
}
}

private void DisposeCache()
{
if (_cache is null)
Expand Down
4 changes: 1 addition & 3 deletions src/Avalonia.Svg.Skia/SvgImage.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Media;
using Avalonia.Metadata;

namespace Avalonia.Svg.Skia;
Expand Down
50 changes: 45 additions & 5 deletions src/Avalonia.Svg.Skia/SvgSource.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using Svg;
using Svg.Skia;

namespace Avalonia.Svg.Skia;
Expand All @@ -18,13 +20,14 @@ public class SvgSource : SKSvg
/// </summary>
/// <param name="path">The path to file or resource.</param>
/// <param name="baseUri">The base uri.</param>
/// <param name="entities">The svg entities.</param>
/// <returns>The svg source.</returns>
public static T? Load<T>(string path, Uri? baseUri) where T : SKSvg, new()
public static T? Load<T>(string path, Uri? baseUri, Dictionary<string, string>? entities = null) where T : SKSvg, new()
{
if (File.Exists(path))
{
var source = new T();
source.Load(path);
source.Load(path, entities);
return source;
}

Expand All @@ -37,7 +40,7 @@ public class SvgSource : SKSvg
{
var stream = response.Content.ReadAsStreamAsync().Result;
var source = new T();
source.Load(stream);
source.Load(stream, entities);
return source;
}
}
Expand All @@ -54,7 +57,7 @@ public class SvgSource : SKSvg
if (uri.IsAbsoluteUri && uri.IsFile)
{
var source = new T();
source.Load(uri.LocalPath);
source.Load(uri.LocalPath, entities);
return source;
}
else
Expand All @@ -65,8 +68,45 @@ public class SvgSource : SKSvg
return default;
}
var source = new T();
source.Load(stream);
source.Load(stream, entities);
return source;
}
}

/// <summary>t
/// Loads svg source from svg source.
/// </summary>
/// <param name="source">The svg source.</param>
/// <returns>The svg source.</returns>
public static T? LoadFromSvg<T>(string source) where T : SKSvg, new()
{
var skSvg = new T();
skSvg.FromSvg(source);
return skSvg;
}

/// <summary>t
/// Loads svg source from file or resource.
/// </summary>
/// <param name="stream">The svg stream.</param>
/// <param name="entities">The svg entities.</param>
/// <returns>The svg source.</returns>
public static T? LoadFromStream<T>(Stream stream, Dictionary<string, string>? entities = null) where T : SKSvg, new()
{
var skSvg = new T();
skSvg.Load(stream, entities);
return skSvg;
}

/// <summary>t
/// Loads svg source from svg document.
/// </summary>
/// <param name="document">The svg document.</param>
/// <returns>The svg source.</returns>
public static T? LoadFromSvgDocument<T>(SvgDocument document) where T : SKSvg, new()
{
var skSvg = new T();
skSvg.FromSvgDocument(document);
return skSvg;
}
}
26 changes: 16 additions & 10 deletions src/Svg.Model/SvgExtensions.IO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO.Compression;
using System.Net;
using System.Text;
using System.Xml;
using Svg.Model.Drawables;
#if USE_SKIASHARP
using SkiaSharp;
Expand Down Expand Up @@ -296,12 +297,12 @@ internal static SvgDocument LoadSvgz(System.IO.Stream stream, Uri baseUri)
return picture;
}
#endif
public static SvgDocument? OpenSvg(string path)
public static SvgDocument? OpenSvg(string path, Dictionary<string, string>? entities = null)
{
return SvgDocument.Open<SvgDocument>(path, null);
return SvgDocument.Open<SvgDocument>(path, entities);
}

public static SvgDocument? OpenSvgz(string path)
public static SvgDocument? OpenSvgz(string path, Dictionary<string, string>? entities = null)
{
using var fileStream = System.IO.File.OpenRead(path);
using var gzipStream = new GZipStream(fileStream, CompressionMode.Decompress);
Expand All @@ -310,27 +311,32 @@ internal static SvgDocument LoadSvgz(System.IO.Stream stream, Uri baseUri)
gzipStream.CopyTo(memoryStream);
memoryStream.Position = 0;

return Open(memoryStream);
return Open(memoryStream, entities);
}

public static SvgDocument? Open(string path)
public static SvgDocument? Open(string path, Dictionary<string, string>? entities = null)
{
var extension = System.IO.Path.GetExtension(path);
return extension.ToLower() switch
{
".svg" => OpenSvg(path),
".svgz" => OpenSvgz(path),
_ => OpenSvg(path),
".svg" => OpenSvg(path, entities),
".svgz" => OpenSvgz(path, entities),
_ => OpenSvg(path, entities),
};
}

public static SvgDocument? Open(System.IO.Stream stream)
public static SvgDocument? Open(System.IO.Stream stream, Dictionary<string, string>? entities = null)
{
return SvgDocument.Open<SvgDocument>(stream, null);
return SvgDocument.Open<SvgDocument>(stream, entities);
}

public static SvgDocument? FromSvg(string svg)
{
return SvgDocument.FromSvg<SvgDocument>(svg);
}

public static SvgDocument? Open(XmlReader reader)
{
return SvgDocument.Open<SvgDocument>(reader);
}
}
58 changes: 54 additions & 4 deletions src/Svg.Skia/SKSvg.Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,49 @@
using System;
using Svg.Model;
using System.Collections.Generic;
using System.Xml;
using Svg.Model.Drawables;
using ShimSkiaSharp;

namespace Svg.Skia;

public class SKSvg : IDisposable
{
public static SKSvg CreateFromStream(System.IO.Stream stream, Dictionary<string, string>? entities = null)
{
var skSvg = new SKSvg();
skSvg.Load(stream, entities);
return skSvg;
}

public static SKSvg CreateFromFile(string path, Dictionary<string, string>? entities = null)
{
var skSvg = new SKSvg();
skSvg.Load(path, entities);
return skSvg;
}

public static SKSvg CreateFromXmlReader(XmlReader reader)
{
var skSvg = new SKSvg();
skSvg.Load(reader);
return skSvg;
}

public static SKSvg CreateFromSvg(string svg)
{
var skSvg = new SKSvg();
skSvg.FromSvg(svg);
return skSvg;
}

public static SKSvg CreateFromSvgDocument(SvgDocument svgDocument)
{
var skSvg = new SKSvg();
skSvg.FromSvgDocument(svgDocument);
return skSvg;
}

public static SkiaSharp.SKPicture? ToPicture(SvgFragment svgFragment, SkiaModel skiaModel, IAssetLoader assetLoader)
{
var picture = SvgExtensions.ToModel(svgFragment, assetLoader, out _, out _);
Expand Down Expand Up @@ -57,10 +93,10 @@ public SKSvg()
AssetLoader = new SkiaAssetLoader(SkiaModel);
}

public SkiaSharp.SKPicture? Load(System.IO.Stream stream)
public SkiaSharp.SKPicture? Load(System.IO.Stream stream, Dictionary<string, string>? entities = null)
{
Reset();
var svgDocument = SvgExtensions.Open(stream);
var svgDocument = SvgExtensions.Open(stream, entities);
if (svgDocument is { })
{
Model = SvgExtensions.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Expand All @@ -71,10 +107,24 @@ public SKSvg()
return null;
}

public SkiaSharp.SKPicture? Load(string path)
public SkiaSharp.SKPicture? Load(string path, Dictionary<string, string>? entities = null)
{
Reset();
var svgDocument = SvgExtensions.Open(path);
var svgDocument = SvgExtensions.Open(path, entities);
if (svgDocument is { })
{
Model = SvgExtensions.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
return Picture;
}
return null;
}

public SkiaSharp.SKPicture? Load(XmlReader reader)
{
Reset();
var svgDocument = SvgExtensions.Open(reader);
if (svgDocument is { })
{
Model = SvgExtensions.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Expand Down
Loading

0 comments on commit 4e7f5b8

Please sign in to comment.