From 69c43cb645c4efac496889312eda330520d513b9 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 27 May 2017 21:57:50 +0200 Subject: [PATCH] Fix DPI scaling with Skia. --- src/Skia/Avalonia.Skia/BitmapImpl.cs | 23 +++++++++++-------- src/Skia/Avalonia.Skia/DrawingContextImpl.cs | 16 +++++++++---- .../Avalonia.Skia/FramebufferRenderTarget.cs | 3 +-- .../Avalonia.Skia/PlatformRenderInterface.cs | 4 ++-- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/Skia/Avalonia.Skia/BitmapImpl.cs b/src/Skia/Avalonia.Skia/BitmapImpl.cs index e9c241b848..3b0105d4c7 100644 --- a/src/Skia/Avalonia.Skia/BitmapImpl.cs +++ b/src/Skia/Avalonia.Skia/BitmapImpl.cs @@ -1,9 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; -using System.Text; -using Avalonia.Media; using Avalonia.Platform; using Avalonia.Rendering; using SkiaSharp; @@ -12,6 +8,9 @@ namespace Avalonia.Skia { class BitmapImpl : IRenderTargetBitmapImpl, IWritableBitmapImpl { + private double _dpiX; + private double _dpiY; + public SKBitmap Bitmap { get; private set; } public BitmapImpl(SKBitmap bm) @@ -19,12 +18,16 @@ namespace Avalonia.Skia Bitmap = bm; PixelHeight = bm.Height; PixelWidth = bm.Width; + _dpiX = 96; + _dpiY = 96; } - public BitmapImpl(int width, int height, PixelFormat? fmt = null) + public BitmapImpl(int width, int height, double dpiX, double dpiY, PixelFormat? fmt = null) { PixelHeight = height; PixelWidth = width; + _dpiX = dpiX; + _dpiY = dpiY; var colorType = fmt?.ToSkColorType() ?? SKImageInfo.PlatformColorType; var runtime = AvaloniaLocator.Current?.GetService()?.GetRuntimeInfo(); if (runtime?.IsDesktop == true && runtime?.OperatingSystem == OperatingSystemType.Linux) @@ -68,8 +71,8 @@ namespace Avalonia.Skia { private readonly SKSurface _surface; - public BitmapDrawingContext(SKBitmap bitmap, IVisualBrushRenderer visualBrushRenderer) - : this(CreateSurface(bitmap), visualBrushRenderer) + public BitmapDrawingContext(SKBitmap bitmap, double dpiX, double dpiY, IVisualBrushRenderer visualBrushRenderer) + : this(CreateSurface(bitmap), dpiX, dpiY, visualBrushRenderer) { } @@ -83,8 +86,8 @@ namespace Avalonia.Skia return rv; } - public BitmapDrawingContext(SKSurface surface, IVisualBrushRenderer visualBrushRenderer) - : base(surface.Canvas, visualBrushRenderer) + public BitmapDrawingContext(SKSurface surface, double dpiX, double dpiY, IVisualBrushRenderer visualBrushRenderer) + : base(surface.Canvas, dpiX, dpiY, visualBrushRenderer) { _surface = surface; } @@ -98,7 +101,7 @@ namespace Avalonia.Skia public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) { - return new BitmapDrawingContext(Bitmap, visualBrushRenderer); + return new BitmapDrawingContext(Bitmap, _dpiX, _dpiY, visualBrushRenderer); } public void Save(Stream stream) diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs index 106e713de4..43e03e63bf 100644 --- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs +++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs @@ -11,6 +11,8 @@ namespace Avalonia.Skia { internal class DrawingContextImpl : IDrawingContextImpl { + private readonly double _dpiX; + private readonly double _dpiY; private readonly Matrix? _postTransform; private readonly IDisposable[] _disposables; private readonly IVisualBrushRenderer _visualBrushRenderer; @@ -20,12 +22,16 @@ namespace Avalonia.Skia public DrawingContextImpl( SKCanvas canvas, + double dpiX, + double dpiY, IVisualBrushRenderer visualBrushRenderer, - Matrix? postTransform = null, params IDisposable[] disposables) { - if (postTransform.HasValue && !postTransform.Value.IsIdentity) - _postTransform = postTransform; + _dpiX = dpiX; + _dpiY = dpiY; + + if (dpiX != 96 || dpiY != 96) + _postTransform = Matrix.CreateScale(dpiX / 96, dpiY / 96); _visualBrushRenderer = visualBrushRenderer; _disposables = disposables; Canvas = canvas; @@ -217,7 +223,7 @@ namespace Avalonia.Skia if (intermediateSize.Width >= 1 && intermediateSize.Height >= 1) { - var intermediate = new BitmapImpl((int)intermediateSize.Width, (int)intermediateSize.Height); + var intermediate = new BitmapImpl((int)intermediateSize.Width, (int)intermediateSize.Height, _dpiX, _dpiY); using (var ctx = intermediate.CreateDrawingContext(_visualBrushRenderer)) { @@ -242,7 +248,7 @@ namespace Avalonia.Skia if (tileBrush != null && tileBrushImage != null) { var calc = new TileBrushCalculator(tileBrush, new Size(tileBrushImage.PixelWidth, tileBrushImage.PixelHeight), targetSize); - var bitmap = new BitmapImpl((int)calc.IntermediateSize.Width, (int)calc.IntermediateSize.Height); + var bitmap = new BitmapImpl((int)calc.IntermediateSize.Width, (int)calc.IntermediateSize.Height, _dpiX, _dpiY); rv.AddDisposable(bitmap); using (var context = bitmap.CreateDrawingContext(null)) { diff --git a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs index 0eacdf41ac..b0d8896963 100644 --- a/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs +++ b/src/Skia/Avalonia.Skia/FramebufferRenderTarget.cs @@ -76,8 +76,7 @@ namespace Avalonia.Skia canvas.RestoreToCount(0); canvas.Save(); canvas.ResetMatrix(); - var scale = Matrix.CreateScale(fb.Dpi.Width / 96, fb.Dpi.Height / 96); - return new DrawingContextImpl(canvas, visualBrushRenderer, scale, canvas, surface, shim, fb); + return new DrawingContextImpl(canvas, fb.Dpi.Width, fb.Dpi.Height, visualBrushRenderer, canvas, surface, shim, fb); } } } diff --git a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs index aea1dea584..3bf587d386 100644 --- a/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs +++ b/src/Skia/Avalonia.Skia/PlatformRenderInterface.cs @@ -77,7 +77,7 @@ namespace Avalonia.Skia if (height < 1) throw new ArgumentException("Height can't be less than 1", nameof(height)); - return new BitmapImpl(width, height); + return new BitmapImpl(width, height, dpiX, dpiY); } public virtual IRenderTarget CreateRenderTarget(IEnumerable surfaces) @@ -90,7 +90,7 @@ namespace Avalonia.Skia public IWritableBitmapImpl CreateWritableBitmap(int width, int height, PixelFormat? format = null) { - return new BitmapImpl(width, height, format); + return new BitmapImpl(width, height, 96, 96, format); } } }