Skip to content

Commit

Permalink
Add new skia controls
Browse files Browse the repository at this point in the history
  • Loading branch information
wieslawsoltes committed Jul 21, 2021
1 parent f247e84 commit 1da5cca
Show file tree
Hide file tree
Showing 16 changed files with 538 additions and 59 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ public void Draw(SKCanvas canvas)
```xml
<ItemGroup>
<PackageReference Include="Svg.SourceGenerator.Skia" Version="0.5.0" />
<PackageReference Include="Avalonia.SKPictureImage" Version="0.5.0" />
<PackageReference Include="Avalonia.Controls.Skia" Version="0.5.0" />
</ItemGroup>
```

Expand All @@ -297,7 +297,7 @@ public void Draw(SKCanvas canvas)
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AvaloniaSample;assembly=AvaloniaSample"
xmlns:skp="clr-namespace:Avalonia.SKPictureImage;assembly=Avalonia.SKPictureImage"
xmlns:skp="clr-namespace:Avalonia.Controls.Skia;assembly=Avalonia.Controls.Skia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
Width="900" Height="650" WindowStartupLocation="CenterScreen"
x:Class="AvaloniaSample.MainWindow"
Expand Down
2 changes: 1 addition & 1 deletion Svg.Skia.sln
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Svg.SourceGenerator.Skia.Sa
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Svg", "src\Avalonia.Svg\Avalonia.Svg.csproj", "{8B0407E4-0A8A-4F46-A218-B9FE500091A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.SKPictureImage", "src\Avalonia.SKPictureImage\Avalonia.SKPictureImage.csproj", "{223B7A5A-E263-4D40-9A6E-FE31EAE92F45}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Controls.Skia", "src\Avalonia.Controls.Skia\Avalonia.Controls.Skia.csproj", "{223B7A5A-E263-4D40-9A6E-FE31EAE92F45}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Svg.Generators", "externals\SVG\Generators\Svg.Generators.csproj", "{AF8AEF5B-0664-4106-9BD3-389758F39B12}"
EndProject
Expand Down
4 changes: 2 additions & 2 deletions build/Base.props
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>0.5.6.1</VersionPrefix>
<VersionPrefix>0.5.6.2</VersionPrefix>
<VersionSuffix></VersionSuffix>
<AvaloniaVersionPrefix>0.10.6.1</AvaloniaVersionPrefix>
<AvaloniaVersionPrefix>0.10.6.2</AvaloniaVersionPrefix>
<AvaloniaVersionSuffix>$(VersionSuffix)</AvaloniaVersionSuffix>
<Authors>Wiesław Šoltés</Authors>
<Company>Wiesław Šoltés</Company>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,24 @@
</PropertyGroup>

<ItemGroup>
<PublishReadyToRunExclude Include="Microsoft.CodeAnalysis.dll"/>
<PublishReadyToRunExclude Include="Microsoft.CodeAnalysis.dll" />
</ItemGroup>

<Import Project="..\..\build\Avalonia.props"/>
<Import Project="..\..\build\Avalonia.Desktop.props"/>
<Import Project="..\..\build\Avalonia.Diagnostics.props"/>
<Import Project="..\..\build\Avalonia.props" />
<Import Project="..\..\build\Avalonia.Desktop.props" />
<Import Project="..\..\build\Avalonia.Diagnostics.props" />

<ItemGroup>
<AdditionalFiles Include="Assets/__tiger.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Tiger"/>
<AdditionalFiles Include="Assets/__AJ_Digital_Camera.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Camera"/>
<AdditionalFiles Include="Assets/SVG_logo.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Logo"/>
<AdditionalFiles Include="Assets/__tiger.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Tiger" />
<AdditionalFiles Include="Assets/__AJ_Digital_Camera.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Camera" />
<AdditionalFiles Include="Assets/SVG_logo.svg" NamespaceName="AvaloniaSKPictureImageSample" ClassName="Logo" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.SKPictureImage\Avalonia.SKPictureImage.csproj"/>
<ProjectReference Include="..\..\src\Svg.SourceGenerator.Skia\Svg.SourceGenerator.Skia.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="False"/>
<ProjectReference Include="..\..\src\Avalonia.Controls.Skia\Avalonia.Controls.Skia.csproj" />
<ProjectReference Include="..\..\src\Svg.SourceGenerator.Skia\Svg.SourceGenerator.Skia.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="False" />
</ItemGroup>

<Import Project="..\..\src\Svg.SourceGenerator.Skia\Svg.SourceGenerator.Skia.props"/>
<Import Project="..\..\src\Svg.SourceGenerator.Skia\Svg.SourceGenerator.Skia.props" />

</Project>
2 changes: 1 addition & 1 deletion samples/AvaloniaSKPictureImageSample/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using Avalonia;
using Avalonia.SKPictureImage;
using Avalonia.Controls.Skia;

namespace AvaloniaSKPictureImageSample
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
<NoWarn>CS1591</NoWarn>
<IsPackable>True</IsPackable>
<Nullable>enable</Nullable>
<RootNamespace>Avalonia.Controls.Skia</RootNamespace>
</PropertyGroup>

<PropertyGroup>
<Description>An SKPictureImage image control for Avalonia.</Description>
<PackageId>Avalonia.SKPictureImage</PackageId>
<Description>A SkiaSharp based controls for Avalonia.</Description>
<PackageId>Avalonia.Controls.Skia</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageTags>svg;vector graphics;rendering;2d;graphics;geometry;shapes;skiasharp;skia;control;avalonia;avaloniaui</PackageTags>
<PackageTags>vector graphics;rendering;2d;graphics;picture;bitamp;geometry;shapes;skiasharp;skia;control;avalonia;avaloniaui</PackageTags>
</PropertyGroup>

<Import Project="..\..\build\Base.props" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
using Avalonia.Metadata;

[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.SKPictureImage")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Skia")]
152 changes: 152 additions & 0 deletions src/Avalonia.Controls.Skia/SKBitmapControl.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System;
using Avalonia.Media;
using Avalonia.Metadata;
using SkiaSharp;

