Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions samples/TestApp/Views/MainView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@
OffContent="Hide Bounds"
Margin="6,0,6,0"
Click="ShowHitBoundsToggle_OnToggled" />
<ToggleSwitch IsChecked="{Binding #Svg.Wireframe}"
OnContent="Wireframe On"
OffContent="Wireframe Off"
Margin="6,0,6,0" />
<Button Content="Export"
Command="{Binding ExportCommand}"
CommandParameter="{Binding #Svg}"
Expand Down
43 changes: 43 additions & 0 deletions src/Svg.Controls.Skia.Avalonia/Svg.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class Svg : Control
private readonly Uri _baseUri;
private SvgSource? _svg;
private bool _enableCache;
private bool _wireframe;
private Dictionary<string, SvgSource>? _cache;

/// <summary>
Expand Down Expand Up @@ -60,6 +61,14 @@ public class Svg : Control
o => o.EnableCache,
(o, v) => o.EnableCache = v);

/// <summary>
/// Defines the <see cref="Wireframe"/> property.
/// </summary>
public static readonly DirectProperty<Svg, bool> WireframeProperty =
AvaloniaProperty.RegisterDirect<Svg, bool>(nameof(Wireframe),
o => o.Wireframe,
(o, v) => o.Wireframe = v);

/// <summary>
/// Defines the Css property.
/// </summary>
Expand Down Expand Up @@ -118,6 +127,15 @@ public bool EnableCache
set { SetAndRaise(EnableCacheProperty, ref _enableCache, value); }
}

/// <summary>
/// Gets or sets a value controlling wireframe rendering mode.
/// </summary>
public bool Wireframe
{
get { return _wireframe; }
set { SetAndRaise(WireframeProperty, ref _wireframe, value); }
}

/// <summary>
/// Gets svg picture.
/// </summary>
Expand Down Expand Up @@ -374,6 +392,16 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang
_cache = new Dictionary<string, SvgSource>();
}
}

if (change.Property == WireframeProperty)
{
if (_svg?.Svg is { } skSvg)
{
skSvg.Wireframe = change.GetNewValue<bool>();
skSvg.ClearWireframePicture();
}
InvalidateVisual();
}
}

private void LoadFromPath(string? path, SvgParameters? parameters = null)
Expand All @@ -389,6 +417,11 @@ private void LoadFromPath(string? path, SvgParameters? parameters = null)
if (_enableCache && _cache is { } && _cache.TryGetValue(path, out var svg))
{
_svg = svg;
if (_svg.Svg is { } skSvg)
{
skSvg.Wireframe = _wireframe;
skSvg.ClearWireframePicture();
}
return;
}

Expand All @@ -401,6 +434,11 @@ private void LoadFromPath(string? path, SvgParameters? parameters = null)
try
{
_svg = SvgSource.Load(path, _baseUri, parameters);
if (_svg?.Svg is { } skSvg2)
{
skSvg2.Wireframe = _wireframe;
skSvg2.ClearWireframePicture();
}

if (_enableCache && _cache is { } && _svg is { })
{
Expand Down Expand Up @@ -429,6 +467,11 @@ private void LoadFromSource(string? source, SvgParameters? parameters = null)
var bytes = Encoding.UTF8.GetBytes(source);
using var ms = new MemoryStream(bytes);
_svg = SvgSource.LoadFromStream(ms, parameters);
if (_svg?.Svg is { } skSvg)
{
skSvg.Wireframe = _wireframe;
skSvg.ClearWireframePicture();
}
}
catch (Exception e)
{
Expand Down
45 changes: 44 additions & 1 deletion src/Svg.Skia/SKSvg.Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,25 @@ public static void Draw(SkiaSharp.SKCanvas skCanvas, string path, SkiaModel skia

public virtual SkiaSharp.SKPicture? Picture { get; protected set; }

public SkiaSharp.SKPicture? WireframePicture { get; protected set; }

private bool _wireframe;
public bool Wireframe
{
get => _wireframe;
set
{
_wireframe = value;
ClearWireframePicture();
}
}

public void ClearWireframePicture()
{
WireframePicture?.Dispose();
WireframePicture = null;
}

public event EventHandler<SKSvgDrawEventArgs>? OnDraw;

protected virtual void RaiseOnDraw(SKSvgDrawEventArgs e)
Expand Down Expand Up @@ -153,6 +172,8 @@ public SKSvg()
Model = SvgService.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
WireframePicture?.Dispose();
WireframePicture = null;

return Picture;
}
Expand All @@ -174,6 +195,8 @@ public SKSvg()
Model = SvgService.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
WireframePicture?.Dispose();
WireframePicture = null;

return Picture;
}
Expand All @@ -188,6 +211,8 @@ public SKSvg()
Model = SvgService.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
WireframePicture?.Dispose();
WireframePicture = null;
return Picture;
}
return null;
Expand Down Expand Up @@ -225,6 +250,8 @@ public SKSvg()
Model = SvgService.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
WireframePicture?.Dispose();
WireframePicture = null;
return Picture;
}
return null;
Expand All @@ -237,6 +264,8 @@ public SKSvg()
Model = SvgService.ToModel(svgDocument, AssetLoader, out var drawable, out _);
Drawable = drawable;
Picture = SkiaModel.ToSKPicture(Model);
WireframePicture?.Dispose();
WireframePicture = null;
return Picture;
}
return null;
Expand Down Expand Up @@ -270,7 +299,18 @@ public void Draw(SkiaSharp.SKCanvas canvas)
}

