Browse Source

Refactoring

Add interpolation to TileBrush
pull/1762/head
Benedikt Schroeder 8 years ago
parent
commit
c0dd75bcce
  1. 6
      src/Avalonia.Controls/Image.cs
  2. 38
      src/Avalonia.Controls/RenderOptions.cs
  3. 6
      src/Avalonia.Visuals/Media/DrawingContext.cs
  4. 12
      src/Avalonia.Visuals/Media/ITileBrush.cs
  5. 19
      src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs
  6. 11
      src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs
  7. 16
      src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs
  8. 12
      src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs
  9. 38
      src/Avalonia.Visuals/Media/RenderOptions.cs
  10. 15
      src/Avalonia.Visuals/Media/TileBrush.cs
  11. 4
      src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs
  12. 6
      src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs
  13. 16
      src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs
  14. 33
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  15. 49
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  16. 9
      src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs
  17. 2
      tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs
  18. 5
      tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs

6
src/Avalonia.Controls/Image.cs

@ -1,14 +1,12 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Visuals.Media;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
using Avalonia.Visuals.Media.Imaging;
/// <summary> /// <summary>
/// Displays a <see cref="Bitmap"/> image. /// Displays a <see cref="Bitmap"/> image.
/// </summary> /// </summary>

38
src/Avalonia.Controls/RenderOptions.cs

@ -1,38 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Controls
{
public class RenderOptions
{
/// <summary>
/// Defines the <see cref="BitmapScalingMode"/> property.
/// </summary>
public static readonly StyledProperty<BitmapScalingMode> BitmapScalingModeProperty =
AvaloniaProperty.RegisterAttached<RenderOptions, Control, BitmapScalingMode>(
"BitmapScalingMode",
inherits: true);
/// <summary>
/// Gets the value of the BitmapScalingMode attached property for a control.
/// </summary>
/// <param name="element">The control.</param>
/// <returns>The control's left coordinate.</returns>
public static BitmapScalingMode GetBitmapScalingMode(AvaloniaObject element)
{
return element.GetValue(BitmapScalingModeProperty);
}
/// <summary>
/// Sets the value of the BitmapScalingMode attached property for a control.
/// </summary>
/// <param name="element">The control.</param>
/// <param name="value">The left value.</param>
public static void SetBitmapScalingMode(AvaloniaObject element, double value)
{
element.SetValue(BitmapScalingModeProperty, value);
}
}
}

6
src/Avalonia.Visuals/Media/DrawingContext.cs

@ -69,12 +69,12 @@ namespace Avalonia.Media
/// <param name="opacity">The opacity to draw with.</param> /// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param> /// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param> /// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapScalingMode"></param> /// <param name="bitmapInterpolationMode"></param>
public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode = default) public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default)
{ {
Contract.Requires<ArgumentNullException>(source != null); Contract.Requires<ArgumentNullException>(source != null);
PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapScalingMode); PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapInterpolationMode);
} }
/// <summary> /// <summary>

12
src/Avalonia.Visuals/Media/ITileBrush.cs

@ -1,5 +1,7 @@
namespace Avalonia.Media namespace Avalonia.Media
{ {
using Avalonia.Visuals.Media.Imaging;
/// <summary> /// <summary>
/// A brush which displays a repeating image. /// A brush which displays a repeating image.
/// </summary> /// </summary>
@ -35,5 +37,13 @@
/// Gets the brush's tile mode. /// Gets the brush's tile mode.
/// </summary> /// </summary>
TileMode TileMode { get; } TileMode TileMode { get; }
/// <summary>
/// Gets the bitmap interpolation mode.
/// </summary>
/// <value>
/// The bitmap interpolation mode.
/// </value>
BitmapInterpolationMode BitmapInterpolationMode { get; }
} }
} }

19
src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs → src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs

@ -6,21 +6,26 @@ namespace Avalonia.Visuals.Media.Imaging
/// <summary> /// <summary>
/// Controls the performance and quality of bitmap scaling. /// Controls the performance and quality of bitmap scaling.
/// </summary> /// </summary>
public enum BitmapScalingMode public enum BitmapInterpolationMode
{ {
/// <summary> /// <summary>
/// Highest quality but worst performance. /// Uses the default behavior of the underling render backend.
/// </summary>
Default,
/// <summary>
/// The best performance but worst image quality.
/// </summary> /// </summary>
HighQuality, LowQuality,
/// <summary> /// <summary>
/// Good performance and decent image quality. /// Good performance and decent image quality.
/// </summary> /// </summary>
MediumQuality, MediumQuality,
/// <summary> /// <summary>
/// The best performance but worst image quality. /// Highest quality but worst performance.
/// </summary> /// </summary>
LowQuality HighQuality
} }
} }

