How to draw rotated text in SkiaSharp
.
Currently I'm rotating the SKCanvas
, drawing the text and then rotating it back. But I thought may be there is a more efficient way to do this.
canvas.RotateDegrees(45, 20, 20);
canvas.DrawText("Text", 20, 20, paint);
canvas.RotateDegrees(-45, 20, 20);
That is the correct way (the only way, I think).
It is not that inefficient as you are not really rotating the canvas, but rather adjusting the drawing matrix (an int[9]
array). Under the hood it is doing something like this:
var m = SKMatrix.CreateRotation(45); // simple struct over int[9]
canvas.CurrentMatrix.Concat(m) // simple multiplication
and then when you draw, it it just uses the matrix:
canvas.DrawText(text, matrix);
and when you rotate back, it just does the math again.
Another way is to save the canvas and then restore:
canvas.Save();
canvas.Rotate(45);
canvas.DrawText(text);
canvas.Restore();
This just makes a copy of the current matrix during the save. And when you restore, it just reverts it. This is a "better" way in that you can possible do a series of transformations, without having to reverse.
Or, you can make use of a convenience type:
// auto save
using (new SKAutoCanvasRestore(canvas)) {
// do any transformations
canvas.Rotate(45);
// do serious work
canvas.DrawText(text);
// auto restore, even on exceptions or errors
}
Another, totally different way to draw text, is to draw along a path:
var path = new SKPath();
// create path ...
// draw using path
canvas.DrawText("text", path, hOffset: 0, vOffset: 0, paint);
You can draw text along a path in SkiaSharp, so (for example) to draw text diagonally across an image:
using (SKPaint skPaint = new SKPaint())
{
SKPath path = new SKPath();
path.MoveTo(original.Width / 10, original.Height - original.Height / 10);
path.LineTo(original.Width - original.Width / 10, original.Height / 10);
canvas.DrawTextOnPath(textToWrite, path, 0, 0, skPaint);
path.Dispose();
}
use MeasureText to get the length of the text and use that to fit it in the centre either by working out the length of the diagonal path and setting the startpoint value in DrawTextOnPath parameters or setting the path origin other than 0,0 (as I do in the example)
I'm not sure if it is more efficient than rotating the canvas though, but it seems a more 'obvious' way of doing the drawing.