namespace Avalonia.Controls.Skia
{
/// <summary>
/// SKBitmap control.
/// </summary>
public class SKBitmapControl : Control, IAffectsRender
{
/// <summary>
/// Defines the <see cref="Bitmap"/> property.
/// </summary>
public static readonly StyledProperty<SKBitmap?> BitmapProperty =
AvaloniaProperty.Register<SKBitmapControl, SKBitmap?>(nameof(Bitmap));

/// <summary>
/// Defines the <see cref="Stretch"/> property.
/// </summary>
public static readonly StyledProperty<Stretch> StretchProperty =
AvaloniaProperty.Register<SKBitmapControl, Stretch>(nameof(Stretch), Stretch.Uniform);

/// <summary>
/// Defines the <see cref="StretchDirection"/> property.
/// </summary>
public static readonly StyledProperty<StretchDirection> StretchDirectionProperty =
AvaloniaProperty.Register<SKBitmapControl, StretchDirection>(nameof(StretchDirection), StretchDirection.Both);

/// <inheritdoc/>
public event EventHandler? Invalidated;

/// <summary>
/// Gets or sets the <see cref="SKBitmap"/> bitmap.
/// </summary>
[Content]
public SKBitmap? Bitmap
{
get => GetValue(BitmapProperty);
set => SetValue(BitmapProperty, value);
}

/// <summary>
/// Gets or sets a value controlling how the image will be stretched.
/// </summary>
public Stretch Stretch
{
get { return GetValue(StretchProperty); }
set { SetValue(StretchProperty, value); }
}

/// <summary>
/// Gets or sets a value controlling in what direction the image will be stretched.
/// </summary>
public StretchDirection StretchDirection
{
get { return GetValue(StretchDirectionProperty); }
set { SetValue(StretchDirectionProperty, value); }
}

static SKBitmapControl()
{
AffectsRender<SKBitmapControl>(BitmapProperty, StretchProperty, StretchDirectionProperty);
AffectsMeasure<SKBitmapControl>(BitmapProperty, StretchProperty, StretchDirectionProperty);
}

protected override Size MeasureOverride(Size availableSize)
{
var bitmap = Bitmap;
if (bitmap is null)
{
return new Size();
}

var sourceSize = new Size(bitmap.Width, bitmap.Height);
return Stretch.CalculateSize(availableSize, sourceSize, StretchDirection);
}

protected override Size ArrangeOverride(Size finalSize)
{
var bitmap = Bitmap;
if (bitmap is null)
{
return new Size();
}

var sourceSize = new Size(bitmap.Width, bitmap.Height);
return Stretch.CalculateSize(finalSize, sourceSize);
}

public override void Render(DrawingContext context)
{
var bitmap = Bitmap;
if (bitmap is null)
{
return;
}

var viewPort = new Rect(Bounds.Size);
var sourceSize = new Size(bitmap.Width, bitmap.Height);
if (sourceSize.Width <= 0 || sourceSize.Height <= 0)
{
return;
}

var scale = Stretch.CalculateScaling(Bounds.Size, sourceSize, StretchDirection);
var scaledSize = sourceSize * scale;
var destRect = viewPort
.CenterRect(new Rect(scaledSize))
.Intersect(viewPort);
var sourceRect = new Rect(sourceSize)
.CenterRect(new Rect(destRect.Size / scale));

var bounds = SKRect.Create(0, 0, bitmap.Width, bitmap.Height);
var scaleMatrix = Matrix.CreateScale(
destRect.Width / sourceRect.Width,
destRect.Height / sourceRect.Height);
var translateMatrix = Matrix.CreateTranslation(
-sourceRect.X + destRect.X - bounds.Top,
-sourceRect.Y + destRect.Y - bounds.Left);

if (bounds.IsEmpty || destRect.IsEmpty)
{
return;
}

using (context.PushClip(destRect))
using (context.PushPreTransform(translateMatrix * scaleMatrix))
{
context.Custom(new SKBitmapDrawOperation(new Rect(0, 0, bounds.Width, bounds.Height), bitmap));
}
}

/// <inheritdoc/>
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);

if (change.Property == BitmapProperty)
{
RaiseInvalidated(EventArgs.Empty);
}
}