11
src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs

@ -1,5 +1,5 @@
using System; using Avalonia.Media.Imaging;
using Avalonia.Media.Imaging; using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media.Immutable namespace Avalonia.Media.Immutable
{ {
@ -21,6 +21,7 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect. /// How the source rectangle will be stretched to fill the destination rect.
/// </param> /// </param>
/// <param name="tileMode">The tile mode.</param> /// <param name="tileMode">The tile mode.</param>
/// <param name="bitmapInterpolationMode">The bitmap interpolation mode.</param>
public ImmutableImageBrush( public ImmutableImageBrush(
IBitmap source, IBitmap source,
AlignmentX alignmentX = AlignmentX.Center, AlignmentX alignmentX = AlignmentX.Center,
@ -29,7 +30,8 @@ namespace Avalonia.Media.Immutable
double opacity = 1, double opacity = 1,
RelativeRect? sourceRect = null, RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform, Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None) TileMode tileMode = TileMode.None,
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
: base( : base(
alignmentX, alignmentX,
alignmentY, alignmentY,
@ -37,7 +39,8 @@ namespace Avalonia.Media.Immutable
opacity, opacity,
sourceRect ?? RelativeRect.Fill, sourceRect ?? RelativeRect.Fill,
stretch, stretch,
tileMode) tileMode,
bitmapInterpolationMode)
{ {
Source = source; Source = source;
} }

16
src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs

@ -1,4 +1,7 @@
using System; // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Media.Immutable namespace Avalonia.Media.Immutable
{ {
@ -19,6 +22,7 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect. /// How the source rectangle will be stretched to fill the destination rect.
/// </param> /// </param>
/// <param name="tileMode">The tile mode.</param> /// <param name="tileMode">The tile mode.</param>
/// <param name="bitmapInterpolationMode">Controls the quality of interpolation.</param>
protected ImmutableTileBrush( protected ImmutableTileBrush(
AlignmentX alignmentX, AlignmentX alignmentX,
AlignmentY alignmentY, AlignmentY alignmentY,
@ -26,7 +30,8 @@ namespace Avalonia.Media.Immutable
double opacity, double opacity,
RelativeRect sourceRect, RelativeRect sourceRect,
Stretch stretch, Stretch stretch,
TileMode tileMode) TileMode tileMode,
BitmapInterpolationMode bitmapInterpolationMode)
{ {
AlignmentX = alignmentX; AlignmentX = alignmentX;
AlignmentY = alignmentY; AlignmentY = alignmentY;
@ -35,6 +40,7 @@ namespace Avalonia.Media.Immutable
SourceRect = sourceRect; SourceRect = sourceRect;
Stretch = stretch; Stretch = stretch;
TileMode = tileMode; TileMode = tileMode;
BitmapInterpolationMode = bitmapInterpolationMode;
} }
/// <summary> /// <summary>
@ -49,7 +55,8 @@ namespace Avalonia.Media.Immutable
source.Opacity, source.Opacity,
source.SourceRect, source.SourceRect,
source.Stretch, source.Stretch,
source.TileMode) source.TileMode,
source.BitmapInterpolationMode)
{ {
} }
@ -73,5 +80,8 @@ namespace Avalonia.Media.Immutable
/// <inheritdoc/> /// <inheritdoc/>
public TileMode TileMode { get; } public TileMode TileMode { get; }
/// <inheritdoc/>
public BitmapInterpolationMode BitmapInterpolationMode { get; }
} }
} }

12
src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs

