I am trying to re-purpose an example from GitHub that deals with cropping an image with SkiaSharp. Specifically, I have a 4096x4096 sprite sheet from which I'd like to extract a sub-image (a specific sprite, if you will). To do that, I use the following snippet (where spriteContent
is a byte array of the PNG image - byte[]
):
var gch = GCHandle.Alloc(spriteContent, GCHandleType.Pinned);
try
{
var addr = gch.AddrOfPinnedObject();
using var pixmap = new SkiaSharp.SKPixmap(info, addr);
SkiaSharp.SKRectI rectI = new SkiaSharp.SKRectI(0, 0, 256, 256);
var subset = pixmap.ExtractSubset(rectI);
using var data = subset.Encode(SkiaSharp.SKPngEncoderOptions.Default)
File.WriteAllBytes("test2.png", data.ToArray());
}
finally
{
gch.Free();
}
The output of this code is, however, this kind of image:
Seems like an odd output. I suspect that I am doing something funky with teh SKRectI
declaration, where the true rectangle is never used. What I understand it to be doing is create a rectangle from point 0 on top, 0 on bottom, 256 pixels tall, 256 pixels wide (i.e., manage the selection). If I adjust this to, let's say:
SkiaSharp.SKRectI rectI = new SkiaSharp.SKRectI(256, 256, 256, 256);
I get a NullReferenceException
and there is nothing in the subset, so I must be misinterpreting how the rectangle selector works.
Any thoughts on what I might be doing wrong here?
The noise you get is caused by the fact, that you reinterpret raw encoded png bytes as pixel data. You need to decode the image first:
using var skBitmap = SKBitmap.Decode(spriteContent);
using var pixmap = new SKPixmap(skBitmap.Info, skBitmap.GetPixels());
SkiaSharp.SKRectI rectI = new SkiaSharp.SKRectI(0, 0, 256, 256);
var subset = pixmap.ExtractSubset(rectI);
using var data = subset.Encode(SkiaSharp.SKPngEncoderOptions.Default);
File.WriteAllBytes(@"test2.png", data.ToArray());