diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index f6f11aa9ad..f146e3571c 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -1,12 +1,11 @@ // 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 System; using Avalonia.Media; using Avalonia.Media.Imaging; namespace Avalonia.Controls -{ +{ /// /// Displays a image. /// @@ -68,7 +67,9 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - context.DrawImage(source, 1, sourceRect, destRect); + var interpolationMode = RenderOptions.GetBitmapInterpolationMode(this); + + context.DrawImage(source, 1, sourceRect, destRect, interpolationMode); } } @@ -100,4 +101,4 @@ namespace Avalonia.Controls } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 962f2c1ba8..60a7a2e518 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -2,9 +2,10 @@ using System; using System.Collections.Generic; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media -{ +{ public sealed class DrawingContext : IDisposable { private int _currentLevel; @@ -68,11 +69,12 @@ namespace Avalonia.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default) { Contract.Requires(source != null); - PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect); + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapInterpolationMode); } /// @@ -309,4 +311,4 @@ namespace Avalonia.Media return pen?.Brush != null && pen.Thickness > 0; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/ITileBrush.cs b/src/Avalonia.Visuals/Media/ITileBrush.cs index 8e2349f506..5cffe02193 100644 --- a/src/Avalonia.Visuals/Media/ITileBrush.cs +++ b/src/Avalonia.Visuals/Media/ITileBrush.cs @@ -1,5 +1,10 @@ -namespace Avalonia.Media -{ +// 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 +{ /// /// A brush which displays a repeating image. /// @@ -35,5 +40,13 @@ /// Gets the brush's tile mode. /// TileMode TileMode { get; } + + /// + /// Gets the bitmap interpolation mode. + /// + /// + /// The bitmap interpolation mode. + /// + BitmapInterpolationMode BitmapInterpolationMode { get; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs new file mode 100644 index 0000000000..7e6d330618 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs @@ -0,0 +1,31 @@ +// 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. + +namespace Avalonia.Visuals.Media.Imaging +{ + /// + /// Controls the performance and quality of bitmap scaling. + /// + public enum BitmapInterpolationMode + { + /// + /// Uses the default behavior of the underling render backend. + /// + Default, + + /// + /// The best performance but worst image quality. + /// + LowQuality, + + /// + /// Good performance and decent image quality. + /// + MediumQuality, + + /// + /// Highest quality but worst performance. + /// + HighQuality + } +} diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs index 678f99c20d..15da8f8b43 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableImageBrush.cs +++ b/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 { @@ -21,6 +21,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// The bitmap interpolation mode. public ImmutableImageBrush( IBitmap source, AlignmentX alignmentX = AlignmentX.Center, @@ -29,7 +30,8 @@ namespace Avalonia.Media.Immutable double opacity = 1, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, - TileMode tileMode = TileMode.None) + TileMode tileMode = TileMode.None, + BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) : base( alignmentX, alignmentY, @@ -37,7 +39,8 @@ namespace Avalonia.Media.Immutable opacity, sourceRect ?? RelativeRect.Fill, stretch, - tileMode) + tileMode, + bitmapInterpolationMode) { Source = source; } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index 37c391040f..c3dd159d04 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/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 { @@ -19,6 +22,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// The bitmap interpolation mode. protected ImmutableTileBrush( AlignmentX alignmentX, AlignmentY alignmentY, @@ -26,7 +30,8 @@ namespace Avalonia.Media.Immutable double opacity, RelativeRect sourceRect, Stretch stretch, - TileMode tileMode) + TileMode tileMode, + BitmapInterpolationMode bitmapInterpolationMode) { AlignmentX = alignmentX; AlignmentY = alignmentY; @@ -35,6 +40,7 @@ namespace Avalonia.Media.Immutable SourceRect = sourceRect; Stretch = stretch; TileMode = tileMode; + BitmapInterpolationMode = bitmapInterpolationMode; } /// @@ -49,7 +55,8 @@ namespace Avalonia.Media.Immutable source.Opacity, source.SourceRect, source.Stretch, - source.TileMode) + source.TileMode, + source.BitmapInterpolationMode) { } @@ -73,5 +80,8 @@ namespace Avalonia.Media.Immutable /// public TileMode TileMode { get; } + + /// + public BitmapInterpolationMode BitmapInterpolationMode { get; } } } diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs index b07d98867c..f1f61a6e65 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableVisualBrush.cs +++ b/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; namespace Avalonia.Media.Immutable @@ -21,6 +24,7 @@ namespace Avalonia.Media.Immutable /// How the source rectangle will be stretched to fill the destination rect. /// /// The tile mode. + /// Controls the quality of interpolation. public ImmutableVisualBrush( IVisual visual, AlignmentX alignmentX = AlignmentX.Center, @@ -29,7 +33,8 @@ namespace Avalonia.Media.Immutable double opacity = 1, RelativeRect? sourceRect = null, Stretch stretch = Stretch.Uniform, - TileMode tileMode = TileMode.None) + TileMode tileMode = TileMode.None, + BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default) : base( alignmentX, alignmentY, @@ -37,7 +42,8 @@ namespace Avalonia.Media.Immutable opacity, sourceRect ?? RelativeRect.Fill, stretch, - tileMode) + tileMode, + bitmapInterpolationMode) { Visual = visual; } diff --git a/src/Avalonia.Visuals/Media/RenderOptions.cs b/src/Avalonia.Visuals/Media/RenderOptions.cs new file mode 100644 index 0000000000..180863f9e8 --- /dev/null +++ b/src/Avalonia.Visuals/Media/RenderOptions.cs @@ -0,0 +1,39 @@ +// 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 +{ + public class RenderOptions + { + /// + /// Defines the property. + /// + public static readonly StyledProperty BitmapInterpolationModeProperty = + AvaloniaProperty.RegisterAttached( + "BitmapInterpolationMode", + BitmapInterpolationMode.MediumQuality, + inherits: true); + + /// + /// Gets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The control's left coordinate. + public static BitmapInterpolationMode GetBitmapInterpolationMode(AvaloniaObject element) + { + return element.GetValue(BitmapInterpolationModeProperty); + } + + /// + /// Sets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The left value. + public static void SetBitmapInterpolationMode(AvaloniaObject element, BitmapInterpolationMode value) + { + element.SetValue(BitmapInterpolationModeProperty, value); + } + } +} diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 3a7f9d9920..2033754137 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -1,6 +1,8 @@ // 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 { /// @@ -75,6 +77,11 @@ namespace Avalonia.Media public static readonly StyledProperty TileModeProperty = AvaloniaProperty.Register(nameof(TileMode)); + static TileBrush() + { + RenderOptions.BitmapInterpolationModeProperty.OverrideDefaultValue(BitmapInterpolationMode.Default); + } + /// /// Gets or sets the horizontal alignment of a tile in the destination. /// @@ -129,5 +136,17 @@ namespace Avalonia.Media get { return (TileMode)GetValue(TileModeProperty); } set { SetValue(TileModeProperty, value); } } + + /// + /// Gets or sets the bitmap interpolation mode. + /// + /// + /// The bitmap interpolation mode. + /// + public BitmapInterpolationMode BitmapInterpolationMode + { + get { return RenderOptions.GetBitmapInterpolationMode(this); } + set { RenderOptions.SetBitmapInterpolationMode(this, value); } + } } } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 04bbe713f2..b11d9f52ab 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Media; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Platform { @@ -30,7 +31,8 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect); + /// The bitmap interpolation mode. + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default); /// /// Draws a bitmap image. diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index f3dbfbd8fb..42ecde6a6d 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -7,6 +7,7 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Utilities; using Avalonia.VisualTree; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { @@ -114,13 +115,13 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { var next = NextDrawAs(); - if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect)) + if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode)) { - Add(new ImageNode(Transform, source, opacity, sourceRect, destRect)); + Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapInterpolationMode)); } else { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 06fdb3f86c..9e8fca5f84 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -4,6 +4,7 @@ using System; using Avalonia.Platform; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { @@ -20,7 +21,8 @@ namespace Avalonia.Rendering.SceneGraph /// The draw opacity. /// The source rect. /// The destination rect. - public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) : base(destRect, transform, null) { Transform = transform; @@ -28,7 +30,8 @@ namespace Avalonia.Rendering.SceneGraph Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; - } + BitmapInterpolationMode = bitmapInterpolationMode; + } /// /// Gets the transform with which the node will be drawn. @@ -55,6 +58,14 @@ namespace Avalonia.Rendering.SceneGraph /// public Rect DestRect { get; } + /// + /// Gets the bitmap interpolation mode. + /// + /// + /// The scaling mode. + /// + public BitmapInterpolationMode BitmapInterpolationMode { get; } + /// /// Determines if this draw operation equals another. /// @@ -63,18 +74,20 @@ namespace Avalonia.Rendering.SceneGraph /// The opacity of the other draw operation. /// The source rect of the other draw operation. /// The dest rect of the other draw operation. + /// The bitmap interpolation mode. /// True if the draw operations are the same, otherwise false. /// /// The properties of the other draw operation are passed in as arguments to prevent /// allocation of a not-yet-constructed draw operation object. /// - public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect) + public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { return transform == Transform && Equals(source.Item, Source.Item) && opacity == Opacity && sourceRect == SourceRect && - destRect == DestRect; + destRect == DestRect && + bitmapInterpolationMode == BitmapInterpolationMode; } /// @@ -83,7 +96,7 @@ namespace Avalonia.Rendering.SceneGraph // TODO: Probably need to introduce some kind of locking mechanism in the case of // WriteableBitmap. context.Transform = Transform; - context.DrawImage(Source, Opacity, SourceRect, DestRect); + context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode); } /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index d2c4bd0aa1..685987ae80 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -10,6 +10,7 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia @@ -95,24 +96,46 @@ namespace Avalonia.Skia } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { - var drawableImage = (IDrawableBitmapImpl) source.Item; + var drawableImage = (IDrawableBitmapImpl)source.Item; var s = sourceRect.ToSKRect(); var d = destRect.ToSKRect(); using (var paint = - new SKPaint {Color = new SKColor(255, 255, 255, (byte) (255 * opacity * _currentOpacity))}) + new SKPaint + { + Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) + }) { + paint.FilterQuality = GetInterpolationMode(bitmapInterpolationMode); + drawableImage.Draw(this, s, d, paint); } } + private static SKFilterQuality GetInterpolationMode(BitmapInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + case BitmapInterpolationMode.LowQuality: + return SKFilterQuality.Low; + case BitmapInterpolationMode.MediumQuality: + return SKFilterQuality.Medium; + case BitmapInterpolationMode.HighQuality: + return SKFilterQuality.High; + case BitmapInterpolationMode.Default: + return SKFilterQuality.None; + default: + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); + } + } + /// public void DrawImage(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { PushOpacityMask(opacityMask, opacityMaskRect); - DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect); + DrawImage(source, 1, new Rect(0, 0, source.Item.PixelWidth, source.Item.PixelHeight), destRect, BitmapInterpolationMode.Default); PopOpacityMask(); } @@ -357,6 +380,7 @@ namespace Avalonia.Skia /// Target size. /// Tile brush to use. /// Tile brush image. + /// The bitmap interpolation mode. private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) { var calc = new TileBrushCalculator(tileBrush, @@ -375,7 +399,7 @@ namespace Avalonia.Skia context.Clear(Colors.Transparent); context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect); + context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, tileBrush.BitmapInterpolationMode); context.PopClip(); } @@ -484,7 +508,7 @@ namespace Avalonia.Skia } else { - tileBrushImage = (IDrawableBitmapImpl) (tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; + tileBrushImage = (IDrawableBitmapImpl)(tileBrush as IImageBrush)?.Source?.PlatformImpl.Item; } if (tileBrush != null && tileBrushImage != null) @@ -690,4 +714,4 @@ namespace Avalonia.Skia } } } -} \ No newline at end of file +} diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 479db51be4..ae5dd3ae13 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -10,13 +10,14 @@ using Avalonia.Utilities; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; +using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode; namespace Avalonia.Direct2D1.Media { /// /// Draws using Direct2D1. /// - public class DrawingContextImpl : IDrawingContextImpl, IDisposable + public class DrawingContextImpl : IDrawingContextImpl { private readonly IVisualBrushRenderer _visualBrushRenderer; private readonly ILayerFactory _layerFactory; @@ -100,19 +101,37 @@ namespace Avalonia.Direct2D1.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect) + /// The bitmap interpolation mode. + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { + var interpolationMode = GetInterpolationMode(bitmapInterpolationMode); + _renderTarget.DrawBitmap( d2d.Value, destRect.ToSharpDX(), (float)opacity, - BitmapInterpolationMode.Linear, + interpolationMode, sourceRect.ToSharpDX()); } } + private static SharpDX.Direct2D1.BitmapInterpolationMode GetInterpolationMode(BitmapInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + case BitmapInterpolationMode.LowQuality: + return SharpDX.Direct2D1.BitmapInterpolationMode.NearestNeighbor; + case BitmapInterpolationMode.MediumQuality: + case BitmapInterpolationMode.HighQuality: + case BitmapInterpolationMode.Default: + return SharpDX.Direct2D1.BitmapInterpolationMode.Linear; + default: + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); + } + } + /// /// Draws a bitmap image. /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs index 75b397edd6..3fc8760a9e 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/ImageBrushImpl.cs @@ -1,7 +1,6 @@ // 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 System; using Avalonia.Media; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; @@ -11,7 +10,9 @@ namespace Avalonia.Direct2D1.Media { public sealed class ImageBrushImpl : BrushImpl { - OptionalDispose _bitmap; + private readonly OptionalDispose _bitmap; + + private readonly Visuals.Media.Imaging.BitmapInterpolationMode _bitmapInterpolationMode; public ImageBrushImpl( ITileBrush brush, @@ -41,6 +42,8 @@ namespace Avalonia.Direct2D1.Media GetBrushProperties(brush, calc.DestinationRect)); } } + + _bitmapInterpolationMode = brush.BitmapInterpolationMode; } public override void Dispose() @@ -102,7 +105,7 @@ namespace Avalonia.Direct2D1.Media context.PushClip(calc.IntermediateClip); context.Transform = calc.IntermediateTransform; - context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect); + context.DrawImage(RefCountable.CreateUnownedNotClonable(bitmap), 1, rect, rect, _bitmapInterpolationMode); context.PopClip(); } diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 7821f60a51..2350a31d5c 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reactive.Subjects; + using Avalonia.Controls; using Avalonia.Data; using Avalonia.Media; @@ -10,8 +11,11 @@ using Avalonia.Rendering; using Avalonia.Rendering.SceneGraph; using Avalonia.Threading; using Avalonia.UnitTests; +using Avalonia.Visuals.Media.Imaging; using Avalonia.VisualTree; + using Moq; + using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering @@ -336,7 +340,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering var context = Mock.Get(target.RenderTarget.CreateDrawingContext(null)); var borderLayer = target.Layers[border].Bitmap; - context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny(), It.IsAny())); + context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny(), It.IsAny(), BitmapInterpolationMode.Default)); } private DeferredRenderer CreateTargetAndRunFrame( diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs index 8c905dab2f..2060cc7170 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs @@ -1,13 +1,13 @@ -using System; -using Avalonia.Media; +using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering.SceneGraph; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using Moq; using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph -{ +{ public class DrawOperationTests { [Fact] @@ -46,7 +46,13 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph public void Image_Node_Releases_Reference_To_Bitmap_On_Dispose() { var bitmap = RefCountable.Create(Mock.Of()); - var imageNode = new ImageNode(Matrix.Identity, bitmap, 1, new Rect(1,1,1,1), new Rect(1,1,1,1)); + var imageNode = new ImageNode( + Matrix.Identity, + bitmap, + 1, + new Rect(1, 1, 1, 1), + new Rect(1, 1, 1, 1), + BitmapInterpolationMode.Default); Assert.Equal(2, bitmap.RefCount);