Browse Source

Add `DrawingImage.Viewbox` (#18913)

* Added DrawingImage.Frame: a rectangular region of `Drawing`, in device independent pixels, to display when rendering the image

* Renamed Frame to Viewbox
Added test
MikeCodesDotNET-coc-update
Tom Edwards 1 month ago
committed by GitHub
parent
commit
f1703dd784
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 39
      src/Avalonia.Base/Media/DrawingImage.cs
  2. 27
      tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs
  3. BIN
      tests/TestFiles/Skia/Media/ImageDrawing/ImageDrawing_Viewbox.expected.png

39
src/Avalonia.Base/Media/DrawingImage.cs

@ -22,6 +22,12 @@ namespace Avalonia.Media
public static readonly StyledProperty<Drawing?> DrawingProperty =
AvaloniaProperty.Register<DrawingImage, Drawing?>(nameof(Drawing));
/// <summary>
/// Defines the <see cref="Viewbox"/> property.
/// </summary>
public static readonly StyledProperty<Rect?> ViewboxProperty =
AvaloniaProperty.Register<DrawingImage, Rect?>(nameof(Viewbox));
/// <inheritdoc/>
public event EventHandler? Invalidated;
@ -35,8 +41,25 @@ namespace Avalonia.Media
set => SetValue(DrawingProperty, value);
}
/// <summary>
/// Gets or sets a rectangular region of <see cref="Drawing"/>, in device independent pixels, to display
/// when rendering this image.
/// </summary>
/// <remarks>
/// This value can be used to display only part of <see cref="Drawing"/>, or to surround it with empty
/// space. If null, <see cref="Drawing"/> will provide its own viewbox.
/// </remarks>
/// <seealso cref="Drawing.GetBounds"/>
public Rect? Viewbox
{
get => GetValue(ViewboxProperty);
set => SetValue(ViewboxProperty, value);
}
/// <inheritdoc/>
public Size Size => Drawing?.GetBounds().Size ?? default;
public Size Size => GetBounds().Size;
private Rect GetBounds() => Viewbox ?? Drawing?.GetBounds() ?? default;
/// <inheritdoc/>
void IImage.Draw(
@ -44,14 +67,18 @@ namespace Avalonia.Media
Rect sourceRect,
Rect destRect)
{
var drawing = Drawing;
if (Drawing is not { } drawing || sourceRect.Size == default || destRect.Size == default)
{
return;
}
var bounds = GetBounds();
if (drawing == null)
if (bounds.Size == default)
{
return;
}
var bounds = drawing.GetBounds();
var scale = Matrix.CreateScale(
destRect.Width / sourceRect.Width,
destRect.Height / sourceRect.Height);
@ -62,7 +89,7 @@ namespace Avalonia.Media
using (context.PushClip(destRect))
using (context.PushTransform(translate * scale))
{
Drawing?.Draw(context);
drawing.Draw(context);
}
}
@ -71,7 +98,7 @@ namespace Avalonia.Media
{
base.OnPropertyChanged(change);
if (change.Property == DrawingProperty)
if (change.Property == DrawingProperty || change.Property == ViewboxProperty)
{
RaiseInvalidated(EventArgs.Empty);
}

27
tests/Avalonia.RenderTests/Media/ImageDrawingTests.cs

@ -45,6 +45,31 @@ namespace Avalonia.Skia.RenderTests
CompareImages();
}
[Fact]
public async Task ImageDrawing_Viewbox()
{
Decorator target = new Decorator
{
Width = 200,
Height = 200,
Child = new Image
{
Source = new DrawingImage
{
Viewbox = new Rect(48, 37, 100, 125),
Drawing = new ImageDrawing
{
ImageSource = new Bitmap(BitmapPath),
Rect = new Rect(0, 0, 200, 200),
}
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ImageDrawing_BottomRight()
{
@ -85,7 +110,7 @@ namespace Avalonia.Skia.RenderTests
{
var target = new Border
{
Width = 400,
Width = 400,
Height = 400,
Child = new DrawingBrushTransformTest()
};

BIN
tests/TestFiles/Skia/Media/ImageDrawing/ImageDrawing_Viewbox.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Loading…
Cancel
Save