@ -1,4 +1,7 @@
using System; // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Visuals.Media.Imaging;
using Avalonia.VisualTree; using Avalonia.VisualTree;
namespace Avalonia.Media.Immutable namespace Avalonia.Media.Immutable
@ -21,6 +24,7 @@ namespace Avalonia.Media.Immutable
/// How the source rectangle will be stretched to fill the destination rect. /// How the source rectangle will be stretched to fill the destination rect.
/// </param> /// </param>
/// <param name="tileMode">The tile mode.</param> /// <param name="tileMode">The tile mode.</param>
/// <param name="bitmapInterpolationMode">Controls the quality of interpolation.</param>
public ImmutableVisualBrush( public ImmutableVisualBrush(
IVisual visual, IVisual visual,
AlignmentX alignmentX = AlignmentX.Center, AlignmentX alignmentX = AlignmentX.Center,
@ -29,7 +33,8 @@ namespace Avalonia.Media.Immutable
double opacity = 1, double opacity = 1,
RelativeRect? sourceRect = null, RelativeRect? sourceRect = null,
Stretch stretch = Stretch.Uniform, Stretch stretch = Stretch.Uniform,
TileMode tileMode = TileMode.None) TileMode tileMode = TileMode.None,
BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default)
: base( : base(
alignmentX, alignmentX,
alignmentY, alignmentY,
@ -37,7 +42,8 @@ namespace Avalonia.Media.Immutable
opacity, opacity,
sourceRect ?? RelativeRect.Fill, sourceRect ?? RelativeRect.Fill,
stretch, stretch,
tileMode) tileMode,
bitmapInterpolationMode)
{ {
Visual = visual; Visual = visual;
} }

38
src/Avalonia.Visuals/Media/RenderOptions.cs

@ -0,0 +1,38 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using Avalonia.Visuals.Media.Imaging;
namespace Avalonia.Visuals.Media
{
public class RenderOptions
{
/// <summary>
/// Defines the <see cref="Imaging.BitmapInterpolationMode"/> property.
/// </summary>
public static readonly StyledProperty<BitmapInterpolationMode> BitmapInterpolationMode =
AvaloniaProperty.RegisterAttached<RenderOptions, AvaloniaObject, BitmapInterpolationMode>(
"BitmapInterpolationMode",
inherits: true);
/// <summary>
/// Gets the value of the BitmapInterpolationMode attached property for a control.
/// </summary>
/// <param name="element">The control.</param>
/// <returns>The control's left coordinate.</returns>
public static BitmapInterpolationMode GetBitmapScalingMode(AvaloniaObject element)
{
return element.GetValue(BitmapInterpolationMode);
}
/// <summary>
/// Sets the value of the BitmapInterpolationMode attached property for a control.
/// </summary>
/// <param name="element">The control.</param>
/// <param name="value">The left value.</param>
public static void SetBitmapScalingMode(AvaloniaObject element, BitmapInterpolationMode value)
{
element.SetValue(BitmapInterpolationMode, value);
}
}
}

15
src/Avalonia.Visuals/Media/TileBrush.cs

@ -3,6 +3,9 @@
namespace Avalonia.Media namespace Avalonia.Media
{ {
using Avalonia.Visuals.Media;
using Avalonia.Visuals.Media.Imaging;
/// <summary> /// <summary>
/// Describes how a <see cref="TileBrush"/> is tiled. /// Describes how a <see cref="TileBrush"/> is tiled.
/// </summary> /// </summary>
@ -129,5 +132,17 @@ namespace Avalonia.Media
get { return (TileMode)GetValue(TileModeProperty); } get { return (TileMode)GetValue(TileModeProperty); }
set { SetValue(TileModeProperty, value); } set { SetValue(TileModeProperty, value); }
} }
/// <summary>
/// Gets or sets the bitmap interpolation mode.
/// </summary>
/// <value>
/// The bitmap interpolation mode.
/// </value>
public BitmapInterpolationMode BitmapInterpolationMode
{
get { return RenderOptions.GetBitmapScalingMode(this); }
set { RenderOptions.SetBitmapScalingMode(this, value); }
}
} }
} }

4
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@ -32,8 +32,8 @@ namespace Avalonia.Platform
/// <param name="opacity">The opacity to draw with.</param> /// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param> /// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param> /// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapScalingMode">Controls</param> /// <param name="bitmapInterpolationMode">Controls</param>
void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode = default); void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default);
/// <summary> /// <summary>
/// Draws a bitmap image. /// Draws a bitmap image.

