I am using Maui and library CSharpMath.SkiaSharp and MathPainter from there too create latex formulas. I have an editor where the user enters latex. Using MathPainter, I draw the latex formula as a stream and show it to the user in real time with a picture, the source of this picture changes as soon as the formula changes. It looks something like this:
MathPainter mathPainter = new() {FontSize = 25};
private void EditorTextChanged(object sender, EventArgs e)
{
string formula = e.NewTextValue;
mathPainter.LaTeX = formula;
LatexImage.Source = ImageSource.FromStream(() => mathPainter.DrawAsStream())
}
Then, when the user is done and clicks the button, I get the picture again as a stream and save it in the place I need. Sometimes it works as expected, but most of the time I just get the "Canvas trying to draw too large bitmap" exception and the application crashes. How can I fix this problem?
Ok, here we go:
This is the source code of DrawAsStream:
public static System.IO.Stream? DrawAsStream<TContent>
(this Painter<SKCanvas, TContent, SKColor> painter,
float textPainterCanvasWidth = TextPainter.DefaultCanvasWidth,
TextAlignment alignment = TextAlignment.TopLeft,
SKEncodedImageFormat format = SKEncodedImageFormat.Png,
int quality = 100) where TContent : class {
var size = painter.Measure(textPainterCanvasWidth).Size;
// SKSurface does not support zero width/height. Null will be returned from SKSurface.Create.
if (size.Width is 0) size.Width = 1;
if (size.Height is 0) size.Height = 1;
using var surface = SKSurface.Create(new SKImageInfo((int)size.Width, (int)size.Height));
painter.Draw(surface.Canvas, alignment);
using var snapshot = surface.Snapshot();
return snapshot.Encode(format, quality).AsStream();
}
This line here:
var size = painter.Measure(textPainterCanvasWidth).Size;
Returns the same result over and over. (This textPainterCanvasWidth says "UNUSED")
So, what do we do? We copy this method and write our own:
Stream GetStream(MathPainter painter)
{
var size = painter.Measure(100).Size; //This returns the same
size.Width = 300;
size.Height = 300;
if (size.Width is 0) size.Width = 1;
if (size.Height is 0) size.Height = 1;
using var surface = SKSurface.Create(new SKImageInfo((int)size.Width, (int)size.Height));
painter.Draw(surface.Canvas, CSharpMath.Rendering.FrontEnd.TextAlignment.Center);
using var snapshot = surface.Snapshot();
return snapshot.Encode(SKEncodedImageFormat.Png, 100).AsStream();
}
And override the Width and Height to 300 in it.
In the XAML we have:
<Image x:Name="myImage" Aspect="AspectFit" WidthRequest="500" HeightRequest="500"/>
And in the code:
myImage.Source = ImageSource.FromStream(() => GetStream(mathPainter));
It works on my side, more or less.