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