dotnet/Microsoft.Maui.Graphics

Canvas: Font property not working for fonts registered with ConfigureFonts

aletfa opened this issue · 2 comments

In a MAUI Canvas try to draw some text with a font registered during the ConfigureFonts startup.

canvas.Font = new Microsoft.Maui.Graphics.Font("Dino");
canvas.DrawString("Hello", 10, 10, HorizontalAlignment.Center);

Expected result:

  • Text rendered with expected Font

Current result:

  • Text rendered with default Font

Hi @aletfa,

Connecting some dots here, this issue is related to or also mentioned in:

We had the same problem i.e. we have to set different Custom Font(s) depending upon some logic, so what I found that the DrawString method doesn't use IFont it uses FontPaint and setting IFont doesn't always override the default FontPaint object.

So I created a workaround,

  • Create a new inherited class from SkiaCanvas e.g. MySkicCanvas
  • Override IFont setter, here set FontPaint object using the Custom Font
  • Create a new inherited class from BitmapExportContext e.g. MyBitmapExportContext
  • in the inherited constructor inject MySkicCanvas while create ScalingCanvas object
  • and while consuming MyBitmapExportContext.Canvas, always set the MyBitmapExportContext.Canvas.Font first then set MyBitmapExportContext.Canvas.FontSize and/or MyBitmapExportContext.Canvas.FontColor

Code snipped is in here
public class MySkiaCanvas : SkiaCanvas { public override IFont Font { set { base.CurrentState.FontPaint = new SKPaint { Color = SKColors.Black, IsAntialias = true, Typeface = SKTypeface.FromFile(value.Name) }; } } }

`
public class MyBitmapExportContext : BitmapExportContext
{
private SKBitmap? _bitmap;
private SKSurface _surface;
private ScalingCanvas _canvas;

    public MyBitmapExportContext(int width, int height, float displayScale) 
        : base(width, height, 72)
    {
        _surface = SKSurface.Create(new SKImageInfo(width, height, SKColorType.Rgba8888, SKAlphaType.Premul));

        _canvas = new ScalingCanvas(new MySkiaCanvas
        {
            Canvas = _surface.Canvas,
            DisplayScale = displayScale
        });
    }

    public override Microsoft.Maui.Graphics.ICanvas Canvas => _canvas;

    public override IImage Image
    {
        get
        {
            return new SkiaImage(Bitmap);
        }   
    }

    public SKBitmap Bitmap
    {
        get
        {
            if (_bitmap == null)
            {
                _bitmap = SKBitmap.Decode(_surface.Snapshot().Encode());
            }

            return _bitmap;
        }
    }

    public override void WriteToStream(Stream stream)
    {
        using var data = _surface.Snapshot().Encode(SKEncodedImageFormat.Png, 100);
        data.SaveTo(stream);
    }

    protected override void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                _surface.Dispose();

                _bitmap?.Dispose();
                _bitmap = null;

                base.Dispose(disposing);

                //we are not setting disposedValue value to true here as its done in the base method
            }
        }        
    }
}

`