Benedikt Schroeder 7 years ago
parent
commit
3154137c2a

+ 12 - 0
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
+    }
+}

+ 4 - 1
src/Avalonia.Visuals/Platform/IDrawingContextImpl.cs

@@ -7,6 +7,8 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Platform
 {
+    using Avalonia.Visuals.Media.Imaging;
+
     /// <summary>
     /// Defines the interface through which drawing occurs.
     /// </summary>
@@ -30,7 +32,8 @@ namespace Avalonia.Platform
         /// <param name="opacity">The opacity to draw with.</param>
         /// <param name="sourceRect">The rect in the image to draw.</param>
         /// <param name="destRect">The rect in the output to draw to.</param>
-        void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect);
+        /// <param name="scalingMode">Controls</param>
+        void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality);
 
         /// <summary>
         /// Draws a bitmap image.

+ 5 - 3
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@@ -10,6 +10,8 @@ using Avalonia.VisualTree;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    using Avalonia.Visuals.Media.Imaging;
+
     /// <summary>
     /// A drawing context which builds a scene graph.
     /// </summary>
@@ -114,13 +116,13 @@ namespace Avalonia.Rendering.SceneGraph
         }
 
         /// <inheritdoc/>
-        public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
+        public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect, BitmapScalingMode scalingMode = BitmapScalingMode.LowQuality)
         {
             var next = NextDrawAs<ImageNode>();
 
-            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
             {

+ 20 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/ImageNode.cs

@@ -7,6 +7,8 @@ using Avalonia.Utilities;
 
 namespace Avalonia.Rendering.SceneGraph
 {
+    using Avalonia.Visuals.Media.Imaging;
+
     /// <summary>
     /// A node in the scene graph which represents an image draw.
     /// </summary>
@@ -20,7 +22,8 @@ namespace Avalonia.Rendering.SceneGraph
         /// <param name="opacity">The draw opacity.</param>
         /// <param name="sourceRect">The source rect.</param>
         /// <param name="destRect">The destination rect.</param>
-        public ImageNode(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
+        /// <param name="scalingMode"></param>
+        public ImageNode(Matrix transform, IRef<IBitmapImpl> 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;
         }
 
+        
+
         /// <summary>
         /// Gets the transform with which the node will be drawn.
         /// </summary>
@@ -55,6 +61,14 @@ namespace Avalonia.Rendering.SceneGraph
         /// </summary>
         public Rect DestRect { get; }
 
+        /// <summary>
+        /// Gets or sets the scaling mode.
+        /// </summary>
+        /// <value>
+        /// The scaling mode.
+        /// </value>
+        public BitmapScalingMode ScalingMode { get; }
+
         /// <summary>
         /// Determines if this draw operation equals another.
         /// </summary>
@@ -63,18 +77,20 @@ namespace Avalonia.Rendering.SceneGraph
         /// <param name="opacity">The opacity of the other draw operation.</param>
         /// <param name="sourceRect">The source rect of the other draw operation.</param>
         /// <param name="destRect">The dest rect of the other draw operation.</param>
+        /// <param name="scalingMode"></param>
         /// <returns>True if the draw operations are the same, otherwise false.</returns>
         /// <remarks>
         /// The properties of the other draw operation are passed in as arguments to prevent
         /// allocation of a not-yet-constructed draw operation object.
         /// </remarks>
-        public bool Equals(Matrix transform, IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
+        public bool Equals(Matrix transform, IRef<IBitmapImpl> 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;
         }
 
         /// <inheritdoc/>
@@ -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);
         }
 
         /// <inheritdoc/>

+ 36 - 7
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@@ -13,6 +13,8 @@ using SharpDX.Mathematics.Interop;
 
 namespace Avalonia.Direct2D1.Media
 {
+    using Avalonia.Visuals.Media.Imaging;
+
     /// <summary>
     /// Draws using Direct2D1.
     /// </summary>
@@ -100,16 +102,43 @@ namespace Avalonia.Direct2D1.Media
         /// <param name="opacity">The opacity to draw with.</param>
         /// <param name="sourceRect">The rect in the image to draw.</param>
         /// <param name="destRect">The rect in the output to draw to.</param>
-        public void DrawImage(IRef<IBitmapImpl> source, double opacity, Rect sourceRect, Rect destRect)
+        /// <param name="scalingMode"></param>
+        public void DrawImage(IRef<IBitmapImpl> 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);
             }
         }
 

+ 7 - 3
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<D2DBitmap> GetDirect2DBitmap(SharpDX.Direct2D1.RenderTarget target);
+        public abstract OptionalDispose<Bitmap> GetDirect2DBitmap(RenderTarget target);
 
         public void Save(string fileName)
         {