From 3154137c2a3eb859a2bed48ee8b07625925dd999 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 16 Jul 2018 20:00:55 +0200 Subject: [PATCH 01/12] Initial --- .../Media/Imaging/BitmapScalingMode.cs | 12 ++++++ .../Platform/IDrawingContextImpl.cs | 5 ++- .../SceneGraph/DeferredDrawingContextImpl.cs | 8 ++-- .../Rendering/SceneGraph/ImageNode.cs | 24 +++++++++-- .../Media/DrawingContextImpl.cs | 43 ++++++++++++++++--- .../Media/Imaging/BitmapImpl.cs | 10 +++-- 6 files changed, 84 insertions(+), 18 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs new file mode 100644 index 0000000000..36d239c9d9 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs @@ -0,0 +1,12 @@ +// 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 +{ + public enum BitmapScalingMode + { + LowQuality, + MediumQuality, + HighQuality + } +} diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 04bbe713f2..f511daf9b2 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -7,6 +7,8 @@ using Avalonia.Utilities; namespace Avalonia.Platform { + using Avalonia.Visuals.Media.Imaging; + /// /// Defines the interface through which drawing occurs. /// @@ -30,7 +32,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); + /// Controls + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality); /// /// Draws a bitmap image. diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index f3dbfbd8fb..7172696e81 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -10,6 +10,8 @@ using Avalonia.VisualTree; namespace Avalonia.Rendering.SceneGraph { + using Avalonia.Visuals.Media.Imaging; + /// /// A drawing context which builds a scene graph. /// @@ -114,13 +116,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, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality) { 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, scalingMode)) { - Add(new ImageNode(Transform, source, opacity, sourceRect, destRect)); + Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, scalingMode)); } else { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 06fdb3f86c..96a8731715 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -7,6 +7,8 @@ using Avalonia.Utilities; namespace Avalonia.Rendering.SceneGraph { + using Avalonia.Visuals.Media.Imaging; + /// /// A node in the scene graph which represents an image draw. /// @@ -20,7 +22,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) + /// + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode) : base(destRect, transform, null) { Transform = transform; @@ -28,8 +31,11 @@ namespace Avalonia.Rendering.SceneGraph Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; + ScalingMode = scalingMode; } + + /// /// Gets the transform with which the node will be drawn. /// @@ -55,6 +61,14 @@ namespace Avalonia.Rendering.SceneGraph /// public Rect DestRect { get; } + /// + /// Gets or sets the scaling mode. + /// + /// + /// The scaling mode. + /// + public BitmapScalingMode ScalingMode { get; } + /// /// Determines if this draw operation equals another. /// @@ -63,18 +77,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. + /// /// 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, BitmapScalingMode scalingMode) { return transform == Transform && Equals(source.Item, Source.Item) && opacity == Opacity && sourceRect == SourceRect && - destRect == DestRect; + destRect == DestRect && + scalingMode == ScalingMode; } /// @@ -83,7 +99,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, ScalingMode); } /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index bdbbdab2b9..27115e164a 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -13,6 +13,8 @@ using SharpDX.Mathematics.Interop; namespace Avalonia.Direct2D1.Media { + using Avalonia.Visuals.Media.Imaging; + /// /// Draws using Direct2D1. /// @@ -100,16 +102,43 @@ 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) + /// + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode) { using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { - _renderTarget.DrawBitmap( - d2d.Value, - destRect.ToSharpDX(), - (float)opacity, - BitmapInterpolationMode.Linear, - sourceRect.ToSharpDX()); + if (_renderTarget is DeviceContext deviceContext) + { + deviceContext.DrawBitmap(d2d.Value, destRect.ToDirect2D(), (float)opacity, GetInterpolationMode(scalingMode), sourceRect.ToDirect2D(), null); + } + else + { + var interpolationMode = scalingMode == BitmapScalingMode.LowQuality + ? BitmapInterpolationMode.NearestNeighbor + : BitmapInterpolationMode.Linear; + + _renderTarget.DrawBitmap( + d2d.Value, + destRect.ToSharpDX(), + (float)opacity, + interpolationMode, + sourceRect.ToSharpDX()); + } + } + } + + private static InterpolationMode GetInterpolationMode(BitmapScalingMode scalingMode) + { + switch (scalingMode) + { + case BitmapScalingMode.LowQuality: + return InterpolationMode.NearestNeighbor; + case BitmapScalingMode.MediumQuality: + return InterpolationMode.Linear; + case BitmapScalingMode.HighQuality: + return InterpolationMode.HighQualityCubic; + default: + throw new ArgumentOutOfRangeException(nameof(scalingMode), scalingMode, null); } } diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index d58f023391..c792334ec1 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -1,11 +1,15 @@ -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 System; using System.IO; using Avalonia.Platform; using SharpDX.WIC; -using D2DBitmap = SharpDX.Direct2D1.Bitmap; namespace Avalonia.Direct2D1.Media { + using SharpDX.Direct2D1; + public abstract class BitmapImpl : IBitmapImpl, IDisposable { public BitmapImpl(ImagingFactory imagingFactory) @@ -17,7 +21,7 @@ namespace Avalonia.Direct2D1.Media public abstract int PixelWidth { get; } public abstract int PixelHeight { get; } - public abstract OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); + public abstract OptionalDispose GetDirect2DBitmap(RenderTarget target); public void Save(string fileName) { From b108ffcab4e2123a56cb39dd3eb6a6da1849c879 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 18 Jul 2018 19:48:31 +0200 Subject: [PATCH 02/12] Initial implementation of BitmapScaleMode --- .gitignore | 1 + Avalonia.sln | 42 +++++++++++++++++++ src/Avalonia.Controls/Image.cs | 19 ++++++++- src/Avalonia.Visuals/Media/DrawingContext.cs | 9 ++-- .../Platform/IDrawingContextImpl.cs | 2 +- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 32 +++++++++++--- 6 files changed, 94 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 583a2b8a2b..f0cbd79cbc 100644 --- a/.gitignore +++ b/.gitignore @@ -182,3 +182,4 @@ project.lock.json ## BenchmarkDotNet ################## BenchmarkDotNet.Artifacts/ +/src/ImageInterpRepro diff --git a/Avalonia.sln b/Avalonia.sln index d1c5026e58..7938b95ac5 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -187,6 +187,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer.HostApp.N EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageInterpRepro", "src\ImageInterpRepro\ImageInterpRepro.csproj", "{54A1062E-126E-4813-98A7-8DB9D949CD93}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 @@ -2514,6 +2516,46 @@ Global {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|NetCoreOnly.Build.0 = Release|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|x86.ActiveCfg = Release|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|x86.Build.0 = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|NetCoreOnly.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|NetCoreOnly.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|x86.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|Any CPU.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhone.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhone.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|NetCoreOnly.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|NetCoreOnly.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|x86.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|x86.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|Any CPU.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhone.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|NetCoreOnly.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|NetCoreOnly.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|x86.ActiveCfg = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|x86.Build.0 = Debug|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|Any CPU.ActiveCfg = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|Any CPU.Build.0 = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhone.ActiveCfg = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhone.Build.0 = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|NetCoreOnly.ActiveCfg = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|NetCoreOnly.Build.0 = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|x86.ActiveCfg = Release|Any CPU + {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index f6f11aa9ad..a9f24f5ce4 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -7,6 +7,8 @@ using Avalonia.Media.Imaging; namespace Avalonia.Controls { + using Avalonia.Visuals.Media.Imaging; + /// /// Displays a image. /// @@ -24,10 +26,17 @@ namespace Avalonia.Controls public static readonly StyledProperty StretchProperty = AvaloniaProperty.Register(nameof(Stretch), Stretch.Uniform); + /// + /// Defines the property. + /// + public static readonly StyledProperty ScalingModeProperty = + AvaloniaProperty.Register(nameof(BitmapScalingMode)); + static Image() { AffectsRender(SourceProperty); AffectsRender(StretchProperty); + AffectsRender(ScalingModeProperty); } /// @@ -48,6 +57,12 @@ namespace Avalonia.Controls set { SetValue(StretchProperty, value); } } + public BitmapScalingMode ScalingMode + { + get { return (BitmapScalingMode)GetValue(ScalingModeProperty); } + set { SetValue(ScalingModeProperty, value); } + } + /// /// Renders the control. /// @@ -68,7 +83,7 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - context.DrawImage(source, 1, sourceRect, destRect); + context.DrawImage(source, 1, sourceRect, destRect, ScalingMode); } } @@ -100,4 +115,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..9cb8712f5b 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -5,6 +5,8 @@ using Avalonia.Platform; namespace Avalonia.Media { + using Avalonia.Visuals.Media.Imaging; + public sealed class DrawingContext : IDisposable { private int _currentLevel; @@ -68,11 +70,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) + /// + public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = default) { Contract.Requires(source != null); - PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect); + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, scalingMode); } /// @@ -309,4 +312,4 @@ namespace Avalonia.Media return pen?.Brush != null && pen.Thickness > 0; } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index f511daf9b2..fbd742f6c3 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -33,7 +33,7 @@ namespace Avalonia.Platform /// The rect in the image to draw. /// The rect in the output to draw to. /// Controls - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality); + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = default); /// /// Draws a bitmap image. diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index b7ce6eedc4..5878038a81 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -14,6 +14,8 @@ using SkiaSharp; namespace Avalonia.Skia { + using Avalonia.Visuals.Media.Imaging; + /// /// Skia based drawing context. /// @@ -95,24 +97,44 @@ 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, BitmapScalingMode scalingMode) { - 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(scalingMode); + drawableImage.Draw(this, s, d, paint); } } + private static SKFilterQuality GetInterpolationMode(BitmapScalingMode scalingMode) + { + switch (scalingMode) + { + case BitmapScalingMode.LowQuality: + return SKFilterQuality.Low; + case BitmapScalingMode.MediumQuality: + return SKFilterQuality.Medium; + case BitmapScalingMode.HighQuality: + return SKFilterQuality.High; + default: + throw new ArgumentOutOfRangeException(nameof(scalingMode), scalingMode, 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, default(BitmapScalingMode)); PopOpacityMask(); } @@ -686,4 +708,4 @@ namespace Avalonia.Skia } } } -} \ No newline at end of file +} From 881069fd5d932a10b02197be18e5ae9a4a92f623 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 19 Jul 2018 07:05:21 +0200 Subject: [PATCH 03/12] Introduce RenderOptions --- .gitignore | 3 +- Avalonia.sln | 42 -------------------------- src/Avalonia.Controls/Image.cs | 17 ++--------- src/Avalonia.Controls/RenderOptions.cs | 36 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 58 deletions(-) create mode 100644 src/Avalonia.Controls/RenderOptions.cs diff --git a/.gitignore b/.gitignore index f0cbd79cbc..dd814ba26f 100644 --- a/.gitignore +++ b/.gitignore @@ -181,5 +181,4 @@ project.lock.json ################## ## BenchmarkDotNet ################## -BenchmarkDotNet.Artifacts/ -/src/ImageInterpRepro +BenchmarkDotNet.Artifacts/ \ No newline at end of file diff --git a/Avalonia.sln b/Avalonia.sln index 7938b95ac5..d1c5026e58 100644 --- a/Avalonia.sln +++ b/Avalonia.sln @@ -187,8 +187,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.Designer.HostApp.N EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Skia.UnitTests", "tests\Avalonia.Skia.UnitTests\Avalonia.Skia.UnitTests.csproj", "{E1240B49-7B4B-4371-A00E-068778C5CF0B}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageInterpRepro", "src\ImageInterpRepro\ImageInterpRepro.csproj", "{54A1062E-126E-4813-98A7-8DB9D949CD93}" -EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13 @@ -2516,46 +2514,6 @@ Global {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|NetCoreOnly.Build.0 = Release|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|x86.ActiveCfg = Release|Any CPU {E1240B49-7B4B-4371-A00E-068778C5CF0B}.Release|x86.Build.0 = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|NetCoreOnly.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|NetCoreOnly.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|x86.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Ad-Hoc|x86.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|Any CPU.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhone.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhone.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|NetCoreOnly.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|NetCoreOnly.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|x86.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.AppStore|x86.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|Any CPU.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhone.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|NetCoreOnly.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|NetCoreOnly.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|x86.ActiveCfg = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Debug|x86.Build.0 = Debug|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|Any CPU.ActiveCfg = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|Any CPU.Build.0 = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhone.ActiveCfg = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhone.Build.0 = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|NetCoreOnly.ActiveCfg = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|NetCoreOnly.Build.0 = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|x86.ActiveCfg = Release|Any CPU - {54A1062E-126E-4813-98A7-8DB9D949CD93}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index a9f24f5ce4..beddc75917 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -26,17 +26,10 @@ namespace Avalonia.Controls public static readonly StyledProperty StretchProperty = AvaloniaProperty.Register(nameof(Stretch), Stretch.Uniform); - /// - /// Defines the property. - /// - public static readonly StyledProperty ScalingModeProperty = - AvaloniaProperty.Register(nameof(BitmapScalingMode)); - static Image() { AffectsRender(SourceProperty); AffectsRender(StretchProperty); - AffectsRender(ScalingModeProperty); } /// @@ -57,12 +50,6 @@ namespace Avalonia.Controls set { SetValue(StretchProperty, value); } } - public BitmapScalingMode ScalingMode - { - get { return (BitmapScalingMode)GetValue(ScalingModeProperty); } - set { SetValue(ScalingModeProperty, value); } - } - /// /// Renders the control. /// @@ -83,7 +70,9 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - context.DrawImage(source, 1, sourceRect, destRect, ScalingMode); + var scalingMode = RenderOptions.GetBitmapScalingMode(this); + + context.DrawImage(source, 1, sourceRect, destRect, scalingMode); } } diff --git a/src/Avalonia.Controls/RenderOptions.cs b/src/Avalonia.Controls/RenderOptions.cs new file mode 100644 index 0000000000..dff1d940d0 --- /dev/null +++ b/src/Avalonia.Controls/RenderOptions.cs @@ -0,0 +1,36 @@ +namespace Avalonia.Controls +{ + using Avalonia.Visuals.Media.Imaging; + + public class RenderOptions + { + /// + /// Defines the property. + /// + public static readonly StyledProperty BitmapScalingModeProperty = + AvaloniaProperty.RegisterAttached( + "BitmapScalingMode", + BitmapScalingMode.LowQuality, + inherits: true); + + /// + /// Gets the value of the BitmapScalingMode attached property for a control. + /// + /// The control. + /// The control's left coordinate. + public static BitmapScalingMode GetBitmapScalingMode(AvaloniaObject element) + { + return element.GetValue(BitmapScalingModeProperty); + } + + /// + /// Sets the value of the BitmapScalingMode attached property for a control. + /// + /// The control. + /// The left value. + public static void SetBitmapScalingMode(AvaloniaObject element, double value) + { + element.SetValue(BitmapScalingModeProperty, value); + } + } +} From 4d525aac6cded30a6b97a28e36584f858a8defc1 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 19 Jul 2018 09:50:14 +0200 Subject: [PATCH 04/12] Code style --- src/Avalonia.Controls/Remote/RemoteWidget.cs | 4 +++- src/Avalonia.Controls/RenderOptions.cs | 10 +++++---- src/Avalonia.Visuals/Media/DrawingContext.cs | 5 ++--- .../Media/Imaging/BitmapScalingMode.cs | 18 +++++++++++++-- .../Platform/IDrawingContextImpl.cs | 4 ++-- .../SceneGraph/DeferredDrawingContextImpl.cs | 6 ++--- .../Rendering/SceneGraph/ImageNode.cs | 22 +++++++++---------- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 4 ++-- .../Media/DrawingContextImpl.cs | 8 +++---- .../Rendering/DeferredRendererTests.cs | 4 +++- .../SceneGraph/DrawOperationTests.cs | 10 ++++++++- 11 files changed, 60 insertions(+), 35 deletions(-) diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs index ea8c3ebe52..594208b51c 100644 --- a/src/Avalonia.Controls/Remote/RemoteWidget.cs +++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs @@ -10,6 +10,8 @@ using PixelFormat = Avalonia.Platform.PixelFormat; namespace Avalonia.Controls.Remote { + using Avalonia.Visuals.Media.Imaging; + public class RemoteWidget : Control { private readonly IAvaloniaRemoteTransportConnection _connection; @@ -76,4 +78,4 @@ namespace Avalonia.Controls.Remote base.Render(context); } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Controls/RenderOptions.cs b/src/Avalonia.Controls/RenderOptions.cs index dff1d940d0..26f7ed260b 100644 --- a/src/Avalonia.Controls/RenderOptions.cs +++ b/src/Avalonia.Controls/RenderOptions.cs @@ -1,7 +1,10 @@ -namespace Avalonia.Controls -{ - using Avalonia.Visuals.Media.Imaging; +// 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 { /// @@ -10,7 +13,6 @@ public static readonly StyledProperty BitmapScalingModeProperty = AvaloniaProperty.RegisterAttached( "BitmapScalingMode", - BitmapScalingMode.LowQuality, inherits: true); /// diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 9cb8712f5b..85e165be36 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -2,11 +2,10 @@ using System; using System.Collections.Generic; using Avalonia.Media.Imaging; using Avalonia.Platform; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Media -{ - using Avalonia.Visuals.Media.Imaging; - +{ public sealed class DrawingContext : IDisposable { private int _currentLevel; diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs index 36d239c9d9..32b98c92a3 100644 --- a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs @@ -3,10 +3,24 @@ namespace Avalonia.Visuals.Media.Imaging { + /// + /// Controls the performance and quality of bitmap scaling. + /// public enum BitmapScalingMode { - LowQuality, + /// + /// Highest quality but worst performance. + /// + HighQuality, + + /// + /// Good performance an decent image quality. + /// MediumQuality, - HighQuality + + /// + /// The best performance but worst image quality. + /// + LowQuality } } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index fbd742f6c3..7f0b2a9904 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -32,8 +32,8 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - /// Controls - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = default); + /// Controls + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode = default); /// /// Draws a bitmap image. diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index 7172696e81..ac69687e60 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -116,13 +116,13 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) { var next = NextDrawAs(); - if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, scalingMode)) + if (next == null || !next.Item.Equals(Transform, source, opacity, sourceRect, destRect, bitmapScalingMode)) { - Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, scalingMode)); + Add(new ImageNode(Transform, source, opacity, sourceRect, destRect, bitmapScalingMode)); } else { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 96a8731715..e896d9a015 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -22,8 +22,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, BitmapScalingMode scalingMode) + /// The bitmap scaling mode. + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) : base(destRect, transform, null) { Transform = transform; @@ -31,10 +31,8 @@ namespace Avalonia.Rendering.SceneGraph Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; - ScalingMode = scalingMode; - } - - + BitmapScalingMode = bitmapScalingMode; + } /// /// Gets the transform with which the node will be drawn. @@ -62,12 +60,12 @@ namespace Avalonia.Rendering.SceneGraph public Rect DestRect { get; } /// - /// Gets or sets the scaling mode. + /// Gets the bitmap scaling mode. /// /// /// The scaling mode. /// - public BitmapScalingMode ScalingMode { get; } + public BitmapScalingMode BitmapScalingMode { get; } /// /// Determines if this draw operation equals another. @@ -77,20 +75,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. - /// + /// /// 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, BitmapScalingMode scalingMode) + public bool Equals(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) { return transform == Transform && Equals(source.Item, Source.Item) && opacity == Opacity && sourceRect == SourceRect && destRect == DestRect && - scalingMode == ScalingMode; + bitmapScalingMode == BitmapScalingMode; } /// @@ -99,7 +97,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, ScalingMode); + context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapScalingMode); } /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 5878038a81..d119998f10 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -97,7 +97,7 @@ namespace Avalonia.Skia } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) { var drawableImage = (IDrawableBitmapImpl)source.Item; var s = sourceRect.ToSKRect(); @@ -109,7 +109,7 @@ namespace Avalonia.Skia Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) }) { - paint.FilterQuality = GetInterpolationMode(scalingMode); + paint.FilterQuality = GetInterpolationMode(bitmapScalingMode); drawableImage.Draw(this, s, d, paint); } diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 27115e164a..d49ef2cd89 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -102,18 +102,18 @@ 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, BitmapScalingMode scalingMode) + /// + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) { using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { if (_renderTarget is DeviceContext deviceContext) { - deviceContext.DrawBitmap(d2d.Value, destRect.ToDirect2D(), (float)opacity, GetInterpolationMode(scalingMode), sourceRect.ToDirect2D(), null); + deviceContext.DrawBitmap(d2d.Value, destRect.ToDirect2D(), (float)opacity, GetInterpolationMode(bitmapScalingMode), sourceRect.ToDirect2D(), null); } else { - var interpolationMode = scalingMode == BitmapScalingMode.LowQuality + var interpolationMode = bitmapScalingMode == BitmapScalingMode.LowQuality ? BitmapInterpolationMode.NearestNeighbor : BitmapInterpolationMode.Linear; diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 7821f60a51..655888cf31 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs @@ -16,6 +16,8 @@ using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering { + using Avalonia.Visuals.Media.Imaging; + public class DeferredRendererTests { [Fact] @@ -336,7 +338,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(), default(BitmapScalingMode))); } 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..996cb289c8 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs @@ -8,6 +8,8 @@ using Xunit; namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph { + using Avalonia.Visuals.Media.Imaging; + public class DrawOperationTests { [Fact] @@ -46,7 +48,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), + BitmapScalingMode.LowQuality); Assert.Equal(2, bitmap.RefCount); From f6c9aa88b93c2b00e2b84ab951bba846e583b375 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 19 Jul 2018 10:04:28 +0200 Subject: [PATCH 05/12] Naming fixes --- src/Avalonia.Controls/Remote/RemoteWidget.cs | 4 +--- src/Avalonia.Visuals/Media/DrawingContext.cs | 6 +++--- src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs | 2 +- .../Rendering/SceneGraph/DeferredDrawingContextImpl.cs | 3 +-- src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs | 5 ++--- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 5 ++--- src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs | 3 +-- .../Rendering/DeferredRendererTests.cs | 6 ++++-- .../Rendering/SceneGraph/DrawOperationTests.cs | 5 ++--- 9 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs index 594208b51c..618a0c3f62 100644 --- a/src/Avalonia.Controls/Remote/RemoteWidget.cs +++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs @@ -9,9 +9,7 @@ using Avalonia.Threading; using PixelFormat = Avalonia.Platform.PixelFormat; namespace Avalonia.Controls.Remote -{ - using Avalonia.Visuals.Media.Imaging; - +{ public class RemoteWidget : Control { private readonly IAvaloniaRemoteTransportConnection _connection; diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 85e165be36..0d7d41e46e 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -69,12 +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, BitmapScalingMode scalingMode = default) + /// + public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode = default) { Contract.Requires(source != null); - PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, scalingMode); + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapScalingMode); } /// diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs index 32b98c92a3..5c91dd993d 100644 --- a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs @@ -14,7 +14,7 @@ namespace Avalonia.Visuals.Media.Imaging HighQuality, /// - /// Good performance an decent image quality. + /// Good performance and decent image quality. /// MediumQuality, diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs index ac69687e60..fbd258fdbe 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -7,11 +7,10 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Utilities; using Avalonia.VisualTree; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { - using Avalonia.Visuals.Media.Imaging; - /// /// A drawing context which builds a scene graph. /// diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index e896d9a015..db5c672b97 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -4,11 +4,10 @@ using System; using Avalonia.Platform; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Rendering.SceneGraph { - using Avalonia.Visuals.Media.Imaging; - /// /// A node in the scene graph which represents an image draw. /// @@ -75,7 +74,7 @@ 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 scaling 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 diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 15ebf31754..f0e56a80cf 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -10,12 +10,11 @@ using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Rendering.Utilities; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia -{ - using Avalonia.Visuals.Media.Imaging; - +{ /// /// Skia based drawing context. /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 801f72b881..0bad70991d 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -7,14 +7,13 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; namespace Avalonia.Direct2D1.Media { - using Avalonia.Visuals.Media.Imaging; - /// /// Draws using Direct2D1. /// diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs index 655888cf31..12ca2777ec 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,14 +11,15 @@ 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 { - using Avalonia.Visuals.Media.Imaging; - public class DeferredRendererTests { [Fact] diff --git a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs index 996cb289c8..664d240966 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs @@ -3,13 +3,12 @@ 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 -{ - using Avalonia.Visuals.Media.Imaging; - +{ public class DrawOperationTests { [Fact] From c0dd75bcce6ae22d67e15da6a290c218fa9ec20e Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Fri, 20 Jul 2018 09:40:37 +0200 Subject: [PATCH 06/12] Refactoring Add interpolation to TileBrush --- src/Avalonia.Controls/Image.cs | 6 +-- src/Avalonia.Controls/RenderOptions.cs | 38 -------------- src/Avalonia.Visuals/Media/DrawingContext.cs | 6 +-- src/Avalonia.Visuals/Media/ITileBrush.cs | 12 ++++- ...lingMode.cs => BitmapInterpolationMode.cs} | 19 ++++--- .../Media/Immutable/ImmutableImageBrush.cs | 11 +++-- .../Media/Immutable/ImmutableTileBrush.cs | 16 ++++-- .../Media/Immutable/ImmutableVisualBrush.cs | 12 +++-- src/Avalonia.Visuals/Media/RenderOptions.cs | 38 ++++++++++++++ src/Avalonia.Visuals/Media/TileBrush.cs | 15 ++++++ .../Platform/IDrawingContextImpl.cs | 4 +- .../SceneGraph/DeferredDrawingContextImpl.cs | 6 +-- .../Rendering/SceneGraph/ImageNode.cs | 16 +++--- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 33 +++++++------ .../Media/DrawingContextImpl.cs | 49 ++++++++----------- .../Media/ImageBrushImpl.cs | 9 ++-- .../Rendering/DeferredRendererTests.cs | 2 +- .../SceneGraph/DrawOperationTests.cs | 5 +- 18 files changed, 172 insertions(+), 125 deletions(-) delete mode 100644 src/Avalonia.Controls/RenderOptions.cs rename src/Avalonia.Visuals/Media/Imaging/{BitmapScalingMode.cs => BitmapInterpolationMode.cs} (71%) create mode 100644 src/Avalonia.Visuals/Media/RenderOptions.cs diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index beddc75917..ffccfdf081 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -1,14 +1,12 @@ // 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; +using Avalonia.Visuals.Media; namespace Avalonia.Controls -{ - using Avalonia.Visuals.Media.Imaging; - +{ /// /// Displays a image. /// diff --git a/src/Avalonia.Controls/RenderOptions.cs b/src/Avalonia.Controls/RenderOptions.cs deleted file mode 100644 index 26f7ed260b..0000000000 --- a/src/Avalonia.Controls/RenderOptions.cs +++ /dev/null @@ -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 - { - /// - /// Defines the property. - /// - public static readonly StyledProperty BitmapScalingModeProperty = - AvaloniaProperty.RegisterAttached( - "BitmapScalingMode", - inherits: true); - - /// - /// Gets the value of the BitmapScalingMode attached property for a control. - /// - /// The control. - /// The control's left coordinate. - public static BitmapScalingMode GetBitmapScalingMode(AvaloniaObject element) - { - return element.GetValue(BitmapScalingModeProperty); - } - - /// - /// Sets the value of the BitmapScalingMode attached property for a control. - /// - /// The control. - /// The left value. - public static void SetBitmapScalingMode(AvaloniaObject element, double value) - { - element.SetValue(BitmapScalingModeProperty, value); - } - } -} diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 0d7d41e46e..173801720d 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -69,12 +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, BitmapScalingMode bitmapScalingMode = default) + /// + 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, bitmapScalingMode); + PlatformImpl.DrawImage(source.PlatformImpl, opacity, sourceRect, destRect, bitmapInterpolationMode); } /// diff --git a/src/Avalonia.Visuals/Media/ITileBrush.cs b/src/Avalonia.Visuals/Media/ITileBrush.cs index 8e2349f506..6c29b159de 100644 --- a/src/Avalonia.Visuals/Media/ITileBrush.cs +++ b/src/Avalonia.Visuals/Media/ITileBrush.cs @@ -1,5 +1,7 @@ namespace Avalonia.Media { + using Avalonia.Visuals.Media.Imaging; + /// /// A brush which displays a repeating image. /// @@ -35,5 +37,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/BitmapScalingMode.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs similarity index 71% rename from src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs rename to src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs index 5c91dd993d..7e6d330618 100644 --- a/src/Avalonia.Visuals/Media/Imaging/BitmapScalingMode.cs +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapInterpolationMode.cs @@ -6,21 +6,26 @@ namespace Avalonia.Visuals.Media.Imaging /// /// Controls the performance and quality of bitmap scaling. /// - public enum BitmapScalingMode + public enum BitmapInterpolationMode { /// - /// Highest quality but worst performance. + /// Uses the default behavior of the underling render backend. + /// + Default, + + /// + /// The best performance but worst image quality. /// - HighQuality, - + LowQuality, + /// /// Good performance and decent image quality. /// - MediumQuality, + MediumQuality, /// - /// The best performance but worst image quality. + /// Highest quality but worst performance. /// - LowQuality + 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..c7a6a168d7 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. + /// Controls the quality of interpolation. 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..7efe1c7349 --- /dev/null +++ b/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 + { + /// + /// Defines the property. + /// + public static readonly StyledProperty BitmapInterpolationMode = + AvaloniaProperty.RegisterAttached( + "BitmapInterpolationMode", + inherits: true); + + /// + /// Gets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The control's left coordinate. + public static BitmapInterpolationMode GetBitmapScalingMode(AvaloniaObject element) + { + return element.GetValue(BitmapInterpolationMode); + } + + /// + /// Sets the value of the BitmapInterpolationMode attached property for a control. + /// + /// The control. + /// The left value. + public static void SetBitmapScalingMode(AvaloniaObject element, BitmapInterpolationMode value) + { + element.SetValue(BitmapInterpolationMode, value); + } + } +} diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 3a7f9d9920..5a6da8f2e1 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -3,6 +3,9 @@ namespace Avalonia.Media { + using Avalonia.Visuals.Media; + using Avalonia.Visuals.Media.Imaging; + /// /// Describes how a is tiled. /// @@ -129,5 +132,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.GetBitmapScalingMode(this); } + set { RenderOptions.SetBitmapScalingMode(this, value); } + } } } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 7f0b2a9904..4ddbbf4dd5 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -32,8 +32,8 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - /// Controls - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode = default); + /// Controls + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, 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 fbd258fdbe..42ecde6a6d 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs @@ -115,13 +115,13 @@ namespace Avalonia.Rendering.SceneGraph } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) + 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, 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 { diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index db5c672b97..35fad25276 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -21,8 +21,8 @@ namespace Avalonia.Rendering.SceneGraph /// The draw opacity. /// The source rect. /// The destination rect. - /// The bitmap scaling mode. - public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) + /// The bitmap scaling mode. + public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) : base(destRect, transform, null) { Transform = transform; @@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph Opacity = opacity; SourceRect = sourceRect; DestRect = destRect; - BitmapScalingMode = bitmapScalingMode; + BitmapInterpolationMode = bitmapInterpolationMode; } /// @@ -64,7 +64,7 @@ namespace Avalonia.Rendering.SceneGraph /// /// The scaling mode. /// - public BitmapScalingMode BitmapScalingMode { get; } + public BitmapInterpolationMode BitmapInterpolationMode { get; } /// /// Determines if this draw operation equals another. @@ -74,20 +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 scaling mode. + /// The bitmap scaling 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, BitmapScalingMode bitmapScalingMode) + 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 && - bitmapScalingMode == BitmapScalingMode; + bitmapInterpolationMode == BitmapInterpolationMode; } /// @@ -96,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, BitmapScalingMode); + context.DrawImage(Source, Opacity, SourceRect, DestRect, BitmapInterpolationMode); } /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index f0e56a80cf..7903e6cf6e 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -14,7 +14,9 @@ using Avalonia.Visuals.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia -{ +{ + using Avalonia.Controls; + /// /// Skia based drawing context. /// @@ -96,7 +98,7 @@ namespace Avalonia.Skia } /// - public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode bitmapScalingMode) + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { var drawableImage = (IDrawableBitmapImpl)source.Item; var s = sourceRect.ToSKRect(); @@ -108,24 +110,26 @@ namespace Avalonia.Skia Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) }) { - paint.FilterQuality = GetInterpolationMode(bitmapScalingMode); + paint.FilterQuality = GetInterpolationMode(bitmapInterpolationMode); 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; - case BitmapScalingMode.MediumQuality: + case BitmapInterpolationMode.MediumQuality: return SKFilterQuality.Medium; - case BitmapScalingMode.HighQuality: + case BitmapInterpolationMode.HighQuality: return SKFilterQuality.High; + case BitmapInterpolationMode.Default: + return SKFilterQuality.None; 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 source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { 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(); } @@ -378,7 +382,8 @@ namespace Avalonia.Skia /// Target size. /// Tile brush to use. /// Tile brush image. - private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) + /// The bitmap interpolation mode. + private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage, BitmapInterpolationMode interpolationMode) { var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); @@ -396,7 +401,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, interpolationMode); context.PopClip(); } @@ -505,12 +510,12 @@ 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) { - ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage); + ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage, tileBrush.BitmapInterpolationMode); } else { diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 0bad70991d..bf379bac5c 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -14,6 +14,8 @@ using SharpDX.Mathematics.Interop; namespace Avalonia.Direct2D1.Media { + using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode; + /// /// Draws using Direct2D1. /// @@ -101,43 +103,34 @@ 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, BitmapScalingMode bitmapScalingMode) + /// + public void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) { using (var d2d = ((BitmapImpl)source.Item).GetDirect2DBitmap(_renderTarget)) { - if (_renderTarget is DeviceContext deviceContext) - { - deviceContext.DrawBitmap(d2d.Value, destRect.ToDirect2D(), (float)opacity, GetInterpolationMode(bitmapScalingMode), sourceRect.ToDirect2D(), null); - } - else - { - var interpolationMode = bitmapScalingMode == BitmapScalingMode.LowQuality - ? BitmapInterpolationMode.NearestNeighbor - : BitmapInterpolationMode.Linear; - - _renderTarget.DrawBitmap( - d2d.Value, - destRect.ToSharpDX(), - (float)opacity, - interpolationMode, - sourceRect.ToSharpDX()); - } + var interpolationMode = GetInterpolationMode(bitmapInterpolationMode); + + _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: - return InterpolationMode.NearestNeighbor; - case BitmapScalingMode.MediumQuality: - return InterpolationMode.Linear; - case BitmapScalingMode.HighQuality: - return InterpolationMode.HighQualityCubic; + 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(scalingMode), scalingMode, null); + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); } } 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 12ca2777ec..2350a31d5c 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/DeferredRendererTests.cs +++ b/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 borderLayer = target.Layers[border].Bitmap; - context.Verify(x => x.DrawImage(borderLayer, 0.5, It.IsAny(), It.IsAny(), default(BitmapScalingMode))); + 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 664d240966..2060cc7170 100644 --- a/tests/Avalonia.Visuals.UnitTests/Rendering/SceneGraph/DrawOperationTests.cs +++ b/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.Rendering.SceneGraph; using Avalonia.Utilities; @@ -53,7 +52,7 @@ namespace Avalonia.Visuals.UnitTests.Rendering.SceneGraph 1, new Rect(1, 1, 1, 1), new Rect(1, 1, 1, 1), - BitmapScalingMode.LowQuality); + BitmapInterpolationMode.Default); Assert.Equal(2, bitmap.RefCount); From 5b5971aff37497df9a19fec944126dc2632bedc2 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 22 Jul 2018 19:15:12 +0200 Subject: [PATCH 07/12] Comment fixes --- .gitignore | 2 +- src/Avalonia.Visuals/Media/DrawingContext.cs | 2 +- src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs | 2 +- src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs | 2 +- src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs | 6 +++--- src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index dd814ba26f..583a2b8a2b 100644 --- a/.gitignore +++ b/.gitignore @@ -181,4 +181,4 @@ project.lock.json ################## ## BenchmarkDotNet ################## -BenchmarkDotNet.Artifacts/ \ No newline at end of file +BenchmarkDotNet.Artifacts/ diff --git a/src/Avalonia.Visuals/Media/DrawingContext.cs b/src/Avalonia.Visuals/Media/DrawingContext.cs index 173801720d..60a7a2e518 100644 --- a/src/Avalonia.Visuals/Media/DrawingContext.cs +++ b/src/Avalonia.Visuals/Media/DrawingContext.cs @@ -69,7 +69,7 @@ namespace Avalonia.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - /// + /// The bitmap interpolation mode. public void DrawImage(IBitmap source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default) { Contract.Requires(source != null); diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs index c7a6a168d7..c3dd159d04 100644 --- a/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs +++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableTileBrush.cs @@ -22,7 +22,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. + /// The bitmap interpolation mode. protected ImmutableTileBrush( AlignmentX alignmentX, AlignmentY alignmentY, diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 4ddbbf4dd5..3ffcde7165 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -32,7 +32,7 @@ namespace Avalonia.Platform /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - /// Controls + /// The bitmap interpolation mode. void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default); /// diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs index 35fad25276..9e8fca5f84 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs @@ -21,7 +21,7 @@ namespace Avalonia.Rendering.SceneGraph /// The draw opacity. /// The source rect. /// The destination rect. - /// The bitmap scaling mode. + /// The bitmap interpolation mode. public ImageNode(Matrix transform, IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode) : base(destRect, transform, null) { @@ -59,7 +59,7 @@ namespace Avalonia.Rendering.SceneGraph public Rect DestRect { get; } /// - /// Gets the bitmap scaling mode. + /// Gets the bitmap interpolation mode. /// /// /// The scaling mode. @@ -74,7 +74,7 @@ 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 scaling mode. + /// 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 diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index bf379bac5c..659c89bb58 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -103,7 +103,7 @@ namespace Avalonia.Direct2D1.Media /// The opacity to draw with. /// The rect in the image to draw. /// The rect in the output to draw to. - /// + /// 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)) From 81008bd5f7189c07b5edb6b2d7de3881f73f15c7 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Sun, 22 Jul 2018 19:42:24 +0200 Subject: [PATCH 08/12] Naming fixes --- src/Avalonia.Controls/Image.cs | 2 +- src/Avalonia.Visuals/Media/RenderOptions.cs | 8 ++++---- src/Avalonia.Visuals/Media/TileBrush.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index ffccfdf081..50e4f1515e 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -68,7 +68,7 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - var scalingMode = RenderOptions.GetBitmapScalingMode(this); + var scalingMode = RenderOptions.GetBitmapInterpolationMode(this); context.DrawImage(source, 1, sourceRect, destRect, scalingMode); } diff --git a/src/Avalonia.Visuals/Media/RenderOptions.cs b/src/Avalonia.Visuals/Media/RenderOptions.cs index 7efe1c7349..b38ba3f9c9 100644 --- a/src/Avalonia.Visuals/Media/RenderOptions.cs +++ b/src/Avalonia.Visuals/Media/RenderOptions.cs @@ -3,12 +3,12 @@ using Avalonia.Visuals.Media.Imaging; -namespace Avalonia.Visuals.Media +namespace Avalonia.Media { public class RenderOptions { /// - /// Defines the property. + /// Defines the property. /// public static readonly StyledProperty BitmapInterpolationMode = AvaloniaProperty.RegisterAttached( @@ -20,7 +20,7 @@ namespace Avalonia.Visuals.Media /// /// The control. /// The control's left coordinate. - public static BitmapInterpolationMode GetBitmapScalingMode(AvaloniaObject element) + public static BitmapInterpolationMode GetBitmapInterpolationMode(AvaloniaObject element) { return element.GetValue(BitmapInterpolationMode); } @@ -30,7 +30,7 @@ namespace Avalonia.Visuals.Media /// /// The control. /// The left value. - public static void SetBitmapScalingMode(AvaloniaObject element, BitmapInterpolationMode value) + public static void SetBitmapInterpolationMode(AvaloniaObject element, BitmapInterpolationMode value) { element.SetValue(BitmapInterpolationMode, value); } diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 5a6da8f2e1..506b406856 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -141,8 +141,8 @@ namespace Avalonia.Media /// public BitmapInterpolationMode BitmapInterpolationMode { - get { return RenderOptions.GetBitmapScalingMode(this); } - set { RenderOptions.SetBitmapScalingMode(this, value); } + get { return RenderOptions.GetBitmapInterpolationMode(this); } + set { RenderOptions.SetBitmapInterpolationMode(this, value); } } } } From 4c63eb37d2459886b9fbfaba19577e38aa448d7f Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 23 Jul 2018 09:17:06 +0200 Subject: [PATCH 09/12] Namespace fixes --- src/Avalonia.Controls/Image.cs | 1 - src/Avalonia.Controls/Remote/RemoteWidget.cs | 4 ++-- src/Avalonia.Visuals/Media/ITileBrush.cs | 9 ++++++--- src/Avalonia.Visuals/Media/TileBrush.cs | 5 ++--- src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs | 3 +-- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 2 -- .../Avalonia.Direct2D1/Media/DrawingContextImpl.cs | 6 ++---- .../Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs | 10 +++------- 8 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index 50e4f1515e..fd90f9f2e8 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -3,7 +3,6 @@ using Avalonia.Media; using Avalonia.Media.Imaging; -using Avalonia.Visuals.Media; namespace Avalonia.Controls { diff --git a/src/Avalonia.Controls/Remote/RemoteWidget.cs b/src/Avalonia.Controls/Remote/RemoteWidget.cs index 618a0c3f62..ea8c3ebe52 100644 --- a/src/Avalonia.Controls/Remote/RemoteWidget.cs +++ b/src/Avalonia.Controls/Remote/RemoteWidget.cs @@ -9,7 +9,7 @@ using Avalonia.Threading; using PixelFormat = Avalonia.Platform.PixelFormat; namespace Avalonia.Controls.Remote -{ +{ public class RemoteWidget : Control { private readonly IAvaloniaRemoteTransportConnection _connection; @@ -76,4 +76,4 @@ namespace Avalonia.Controls.Remote base.Render(context); } } -} +} \ No newline at end of file diff --git a/src/Avalonia.Visuals/Media/ITileBrush.cs b/src/Avalonia.Visuals/Media/ITileBrush.cs index 6c29b159de..5cffe02193 100644 --- a/src/Avalonia.Visuals/Media/ITileBrush.cs +++ b/src/Avalonia.Visuals/Media/ITileBrush.cs @@ -1,7 +1,10 @@ -namespace Avalonia.Media -{ - using Avalonia.Visuals.Media.Imaging; +// 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. /// diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 506b406856..094208d021 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -1,11 +1,10 @@ // 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 { - using Avalonia.Visuals.Media; - using Avalonia.Visuals.Media.Imaging; - /// /// Describes how a is tiled. /// diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index 3ffcde7165..debc7103c0 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -4,11 +4,10 @@ using System; using Avalonia.Media; using Avalonia.Utilities; +using Avalonia.Visuals.Media.Imaging; namespace Avalonia.Platform { - using Avalonia.Visuals.Media.Imaging; - /// /// Defines the interface through which drawing occurs. /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 7903e6cf6e..28ac311605 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -15,8 +15,6 @@ using SkiaSharp; namespace Avalonia.Skia { - using Avalonia.Controls; - /// /// Skia based drawing context. /// diff --git a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs index 659c89bb58..ae5dd3ae13 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs @@ -7,19 +7,17 @@ using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; using Avalonia.Utilities; -using Avalonia.Visuals.Media.Imaging; using SharpDX; using SharpDX.Direct2D1; using SharpDX.Mathematics.Interop; +using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode; namespace Avalonia.Direct2D1.Media { - using BitmapInterpolationMode = Avalonia.Visuals.Media.Imaging.BitmapInterpolationMode; - /// /// Draws using Direct2D1. /// - public class DrawingContextImpl : IDrawingContextImpl, IDisposable + public class DrawingContextImpl : IDrawingContextImpl { private readonly IVisualBrushRenderer _visualBrushRenderer; private readonly ILayerFactory _layerFactory; diff --git a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs index c792334ec1..d58f023391 100644 --- a/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs +++ b/src/Windows/Avalonia.Direct2D1/Media/Imaging/BitmapImpl.cs @@ -1,15 +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 System; using System.IO; using Avalonia.Platform; using SharpDX.WIC; +using D2DBitmap = SharpDX.Direct2D1.Bitmap; namespace Avalonia.Direct2D1.Media { - using SharpDX.Direct2D1; - public abstract class BitmapImpl : IBitmapImpl, IDisposable { public BitmapImpl(ImagingFactory imagingFactory) @@ -21,7 +17,7 @@ namespace Avalonia.Direct2D1.Media public abstract int PixelWidth { get; } public abstract int PixelHeight { get; } - public abstract OptionalDispose GetDirect2DBitmap(RenderTarget target); + public abstract OptionalDispose GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target); public void Save(string fileName) { From f4b0e22963eb51a6dd4b0ea111a1bbf64d374fd0 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Mon, 23 Jul 2018 19:06:22 +0200 Subject: [PATCH 10/12] Set default to high quality --- src/Avalonia.Visuals/Media/RenderOptions.cs | 11 ++++++----- src/Avalonia.Visuals/Media/TileBrush.cs | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Avalonia.Visuals/Media/RenderOptions.cs b/src/Avalonia.Visuals/Media/RenderOptions.cs index b38ba3f9c9..5e16f5f9ce 100644 --- a/src/Avalonia.Visuals/Media/RenderOptions.cs +++ b/src/Avalonia.Visuals/Media/RenderOptions.cs @@ -8,11 +8,12 @@ namespace Avalonia.Media public class RenderOptions { /// - /// Defines the property. + /// Defines the property. /// - public static readonly StyledProperty BitmapInterpolationMode = + public static readonly StyledProperty BitmapInterpolationModeProperty = AvaloniaProperty.RegisterAttached( - "BitmapInterpolationMode", + "BitmapInterpolationMode", + BitmapInterpolationMode.HighQuality, inherits: true); /// @@ -22,7 +23,7 @@ namespace Avalonia.Media /// The control's left coordinate. public static BitmapInterpolationMode GetBitmapInterpolationMode(AvaloniaObject element) { - return element.GetValue(BitmapInterpolationMode); + return element.GetValue(BitmapInterpolationModeProperty); } /// @@ -32,7 +33,7 @@ namespace Avalonia.Media /// The left value. public static void SetBitmapInterpolationMode(AvaloniaObject element, BitmapInterpolationMode value) { - element.SetValue(BitmapInterpolationMode, value); + element.SetValue(BitmapInterpolationModeProperty, value); } } } diff --git a/src/Avalonia.Visuals/Media/TileBrush.cs b/src/Avalonia.Visuals/Media/TileBrush.cs index 094208d021..2033754137 100644 --- a/src/Avalonia.Visuals/Media/TileBrush.cs +++ b/src/Avalonia.Visuals/Media/TileBrush.cs @@ -77,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. /// From 7e59520aaff11a8ab24817d446f65fc23a94f2c4 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Wed, 25 Jul 2018 13:44:01 +0200 Subject: [PATCH 11/12] Set default render quality to medium --- src/Avalonia.Visuals/Media/RenderOptions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Visuals/Media/RenderOptions.cs b/src/Avalonia.Visuals/Media/RenderOptions.cs index 5e16f5f9ce..180863f9e8 100644 --- a/src/Avalonia.Visuals/Media/RenderOptions.cs +++ b/src/Avalonia.Visuals/Media/RenderOptions.cs @@ -13,7 +13,7 @@ namespace Avalonia.Media public static readonly StyledProperty BitmapInterpolationModeProperty = AvaloniaProperty.RegisterAttached( "BitmapInterpolationMode", - BitmapInterpolationMode.HighQuality, + BitmapInterpolationMode.MediumQuality, inherits: true); /// From fb30bcd9bd1cd24e045e688e22c09036bdad5bd3 Mon Sep 17 00:00:00 2001 From: Benedikt Schroeder Date: Thu, 26 Jul 2018 08:58:54 +0200 Subject: [PATCH 12/12] Some minor issues fixed --- src/Avalonia.Controls/Image.cs | 4 ++-- src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs | 2 +- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/Image.cs b/src/Avalonia.Controls/Image.cs index fd90f9f2e8..f146e3571c 100644 --- a/src/Avalonia.Controls/Image.cs +++ b/src/Avalonia.Controls/Image.cs @@ -67,9 +67,9 @@ namespace Avalonia.Controls Rect sourceRect = new Rect(sourceSize) .CenterRect(new Rect(destRect.Size / scale)); - var scalingMode = RenderOptions.GetBitmapInterpolationMode(this); + var interpolationMode = RenderOptions.GetBitmapInterpolationMode(this); - context.DrawImage(source, 1, sourceRect, destRect, scalingMode); + context.DrawImage(source, 1, sourceRect, destRect, interpolationMode); } } diff --git a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs index debc7103c0..b11d9f52ab 100644 --- a/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs +++ b/src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs @@ -32,7 +32,7 @@ namespace Avalonia.Platform /// The rect in the image to draw. /// The rect in the output to draw to. /// The bitmap interpolation mode. - void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = default); + void DrawImage(IRef source, double opacity, Rect sourceRect, Rect destRect, BitmapInterpolationMode bitmapInterpolationMode = BitmapInterpolationMode.Default); /// /// Draws a bitmap image. diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 28ac311605..685987ae80 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -381,7 +381,7 @@ namespace Avalonia.Skia /// Tile brush to use. /// Tile brush image. /// The bitmap interpolation mode. - private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage, BitmapInterpolationMode interpolationMode) + private void ConfigureTileBrush(ref PaintWrapper paintWrapper, Size targetSize, ITileBrush tileBrush, IDrawableBitmapImpl tileBrushImage) { var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); @@ -399,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, interpolationMode); + context.DrawImage(RefCountable.CreateUnownedNotClonable(tileBrushImage), 1, rect, rect, tileBrush.BitmapInterpolationMode); context.PopClip(); } @@ -513,7 +513,7 @@ namespace Avalonia.Skia if (tileBrush != null && tileBrushImage != null) { - ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage, tileBrush.BitmapInterpolationMode); + ConfigureTileBrush(ref paintWrapper, targetSize, tileBrush, tileBrushImage); } else {