Replies: 7 comments 8 replies
-
Hmm, it looks like I can draw a bitmap to a bitmap with an offset using a canvas like this:
Will test tomorrow but looks good :) |
Beta Was this translation helpful? Give feedback.
-
It works as expected but I don't know if this is the right way to go... What would be the best way to draw multiple bitmaps into a big one without messing up the main bitmap? Any suggestions? |
Beta Was this translation helpful? Give feedback.
-
Although Skia is not thread safe, if the destination rectangles don't overlap, you could try to make different destination If the rectangles do overlap, using multiple threads won't work of course... Out of curiosity, why are you using multiple threads for a single drawing? |
Beta Was this translation helpful? Give feedback.
-
I have a big LED-Screen (384x192) which is fed using https://github.com/hzeller/rpi-rgb-led-matrix. Thats all easy as long as only one Task writes to the canvas. But I want to have multiple "layers" to be able to draw different things to different parts of the canvas, for example a scrolltext at 64,32 (x,y), an image to 128,96 and so on. In the main thread, before pushing out the main bitmap to the canvas, I call a method on each "child-canvas' that stops the writing to the corresponding child-canvas, copies the bitmap to the main-bitmap and then releases the lock so the child-canvi could be updated again. This all works but results in heavy flicker and 'jumping' text, as the RPi4 semms to be not fast enough to lock all Tasks that write to the child-bitmap, coyping the child-bitmap to the big bitmap and pushing it out to the LED-Display. I've experimented with some Thread.Sleeps and so on, but thats all crap...Even going one ladder down and using Threads with ManualResetEvents doesn't work well. So I need an ultrafast solution that allows me to write to my child-bitmaps while the 'main' bitmap is constantly pushed out the LED-Matrix. I think you got the point but for completeness here's a small snipped from my main-thread: private void ThreadImplementation()
{
while (true)
{
_mre.Reset();
foreach (var canvas in _canvi)
canvas.PrepareNextFrame();
_mre.Set();
DrawBitmapPixelsToCanvas(_ledMatrix, _mainCanvas, _mainCanvasBitmap);
//DrawBitmapPixelsToCanvasOnlyChangedPixels(_ledMatrix, _mainCanvas, _mainCanvasBitmap);
}
} And the DrawPixels-Method: private static void DrawBitmapPixelsToCanvas(RGBLedMatrix ledMatrix, RGBLedCanvas canvas, SKBitmap bitmap)
{
var pixelAddr = bitmap.GetPixels();
unsafe
{
var ptr = (byte*)pixelAddr.ToPointer();
for (var col = 0; col < bitmap.Height; col++)
for (var row = 0; row < bitmap.Width; row++)
{
var b = *ptr++;
var g = *ptr++;
var r = *ptr++;
ptr++; //Skip alpha
canvas.SetPixel(row, col, new RGBLedMatrixWrapper.Color(r, g, b));
}
}
ledMatrix.SwapOnVsync(canvas);
} And here's the method in the child-canvas class that is called from the '...PrepareNextFrame()'-method: private static void CopyWithOffset(SKBitmap targetBitmap, SKBitmap sourceBitmap, SKPoint targetLocation)
{
using var canvas = new SKCanvas(targetBitmap);
canvas.DrawBitmap(sourceBitmap, targetLocation);
} targetBitmap represents the main 'big' bitmap and sourceBitmap is the smaller child-bitmap that should be written 'into' the targetBitmap at a specific location.
Could you give me an example on how to implement that? Thanks! |
Beta Was this translation helpful? Give feedback.
-
You're right, it IS small but according to the folks using this library it's the highest resolution a single Pi4 can handle with acceptable refresh rate. I built it using 3 chains of 3 128x64 modules. I also set https://github.com/hzeller/rpi-rgb-led-matrix#cpu-use so that the refresh takes place on a dedicated cpu.
That's a discussion I have read many times in the issue-section of the LED-Repo.
I have access to the bindings as they're also in the repo at https://github.com/hzeller/rpi-rgb-led-matrix/tree/master/bindings/c%23 but I'm not skilled enough to rewrite it using unmanaged delegates.
If I throw away all my canvas-logic, even all Skia-related stuff and write directly to the led-matrix using canvas.SetPixel it's blazing fast. public Task DrawScrollText(string text, int xPos, int yPos, int delay, SKColor color, int loops = -1,
CancellationToken ct = default)
{
return Task.Run(() =>
{
var infinite = loops == -1;
var typeFace = SKTypeface.FromFamilyName("Comic Sans MS", SKFontStyleWeight.Thin,
SKFontStyleWidth.Normal, SKFontStyleSlant.Oblique);
using var textPaint = new SKPaint
{
TextSize = 24.0f,
IsAntialias = true,
Color = color,
Typeface = typeFace,
FilterQuality = SKFilterQuality.High,
TextEncoding = SKTextEncoding.Utf16
};
var textWidth = (int) Math.Ceiling(textPaint.MeasureText(text));
using var skCanvas = new SKCanvas(_myBitmap);
while (infinite || loops >= 0)
{
loops--;
for (var i = _myBitmap.Width; i >= -textWidth; i--)
{
_mre.WaitOne();
//skCanvas.Clear(SKColors.Black);
_myBitmap.Erase(SKColors.Black); //<-- This seems to be really inefficient.
skCanvas.DrawText(text, i, yPos, textPaint);
Thread.Sleep(delay);
if (ct.IsCancellationRequested)
{
Console.WriteLine("DrawScrollText-Task canceled.");
throw new OperationCanceledException(ct);
}
}
}
}, ct);
} I need to clear the canvas/bitmap before writing the new text on the next position. This might slow down things and looks inefficient but I don't know another way...
No, I like all glowing things, espcially LEDs...its all just for fun and this problem bugs me a lot :) It's the first time I use Skia as I think it could be working well for this. Thanks for your help! |
Beta Was this translation helpful? Give feedback.
-
You seem to be mixing two different threading models. You use Also, I would not use a For the Skia bits, it might indeed be the case that rendering text is slow on a PI. I would put a StopWatch around it and check. Or, you could start with a simple moving solid color square on a solid color background, and also test changing all the colors of all the pixels every frame, background and foreground, because the |
Beta Was this translation helpful? Give feedback.
-
The Thread.Sleep is for the loop to specify the pause = scrolling speed before the text moves to the next position. If I remove it the text 'rushes' thru the display and is not readable. I don't know how to accomplish this any other way.
You're right, I've experimented with Tasks and Threads, knowing that many Tasks may run on a single Thread but even after changing my Drawing-Methods to use explicit Threads instead of Tasks makes no relevance. As it turns out this is too much advanced stuff for me so I should just stick with a simple blinking LED-Example ;( |
Beta Was this translation helpful? Give feedback.
-
Hi!
I'm new to Skia and try to use it for some pixel-manipulations on my LED-Matrix on a Raspberry Pi.
I would like to know if there's an easy way to copy one (smaller) bitmap into another (larger) bitmap at a given location.
So lets say I have two bitmaps:
var entireBitmap = new SKBitmap(64, 32); var smallBitmap = new SKBitmap(16,8);
Now I want to copy the entire 'smallBitmap' into the 'entireBitmap' at let's say x = 12, y= 18.
I think I could do it using GetPixel and SetPixel but thats slow and needs some calculations so I think maybe theres a better way?!
It should also accept negative location coordinates and tolerate overlapping if the smaller bitmap goes beyond the height or width of the entire bitmap.
Someting like SKBitmap.CopyTo(entireBitmap, smallBitmap, x, y);
Thanks and regards
Jan
Beta Was this translation helpful? Give feedback.
All reactions