From ba75735848cff6287402ec4e9bd8ade95e72e8e4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Wed, 6 May 2020 16:55:09 -0300 Subject: [PATCH] decode bitmaps at a specified size. --- src/Avalonia.Visuals/Media/Imaging/Bitmap.cs | 12 ++++++++++ .../Media/Imaging/BitmapDecodeOptions.cs | 11 +++++++++ .../Platform/IPlatformRenderInterface.cs | 5 ++++ src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 19 +-------------- .../Avalonia.Skia/PlatformRenderInterface.cs | 23 +++++++++++++++++++ src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs | 18 +++++++++++++++ .../Avalonia.Direct2D1/Direct2D1Platform.cs | 11 +++++++++ 7 files changed, 81 insertions(+), 18 deletions(-) create mode 100644 src/Avalonia.Visuals/Media/Imaging/BitmapDecodeOptions.cs diff --git a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs index 42ee35133e..408a93eae7 100644 --- a/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs +++ b/src/Avalonia.Visuals/Media/Imaging/Bitmap.cs @@ -31,6 +31,18 @@ namespace Avalonia.Media.Imaging PlatformImpl = RefCountable.Create(factory.LoadBitmap(stream)); } + public Bitmap(Stream stream, BitmapDecodeOptions decodeOptions) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + PlatformImpl = RefCountable.Create(factory.LoadBitmap(stream, decodeOptions)); + } + + public Bitmap(string file, BitmapDecodeOptions decodeOptions) + { + IPlatformRenderInterface factory = AvaloniaLocator.Current.GetService(); + PlatformImpl = RefCountable.Create(factory.LoadBitmap(file, decodeOptions)); + } + /// /// Initializes a new instance of the class. /// diff --git a/src/Avalonia.Visuals/Media/Imaging/BitmapDecodeOptions.cs b/src/Avalonia.Visuals/Media/Imaging/BitmapDecodeOptions.cs new file mode 100644 index 0000000000..ec9d823bb4 --- /dev/null +++ b/src/Avalonia.Visuals/Media/Imaging/BitmapDecodeOptions.cs @@ -0,0 +1,11 @@ +using Avalonia.Visuals.Media.Imaging; + +namespace Avalonia.Media.Imaging +{ + public struct BitmapDecodeOptions + { + public PixelSize DecodePixelSize { get; set; } + + public BitmapInterpolationMode InterpolationMode { get; set; } + } +} diff --git a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs index bd569fe841..86662a3584 100644 --- a/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs +++ b/src/Avalonia.Visuals/Platform/IPlatformRenderInterface.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using Avalonia.Media; +using Avalonia.Media.Imaging; namespace Avalonia.Platform { @@ -84,6 +85,10 @@ namespace Avalonia.Platform /// An . IWriteableBitmapImpl CreateWriteableBitmap(PixelSize size, Vector dpi, PixelFormat? format = null); + IBitmapImpl LoadBitmap(string fileName, BitmapDecodeOptions decodeOptions); + + IBitmapImpl LoadBitmap(Stream stream, BitmapDecodeOptions decodeOptions); + /// /// Loads a bitmap implementation from a file.. /// diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 9f99ed3cef..6472338734 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -123,29 +123,12 @@ namespace Avalonia.Skia Color = new SKColor(255, 255, 255, (byte)(255 * opacity * _currentOpacity)) }) { - paint.FilterQuality = GetInterpolationMode(bitmapInterpolationMode); + paint.FilterQuality = bitmapInterpolationMode.ToSKFilterQuality(); drawableImage.Draw(this, s, d, paint); } } - private static SKFilterQuality GetInterpolationMode(BitmapInterpolationMode interpolationMode) - { - switch (interpolationMode) - { - case BitmapInterpolationMode.LowQuality: - return SKFilterQuality.Low; - case BitmapInterpolationMode.MediumQuality: - return SKFilterQuality.Medium; - case BitmapInterpolationMode.HighQuality: - return SKFilterQuality.High; - case BitmapInterpolationMode.Default: - return SKFilterQuality.None; - default: - throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); - } - } - /// public void DrawBitmap(IRef source, IBrush opacityMask, Rect opacityMaskRect, Rect destRect) { diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index f6d77e1045..b96a65186e 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using Avalonia.Controls.Platform.Surfaces; using Avalonia.Media; +using Avalonia.Media.Imaging; using Avalonia.OpenGL; using Avalonia.Platform; using SkiaSharp; @@ -77,6 +78,28 @@ namespace Avalonia.Skia return new StreamGeometryImpl(); } + public IBitmapImpl LoadBitmap(string fileName, BitmapDecodeOptions decodeOptions) + { + using (var stream = File.OpenRead(fileName)) + { + return LoadBitmap(stream, decodeOptions); + } + } + + public unsafe IBitmapImpl LoadBitmap(Stream stream, BitmapDecodeOptions decodeOptions) + { + var skBitmap = SKBitmap.Decode(stream); + + skBitmap = skBitmap.Resize(new SKImageInfo(decodeOptions.DecodePixelSize.Width, decodeOptions.DecodePixelSize.Height), decodeOptions.InterpolationMode.ToSKFilterQuality()); + + fixed (byte* p = skBitmap.Bytes) + { + IntPtr ptr = (IntPtr)p; + + return LoadBitmap(PixelFormat.Bgra8888, ptr, new PixelSize(skBitmap.Width, skBitmap.Height), new Vector(96, 96), skBitmap.RowBytes); + } + } + /// public IBitmapImpl LoadBitmap(Stream stream) { diff --git a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs index 1dd2310475..c706d5c1aa 100644 --- a/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs +++ b/src/Skia/Avalonia.Skia/SkiaSharpExtensions.cs @@ -1,12 +1,30 @@ using System; using Avalonia.Media; using Avalonia.Platform; +using Avalonia.Visuals.Media.Imaging; using SkiaSharp; namespace Avalonia.Skia { public static class SkiaSharpExtensions { + public static SKFilterQuality ToSKFilterQuality(this BitmapInterpolationMode interpolationMode) + { + switch (interpolationMode) + { + case BitmapInterpolationMode.LowQuality: + return SKFilterQuality.Low; + case BitmapInterpolationMode.MediumQuality: + return SKFilterQuality.Medium; + case BitmapInterpolationMode.HighQuality: + return SKFilterQuality.High; + case BitmapInterpolationMode.Default: + return SKFilterQuality.None; + default: + throw new ArgumentOutOfRangeException(nameof(interpolationMode), interpolationMode, null); + } + } + public static SKPoint ToSKPoint(this Point p) { return new SKPoint((float)p.X, (float)p.Y); diff --git a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs index b8bbed24f8..534ecdd6e6 100644 --- a/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs +++ b/src/Windows/Avalonia.Direct2D1/Direct2D1Platform.cs @@ -7,6 +7,7 @@ using Avalonia.Controls.Platform.Surfaces; using Avalonia.Direct2D1.Media; using Avalonia.Direct2D1.Media.Imaging; using Avalonia.Media; +using Avalonia.Media.Imaging; using Avalonia.Platform; using SharpDX.DirectWrite; using GlyphRun = Avalonia.Media.GlyphRun; @@ -194,6 +195,16 @@ namespace Avalonia.Direct2D1 return new WicBitmapImpl(format, data, size, dpi, stride); } + public IBitmapImpl LoadBitmap(string fileName, BitmapDecodeOptions decodeOptions) + { + throw new NotImplementedException(); + } + + public IBitmapImpl LoadBitmap(Stream stream, BitmapDecodeOptions decodeOptions) + { + throw new NotImplementedException(); + } + public IGlyphRunImpl CreateGlyphRun(GlyphRun glyphRun, out double width) { var glyphTypeface = (GlyphTypefaceImpl)glyphRun.GlyphTypeface.PlatformImpl;