6
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@ -115,13 +115,13 @@ namespace Avalonia.Rendering.SceneGraph
} }
/// <inheritdoc/> /// <inheritdoc/>
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{ {
var next = NextDrawAs<ImageNode>(); var next = NextDrawAs<ImageNode>();
if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapScalingMode)) if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode))
{ {
Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapScalingMode)); Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode));
} }
else else
{ {

16
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@ -21,8 +21,8 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="opacity">The draw opacity.</param> /// <param name="opacity">The draw opacity.</param>
/// <param name="sourceRect">The source rect.</param> /// <param name="sourceRect">The source rect.</param>
/// <param name="destRect">The destination rect.</param> /// <param name="destRect">The destination rect.</param>
/// <param name="bitmapScalingMode">The bitmap scaling mode.</param> /// <param name="bitmapInterpolationMode">The bitmap scaling mode.</param>
public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
: base(destRect, transform, null) : base(destRect, transform, null)
{ {
Transform = transform; Transform = transform;
@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
Opacity = opacity; Opacity = opacity;
SourceRect = sourceRect; SourceRect = sourceRect;
DestRect = destRect; DestRect = destRect;
BitmapScalingMode = bitmapScalingMode; BitmapInterpolationMode = bitmapInterpolationMode;
} }
/// <summary> /// <summary>
@ -64,7 +64,7 @@ namespace Avalonia.Rendering.SceneGraph
/// <value> /// <value>
/// The scaling mode. /// The scaling mode.
/// </value> /// </value>
public BitmapScalingMode BitmapScalingMode { get; } public BitmapInterpolationMode BitmapInterpolationMode { get; }
/// <summary> /// <summary>
/// Determines if this draw operation equals another. /// Determines if this draw operation equals another.
@ -74,20 +74,20 @@ namespace Avalonia.Rendering.SceneGraph
/// <param name="opacity">The opacity of the other draw operation.</param> /// <param name="opacity">The opacity of the other draw operation.</param>
/// <param name="sourceRect">The source rect of the other draw operation.</param> /// <param name="sourceRect">The source rect of the other draw operation.</param>
/// <param name="destRect">The dest rect of the other draw operation.</param> /// <param name="destRect">The dest rect of the other draw operation.</param>
/// <param name="bitmapScalingMode">The bitmap scaling mode.</param> /// <param name="bitmapInterpolationMode">The bitmap scaling mode.</param>
/// <returns>True if the draw operations are the same, otherwise false.</returns> /// <returns>True if the draw operations are the same, otherwise false.</returns>
/// <remarks> /// <remarks>
/// The properties of the other draw operation are passed in as arguments to prevent /// The properties of the other draw operation are passed in as arguments to prevent
/// allocation of a not-yet-constructed draw operation object. /// allocation of a not-yet-constructed draw operation object.
/// </remarks> /// </remarks>
public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{ {
return transform == Transform && return transform == Transform &&
Equals(source.Item, Source.Item) && Equals(source.Item, Source.Item) &&
opacity == Opacity && opacity == Opacity &&
sourceRect == SourceRect && sourceRect == SourceRect &&
destRect == DestRect && destRect == DestRect &&
bitmapScalingMode == BitmapScalingMode; bitmapInterpolationMode == BitmapInterpolationMode;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -96,7 +96,7 @@ namespace Avalonia.Rendering.SceneGraph
// TODO: Probably need to introduce some kind of locking mechanism in the case of // TODO: Probably need to introduce some kind of locking mechanism in the case of
// WriteableBitmap. // WriteableBitmap.
context.Transform = Transform; context.Transform = Transform;
context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapScalingMode); context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode);
} }
/// <inheritdoc/> /// <inheritdoc/>

