diff --git a/Source/OxyPlot.Maui.Skia/OxyPlot.Maui.Skia.csproj b/Source/OxyPlot.Maui.Skia/OxyPlot.Maui.Skia.csproj index 9b271a6..0891f67 100644 --- a/Source/OxyPlot.Maui.Skia/OxyPlot.Maui.Skia.csproj +++ b/Source/OxyPlot.Maui.Skia/OxyPlot.Maui.Skia.csproj @@ -36,8 +36,8 @@ - - + + diff --git a/Source/OxyPlot.Maui.Skia/SkiaRenderContext.cs b/Source/OxyPlot.Maui.Skia/SkiaRenderContext.cs index 0c0f383..8bc5a48 100644 --- a/Source/OxyPlot.Maui.Skia/SkiaRenderContext.cs +++ b/Source/OxyPlot.Maui.Skia/SkiaRenderContext.cs @@ -17,6 +17,7 @@ internal class SkiaRenderContext : IRenderContext, IDisposable private readonly Dictionary shaperCache = new(); private readonly Dictionary typefaceCache = new(); private SKPaint paint = new(); + private SKFont font = new(); private SKPath path = new(); /// @@ -130,7 +131,7 @@ public void DrawImage( double destWidth, double destHeight, double opacity, - bool interpolate) + bool interpolate = false) { if (source == null) { @@ -138,13 +139,22 @@ public void DrawImage( } var bytes = source.GetData(); - var image = SKBitmap.Decode(bytes); + var bmp = SKBitmap.Decode(bytes); var src = new SKRect((float)srcX, (float)srcY, (float)(srcX + srcWidth), (float)(srcY + srcHeight)); var dest = new SKRect(this.Convert(destX), this.Convert(destY), this.Convert(destX + destWidth), this.Convert(destY + destHeight)); - var paint = this.GetImagePaint(opacity, interpolate); - this.SkCanvas.DrawBitmap(image, src, dest, paint); + var paint = this.GetImagePaint(opacity); + if (interpolate) + { + var sampling = new SKSamplingOptions(SKFilterMode.Linear, SKMipmapMode.Linear); + var img = SKImage.FromBitmap(bmp); + this.SkCanvas.DrawImage(img, src, dest, sampling, paint); + } + else + { + this.SkCanvas.DrawBitmap(bmp, src, dest, paint); + } } /// @@ -364,14 +374,15 @@ public void DrawText( return; } - var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper); + var font = this.GetTextFont(fontFamily, fontSize, fontWeight, out var shaper); + var paint = this.GetTextPaint(); paint.Color = fill.ToSKColor(); var x = this.Convert(p.X); var y = this.Convert(p.Y); var lines = StringHelper.SplitLines(text); - var lineHeight = paint.GetFontMetrics(out var metrics); + var lineHeight = font.GetFontMetrics(out var metrics); var deltaY = verticalAlignment switch { @@ -389,7 +400,7 @@ public void DrawText( { if (this.UseTextShaping) { - var width = this.MeasureText(line, shaper, paint); + var width = this.MeasureText(line, shaper, font); var deltaX = horizontalAlignment switch { HorizontalAlignment.Left => 0, @@ -398,12 +409,11 @@ public void DrawText( _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment)) }; - this.paint.TextAlign = SKTextAlign.Left; - this.SkCanvas.DrawShapedText(shaper, line, deltaX, deltaY, paint); + this.SkCanvas.DrawShapedText(shaper, line, deltaX, deltaY, SKTextAlign.Left, font, paint); } else { - paint.TextAlign = horizontalAlignment switch + var align = horizontalAlignment switch { HorizontalAlignment.Left => SKTextAlign.Left, HorizontalAlignment.Center => SKTextAlign.Center, @@ -411,7 +421,7 @@ public void DrawText( _ => throw new ArgumentOutOfRangeException(nameof(horizontalAlignment)) }; - this.SkCanvas.DrawText(line, 0, deltaY, paint); + this.SkCanvas.DrawText(line, 0, deltaY, align, font, paint); } deltaY += lineHeight; @@ -427,9 +437,10 @@ public OxySize MeasureText(string text, string fontFamily = null, double fontSiz } var lines = StringHelper.SplitLines(text); - var paint = this.GetTextPaint(fontFamily, fontSize, fontWeight, out var shaper); - var height = paint.GetFontMetrics(out _) * lines.Length; - var width = lines.Max(line => this.MeasureText(line, shaper, paint)); + var font = this.GetTextFont(fontFamily, fontSize, fontWeight, out var shaper); + var paint = this.GetTextPaint(); + var height = font.GetFontMetrics(out _) * lines.Length; + var width = lines.Max(line => this.MeasureText(line, shaper, font)); return new OxySize(this.ConvertBack(width), this.ConvertBack(height)); } @@ -739,12 +750,10 @@ private SKPaint GetFillPaint(OxyColor fillColor, EdgeRenderingMode edgeRendering /// This modifies and returns the local instance. /// /// The opacity. - /// A value indicating whether interpolation should be used. /// The paint. - private SKPaint GetImagePaint(double opacity, bool interpolate) + private SKPaint GetImagePaint(double opacity) { this.paint.Color = new SKColor(0, 0, 0, (byte)(255 * opacity)); - this.paint.FilterQuality = interpolate ? SKFilterQuality.High : SKFilterQuality.None; this.paint.IsAntialias = true; return this.paint; } @@ -833,17 +842,17 @@ private SKPaint GetStrokePaint(OxyColor strokeColor, double strokeThickness, Edg } /// - /// Gets a containing information needed to render text. + /// Gets a containing information needed to render text. /// /// - /// This modifies and returns the local instance. + /// This modifies and returns the local instance. /// /// The font family. /// The font size. /// The font weight. /// The font shaper. - /// The paint. - private SKPaint GetTextPaint(string fontFamily, double fontSize, double fontWeight, out SKShaper shaper) + /// The font. + private SKFont GetTextFont(string fontFamily, double fontSize, double fontWeight, out SKShaper shaper) { var fontDescriptor = new FontDescriptor(fontFamily, fontWeight); if (!this.typefaceCache.TryGetValue(fontDescriptor, out var typeface)) @@ -865,12 +874,24 @@ private SKPaint GetTextPaint(string fontFamily, double fontSize, double fontWeig shaper = null; } - this.paint.Typeface = typeface; - this.paint.TextSize = this.Convert(fontSize); + this.font.Typeface = typeface; + this.font.Size = this.Convert(fontSize); + this.font.Hinting = this.RendersToScreen ? SKFontHinting.Full : SKFontHinting.None; + this.font.Subpixel = this.RendersToScreen; + return this.font; + } + + /// + /// Gets a containing information needed to render text. + /// + /// + /// This modifies and returns the local instance. + /// + /// The paint. + private SKPaint GetTextPaint() + { this.paint.IsAntialias = true; this.paint.Style = SKPaintStyle.Fill; - this.paint.HintingLevel = this.RendersToScreen ? SKPaintHinting.Full : SKPaintHinting.NoHinting; - this.paint.SubpixelText = this.RendersToScreen; return this.paint; } @@ -879,36 +900,37 @@ private SKPaint GetTextPaint(string fontFamily, double fontSize, double fontWeig /// /// The text to measure. /// The text shaper. - /// The paint. + /// The font. /// The width of the text when rendered using the specified shaper and paint. - private float MeasureText(string text, SKShaper shaper, SKPaint paint) + private float MeasureText(string text, SKShaper shaper, SKFont font) { if (!this.UseTextShaping) { - return paint.MeasureText(text); + return font.MeasureText(text); } // we have to get a bit creative here as SKShaper does not offer a direct overload for this. // see also https://github.com/mono/SkiaSharp/blob/master/source/SkiaSharp.HarfBuzz/SkiaSharp.HarfBuzz.Shared/SKShaper.cs using var buffer = new HarfBuzzSharp.Buffer(); - switch (paint.TextEncoding) - { - case SKTextEncoding.Utf8: - buffer.AddUtf8(text); - break; - case SKTextEncoding.Utf16: - buffer.AddUtf16(text); - break; - case SKTextEncoding.Utf32: - buffer.AddUtf32(text); - break; - default: - throw new NotSupportedException("TextEncoding is not supported."); - } + + // switch (paint.TextEncoding) + // { + // case SKTextEncoding.Utf8: + buffer.AddUtf8(text); + // break; + // case SKTextEncoding.Utf16: + // buffer.AddUtf16(text); + // break; + // case SKTextEncoding.Utf32: + // buffer.AddUtf32(text); + // break; + // default: + // throw new NotSupportedException("TextEncoding is not supported."); + // } buffer.GuessSegmentProperties(); - shaper.Shape(buffer, paint); - return buffer.GlyphPositions.Sum(gp => gp.XAdvance) * paint.TextSize / 512; + shaper.Shape(buffer, font); + return buffer.GlyphPositions.Sum(gp => gp.XAdvance) * font.Size / 512; } ///