canvas.Save();
canvas.DrawPicture(picture);
if (Wireframe && Model is { })
{
WireframePicture ??= SkiaModel.ToWireframePicture(Model);
if (WireframePicture is { })
{
canvas.DrawPicture(WireframePicture);
}
}
else
{
canvas.DrawPicture(picture);
}
canvas.Restore();

RaiseOnDraw(new SKSvgDrawEventArgs(canvas));
Expand All @@ -285,6 +325,9 @@ private void Reset()

Picture?.Dispose();
Picture = null;

WireframePicture?.Dispose();
WireframePicture = null;
}
}

Expand Down
102 changes: 89 additions & 13 deletions src/Svg.Skia/SkiaModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@
};
}

public SkiaSharp.SKFilterQuality ToSKFilterQuality(SKFilterQuality filterQuality)

Check warning on line 918 in src/Svg.Skia/SkiaModel.cs

View workflow job for this annotation

GitHub Actions / Build ubuntu-latest

'SKFilterQuality' is obsolete: 'Use SKSamplingOptions instead.'

Check warning on line 918 in src/Svg.Skia/SkiaModel.cs

View workflow job for this annotation

GitHub Actions / Build windows-latest

'SKFilterQuality' is obsolete: 'Use SKSamplingOptions instead.'

Check warning on line 918 in src/Svg.Skia/SkiaModel.cs

View workflow job for this annotation

GitHub Actions / Build macos-latest

'SKFilterQuality' is obsolete: 'Use SKSamplingOptions instead.'
{
return filterQuality switch
{
Expand Down Expand Up @@ -1246,7 +1246,23 @@
return skPictureRecorder.EndRecording();
}

public void Draw(CanvasCommand canvasCommand, SkiaSharp.SKCanvas skCanvas)
public SkiaSharp.SKPicture? ToWireframePicture(SKPicture? picture)
{
if (picture is null)
{
return null;
}

var skRect = ToSKRect(picture.CullRect);
using var skPictureRecorder = new SkiaSharp.SKPictureRecorder();
using var skCanvas = skPictureRecorder.BeginRecording(skRect);

Draw(picture, skCanvas, true);

return skPictureRecorder.EndRecording();
}

public void Draw(CanvasCommand canvasCommand, SkiaSharp.SKCanvas skCanvas, bool wireframe = false)
{
switch (canvasCommand)
{
Expand Down Expand Up @@ -1289,7 +1305,9 @@
{
if (saveLayerCanvasCommand.Paint is { })
{
var paint = ToSKPaint(saveLayerCanvasCommand.Paint);
var paint = wireframe
? ToWireframePaint(saveLayerCanvasCommand.Paint)
: ToSKPaint(saveLayerCanvasCommand.Paint);
skCanvas.SaveLayer(paint);
}
else
Expand All @@ -1302,11 +1320,20 @@
{
if (drawImageCanvasCommand.Image is { })
{
var image = ToSKImage(drawImageCanvasCommand.Image);
var source = ToSKRect(drawImageCanvasCommand.Source);
var dest = ToSKRect(drawImageCanvasCommand.Dest);
var paint = ToSKPaint(drawImageCanvasCommand.Paint);
skCanvas.DrawImage(image, source, dest, paint);
if (wireframe)
{
var rectPath = new SkiaSharp.SKPath();
rectPath.AddRect(ToSKRect(drawImageCanvasCommand.Dest));
skCanvas.DrawPath(rectPath, ToWireframePaint(null));
}
else
{
var image = ToSKImage(drawImageCanvasCommand.Image);
var source = ToSKRect(drawImageCanvasCommand.Source);
var dest = ToSKRect(drawImageCanvasCommand.Dest);
var paint = ToSKPaint(drawImageCanvasCommand.Paint);
skCanvas.DrawImage(image, source, dest, paint);
}
}
break;
}
Expand All @@ -1315,7 +1342,9 @@
if (drawPathCanvasCommand.Path is { } && drawPathCanvasCommand.Paint is { })
{
var path = ToSKPath(drawPathCanvasCommand.Path);
var paint = ToSKPaint(drawPathCanvasCommand.Paint);
var paint = wireframe
? ToWireframePaint(drawPathCanvasCommand.Paint)
: ToSKPaint(drawPathCanvasCommand.Paint);
skCanvas.DrawPath(path, paint);
}
break;
Expand All @@ -1326,7 +1355,9 @@
{
var text = drawPositionedTextCanvasCommand.TextBlob.Text;
var points = ToSKPoints(drawPositionedTextCanvasCommand.TextBlob.Points);
var paint = ToSKPaint(drawPositionedTextCanvasCommand.Paint);
var paint = wireframe
? ToWireframePaint(drawPositionedTextCanvasCommand.Paint)
: ToSKPaint(drawPositionedTextCanvasCommand.Paint);
var font = paint?.ToFont();
var textBlob = SkiaSharp.SKTextBlob.CreatePositioned(text, font, points);
skCanvas.DrawText(textBlob, 0, 0, paint);
Expand All @@ -1340,7 +1371,9 @@
var text = drawTextCanvasCommand.Text;
var x = drawTextCanvasCommand.X;
var y = drawTextCanvasCommand.Y;
var paint = ToSKPaint(drawTextCanvasCommand.Paint);
var paint = wireframe
? ToWireframePaint(drawTextCanvasCommand.Paint)
: ToSKPaint(drawTextCanvasCommand.Paint);
skCanvas.DrawText(text, x, y, paint);
}
break;
Expand All @@ -1353,15 +1386,17 @@
var path = ToSKPath(drawTextOnPathCanvasCommand.Path);
var hOffset = drawTextOnPathCanvasCommand.HOffset;
var vOffset = drawTextOnPathCanvasCommand.VOffset;
var paint = ToSKPaint(drawTextOnPathCanvasCommand.Paint);
var paint = wireframe
? ToWireframePaint(drawTextOnPathCanvasCommand.Paint)
: ToSKPaint(drawTextOnPathCanvasCommand.Paint);
skCanvas.DrawTextOnPath(text, path, hOffset, vOffset, paint);
}
break;
}
}
}