33
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -14,7 +14,9 @@ using Avalonia.Visuals.Media.Imaging;
using SkiaSharp; using SkiaSharp;
namespace Avalonia.Skia namespace Avalonia.Skia
{ {
using Avalonia.Controls;
/// <summary> /// <summary>
/// Skia based drawing context. /// Skia based drawing context.
/// </summary> /// </summary>
@ -96,7 +98,7 @@ namespace Avalonia.Skia
} }
/// <inheritdoc /> /// <inheritdoc />
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{ {
var drawableImage = (IDrawableBitmapImpl)source.Item; var drawableImage = (IDrawableBitmapImpl)source.Item;
var s = sourceRect.ToSKRect(); var s = sourceRect.ToSKRect();
@ -108,24 +110,26 @@ namespace Avalonia.Skia
Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity))
}) })
{ {
paint.FilterQuality = GetInterpolationMode(bitmapScalingMode); paint.FilterQuality = GetInterpolationMode(bitmapInterpolationMode);
drawableImage.Draw(this, s, d, paint); drawableImage.Draw(this, s, d, paint);
} }
} }
private static SKFilterQuality GetInterpolationMode(BitmapScalingMode scalingMode) private static SKFilterQuality GetInterpolationMode(BitmapInterpolationMode interpolationMode)
{ {
switch (scalingMode) switch (interpolationMode)
{ {
case BitmapScalingMode.LowQuality: case BitmapInterpolationMode.LowQuality:
return SKFilterQuality.Low; return SKFilterQuality.Low;
case BitmapScalingMode.MediumQuality: case BitmapInterpolationMode.MediumQuality:
return SKFilterQuality.Medium; return SKFilterQuality.Medium;
case BitmapScalingMode.HighQuality: case BitmapInterpolationMode.HighQuality:
return SKFilterQuality.High; return SKFilterQuality.High;
case BitmapInterpolationMode.Default:
return SKFilterQuality.None;
default: default:
throw new ArgumentOutOfRangeException(nameof(scalingMode), scalingMode, null); throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null);
} }
} }
@ -133,7 +137,7 @@ namespace Avalonia.Skia
public void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) public void DrawImage(IRef<IBitmapImpl> source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect)
{ {
PushOpacityMask(opacityMask, opacityMaskRect); PushOpacityMask(opacityMask, opacityMaskRect);
DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect, default(BitmapScalingMode)); DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect, BitmapInterpolationMode.Default);
PopOpacityMask(); PopOpacityMask();
} }
@ -378,7 +382,8 @@ namespace Avalonia.Skia
/// <param name="targetSize">Target size.</param> /// <param name="targetSize">Target size.</param>
/// <param name="tileBrush">Tile brush to use.</param> /// <param name="tileBrush">Tile brush to use.</param>
/// <param name="tileBrushImage">Tile brush image.</param> /// <param name="tileBrushImage">Tile brush image.</param>
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) /// <param name="interpolationMode">The bitmap interpolation mode.</param>
private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage, BitmapInterpolationMode interpolationMode)
{ {
var calc = new TileBrushCalculator(tileBrush, var calc = new TileBrushCalculator(tileBrush,
new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize);
@ -396,7 +401,7 @@ namespace Avalonia.Skia
context.Clear(Colors.Transparent); context.Clear(Colors.Transparent);
context.PushClip(calc.IntermediateClip); context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform; context.Transform = calc.IntermediateTransform;
context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect); context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, interpolationMode);
context.PopClip(); context.PopClip();
} }
@ -505,12 +510,12 @@ namespace Avalonia.Skia
} }
else else
{ {
tileBrushImage = (IDrawableBitmapImpl) (tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; tileBrushImage = (IDrawableBitmapImpl)(tileBrush as IImageBrush)?.Source?.PlatformImpl.Item;
} }
if (tileBrush != null && tileBrushImage != null) if (tileBrush != null && tileBrushImage != null)
{ {
ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage); ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage, tileBrush.BitmapInterpolationMode);
} }
else else
{ {

49
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -14,6 +14,8 @@ using SharpDX.Mathematics.Interop;
namespace Avalonia.Direct2D1.Media namespace Avalonia.Direct2D1.Media
{ {
using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode;
/// <summary> /// <summary>
/// Draws using Direct2D1. /// Draws using Direct2D1.
/// </summary> /// </summary>
@ -101,43 +103,34 @@ namespace Avalonia.Direct2D1.Media
/// <param name="opacity">The opacity to draw with.</param> /// <param name="opacity">The opacity to draw with.</param>
/// <param name="sourceRect">The rect in the image to draw.</param> /// <param name="sourceRect">The rect in the image to draw.</param>
/// <param name="destRect">The rect in the output to draw to.</param> /// <param name="destRect">The rect in the output to draw to.</param>
/// <param name="bitmapScalingMode"></param> /// <param name="bitmapInterpolationMode"></param>
public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode)
{ {
using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget))
{ {
if (_renderTarget is DeviceContext deviceContext) var interpolationMode = GetInterpolationMode(bitmapInterpolationMode);
{
deviceContext.DrawBitmap(d2d.Value, destRect.ToDirect2D(), (float)opacity, GetInterpolationMode(bitmapScalingMode), sourceRect.ToDirect2D(), null); _renderTarget.DrawBitmap(
} d2d.Value,
else destRect.ToSharpDX(),
{ (float)opacity,
var interpolationMode = bitmapScalingMode == BitmapScalingMode.LowQuality interpolationMode,
? BitmapInterpolationMode.NearestNeighbor sourceRect.ToSharpDX());
: BitmapInterpolationMode.Linear;
_renderTarget.DrawBitmap(
d2d.Value,
destRect.ToSharpDX(),
(float)opacity,
interpolationMode,
sourceRect.ToSharpDX());
}
} }
} }
private static InterpolationMode GetInterpolationMode(BitmapScalingMode scalingMode) private static SharpDX.Direct2D1.BitmapInterpolationMode GetInterpolationMode(BitmapInterpolationMode interpolationMode)
{ {
switch (scalingMode) switch (interpolationMode)
{ {
case BitmapScalingMode.LowQuality: case BitmapInterpolationMode.LowQuality:
return InterpolationMode.NearestNeighbor; return SharpDX.Direct2D1.BitmapInterpolationMode.NearestNeighbor;
case BitmapScalingMode.MediumQuality: case BitmapInterpolationMode.MediumQuality:
return InterpolationMode.Linear; case BitmapInterpolationMode.HighQuality:
case BitmapScalingMode.HighQuality: case BitmapInterpolationMode.Default:
return InterpolationMode.HighQualityCubic; return SharpDX.Direct2D1.BitmapInterpolationMode.Linear;
default: default:
throw new ArgumentOutOfRangeException(nameof(scalingMode), scalingMode, null); throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null);
} }
} }