/// <summary>
/// Raises the <see cref="Invalidated"/> event.
/// </summary>
/// <param name="e">The event args.</param>
protected void RaiseInvalidated(EventArgs e) => Invalidated?.Invoke(this, e);
}
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Skia;
using SkiaSharp;

namespace Avalonia.SKPictureImage
namespace Avalonia.Controls.Skia
{
public class SKBitmapDrawOperation : ICustomDrawOperation
{
private readonly SkiaSharp.SKBitmap? _bitmap;
private readonly SKBitmap? _bitmap;
private readonly Rect _bounds;

public SKBitmapDrawOperation(Rect bounds, SkiaSharp.SKBitmap? bitmap)
public SKBitmapDrawOperation(Rect bounds, SKBitmap? bitmap)
{
_bitmap = bitmap;
_bounds = bounds;
Expand All @@ -21,7 +22,7 @@ public void Dispose()

public Rect Bounds => _bounds;

public bool HitTest(Point p) => false;
public bool HitTest(Point p) => _bounds.Contains(p);

public bool Equals(ICustomDrawOperation? other) => false;

Expand All @@ -32,9 +33,8 @@ public void Render(IDrawingContextImpl context)
{
canvas.DrawBitmap(
_bitmap,
SkiaSharp.SKRect.Create(0, 0, _bitmap.Width, _bitmap.Height),
SkiaSharp.SKRect.Create((float)_bounds.Left, (float)_bounds.Top, (float)_bounds.Width, (float)_bounds.Height),
null);
SKRect.Create(0, 0, _bitmap.Width, _bitmap.Height),
SKRect.Create((float)_bounds.Left, (float)_bounds.Top, (float)_bounds.Width, (float)_bounds.Height));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
#nullable disable
using System;
using System;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.Visuals.Media.Imaging;
using SkiaSharp;

namespace Avalonia.SKPictureImage
namespace Avalonia.Controls.Skia
{
/// <summary>
/// An <see cref="IImage"/> that uses a <see cref="SKBitmapImage"/> for content.
Expand All @@ -14,16 +14,16 @@ public class SKBitmapImage : AvaloniaObject, IImage, IAffectsRender
/// <summary>
/// Defines the <see cref="Source"/> property.
/// </summary>
public static readonly StyledProperty<SkiaSharp.SKBitmap> SourceProperty =
AvaloniaProperty.Register<SKBitmapImage, SkiaSharp.SKBitmap>(nameof(Source));
public static readonly StyledProperty<SKBitmap?> SourceProperty =
AvaloniaProperty.Register<SKBitmapImage, SKBitmap?>(nameof(Source));

public event EventHandler Invalidated;
public event EventHandler? Invalidated;

/// <summary>
/// Gets or sets the <see cref="SKBitmap"/> content.
/// </summary>
[Content]
public SkiaSharp.SKBitmap Source
public SKBitmap? Source
{
get => GetValue(SourceProperty);
set => SetValue(SourceProperty, value);
Expand All @@ -40,7 +40,11 @@ void IImage.Draw(DrawingContext context, Rect sourceRect, Rect destRect, BitmapI
{
return;
}
var bounds = SkiaSharp.SKRect.Create(0, 0, source.Width, source.Height);
if (source.Width <= 0 || source.Height <= 0)
{
return;
}
var bounds = SKRect.Create(0, 0, source.Width, source.Height);
var scaleMatrix = Matrix.CreateScale(destRect.Width / sourceRect.Width, destRect.Height / sourceRect.Height);
var translateMatrix = Matrix.CreateTranslation(-sourceRect.X + destRect.X - bounds.Top, -sourceRect.Y + destRect.Y - bounds.Left);
using (context.PushClip(destRect))
Expand Down
Loading

0 comments on commit 1da5cca

Please sign in to comment.