public void Draw(SKPicture picture, SkiaSharp.SKCanvas skCanvas)
public void Draw(SKPicture picture, SkiaSharp.SKCanvas skCanvas, bool wireframe = false)
{
if (picture.Commands is null)
{
Expand All @@ -1370,7 +1405,48 @@

foreach (var canvasCommand in picture.Commands)
{
Draw(canvasCommand, skCanvas);
Draw(canvasCommand, skCanvas, wireframe);
}
}

private SkiaSharp.SKPaint ToWireframePaint(SKPaint? paint)
{
var strokeCap = paint is null ? SkiaSharp.SKStrokeCap.Butt : ToSKStrokeCap(paint.StrokeCap);
var strokeJoin = paint is null ? SkiaSharp.SKStrokeJoin.Miter : ToSKStrokeJoin(paint.StrokeJoin);
var textAlign = paint is null ? SkiaSharp.SKTextAlign.Left : ToSKTextAlign(paint.TextAlign);
var typeface = paint is null ? null : ToSKTypeface(paint.Typeface);
var textEncoding = paint is null ? SkiaSharp.SKTextEncoding.Utf8 : ToSKTextEncoding(paint.TextEncoding);
var colorFilter = paint is null ? null : ToSKColorFilter(paint.ColorFilter);
var imageFilter = paint is null ? null : ToSKImageFilter(paint.ImageFilter);
var pathEffect = paint is null ? null : ToSKPathEffect(paint.PathEffect);
var blendMode = paint is null ? SkiaSharp.SKBlendMode.SrcOver : ToSKBlendMode(paint.BlendMode);
var filterQuality = paint is null ? SkiaSharp.SKFilterQuality.None : ToSKFilterQuality(paint.FilterQuality);

return new SkiaSharp.SKPaint
{
Style = SkiaSharp.SKPaintStyle.Stroke,
IsAntialias = paint?.IsAntialias ?? false,
StrokeWidth = 0,
StrokeCap = strokeCap,
StrokeJoin = strokeJoin,
StrokeMiter = paint?.StrokeMiter ?? 4,
TextSize = paint?.TextSize ?? 0,
TextAlign = textAlign,
Typeface = typeface,
LcdRenderText = paint?.LcdRenderText ?? false,
SubpixelText = paint?.SubpixelText ?? false,
TextEncoding = textEncoding,
Color = new SkiaSharp.SKColor(128, 128, 128, 255),
ColorFilter = colorFilter,
ImageFilter = imageFilter,
PathEffect = pathEffect,
BlendMode = blendMode,
FilterQuality = filterQuality
};
}

public void DrawWireframe(SKPicture picture, SkiaSharp.SKCanvas skCanvas)
{
Draw(picture, skCanvas, true);
}
}
Loading