9
src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs

@ -1,7 +1,6 @@
// Copyright (c) The Avalonia Project. All rights reserved. // Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information. // Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Rendering.Utilities; using Avalonia.Rendering.Utilities;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -11,7 +10,9 @@ namespace Avalonia.Direct2D1.Media
{ {
public sealed class ImageBrushImpl : BrushImpl public sealed class ImageBrushImpl : BrushImpl
{ {
OptionalDispose<Bitmap> _bitmap; private readonly OptionalDispose<Bitmap> _bitmap;
private readonly Visuals.Media.Imaging.BitmapInterpolationMode _bitmapInterpolationMode;
public ImageBrushImpl( public ImageBrushImpl(
ITileBrush brush, ITileBrush brush,
@ -41,6 +42,8 @@ namespace Avalonia.Direct2D1.Media
GetBrushProperties(brush, calc.DestinationRect)); GetBrushProperties(brush, calc.DestinationRect));
} }
} }
_bitmapInterpolationMode = brush.BitmapInterpolationMode;
} }
public override void Dispose() public override void Dispose()
@ -102,7 +105,7 @@ namespace Avalonia.Direct2D1.Media
context.PushClip(calc.IntermediateClip); context.PushClip(calc.IntermediateClip);
context.Transform = calc.IntermediateTransform; context.Transform = calc.IntermediateTransform;
context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect); context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode);
context.PopClip(); context.PopClip();
} }

2
tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs

@ -340,7 +340,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering
var context = Mock.Get(target.RenderTarget.CreateDrawingContext(null)); var context = Mock.Get(target.RenderTarget.CreateDrawingContext(null));
var borderLayer = target.Layers[border].Bitmap; var borderLayer = target.Layers[border].Bitmap;
context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny<Rect>(), It.IsAny<Rect>(), default(BitmapScalingMode))); context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny<Rect>(), It.IsAny<Rect>(), BitmapInterpolationMode.Default));
} }
private DeferredRenderer CreateTargetAndRunFrame( private DeferredRenderer CreateTargetAndRunFrame(

5
tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs

@ -1,5 +1,4 @@
using System; using Avalonia.Media;
using Avalonia.Media;
using Avalonia.Platform; using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph; using Avalonia.Rendering.SceneGraph;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -53,7 +52,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph
1, 1,
new Rect(1, 1, 1, 1), new Rect(1, 1, 1, 1),
new Rect(1, 1, 1, 1), new Rect(1, 1, 1, 1),
BitmapScalingMode.LowQuality); BitmapInterpolationMode.Default);
Assert.Equal(2, bitmap.RefCount); Assert.Equal(2, bitmap.RefCount);

Loading…
Cancel
Save