mirror of
https://github.com/unclshura/splitter.git
synced 2026-06-21 16:12:01 +00:00
137 lines
3.7 KiB
C#
137 lines
3.7 KiB
C#
using Avalonia;
|
|
using Avalonia.Media.Imaging;
|
|
using Avalonia.Platform;
|
|
|
|
namespace Splitter_UI.Services;
|
|
|
|
public sealed class MatToBitmapConverter(IBufferPool _pool) : IMatToBitmapConverter
|
|
{
|
|
private readonly object _sync = new();
|
|
|
|
public Bitmap Convert(Mat mat, Bitmap? existing = null)
|
|
{
|
|
if (mat.Empty())
|
|
throw new ArgumentException("Mat is empty.", nameof(mat));
|
|
|
|
var w = mat.Width;
|
|
var h = mat.Height;
|
|
var channels = mat.Channels();
|
|
|
|
if (channels != 3 && channels != 4)
|
|
throw new NotSupportedException($"Only 3 or 4 channel Mats are supported. Got {channels}.");
|
|
|
|
lock (_sync)
|
|
{
|
|
var entry = _pool.Get(w, h);
|
|
|
|
var src = mat;
|
|
if (!src.IsContinuous())
|
|
src = src.Clone();
|
|
|
|
unsafe
|
|
{
|
|
var srcPtr = (byte*)src.DataPointer;
|
|
var totalBytes = w * h * channels;
|
|
|
|
if (channels == 3)
|
|
{
|
|
fixed (byte* dstBgr = entry.Bgr)
|
|
{
|
|
Buffer.MemoryCopy(srcPtr, dstBgr, entry.Bgr.Length, totalBytes);
|
|
}
|
|
|
|
ConvertBgrToBgra(entry.Bgr, entry.Bgra, w, h);
|
|
}
|
|
else
|
|
{
|
|
fixed (byte* dstBgra = entry.Bgra)
|
|
{
|
|
Buffer.MemoryCopy(srcPtr, dstBgra, entry.Bgra.Length, totalBytes);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (existing is WriteableBitmap wb &&
|
|
wb.PixelSize.Width == w &&
|
|
wb.PixelSize.Height == h)
|
|
{
|
|
UpdateWriteableBitmap(wb, entry.Bgra, w, h);
|
|
return wb;
|
|
}
|
|
|
|
return CreateBitmap(entry.Bgra, w, h);
|
|
}
|
|
}
|
|
|
|
public Bitmap Convert(byte[] bgr, int width, int height, Bitmap? existing = null)
|
|
{
|
|
var entry = _pool.Get(width, height);
|
|
ConvertBgrToBgra(bgr, entry.Bgra, width, height);
|
|
|
|
if (existing is WriteableBitmap wb &&
|
|
wb.PixelSize.Width == width &&
|
|
wb.PixelSize.Height == height)
|
|
{
|
|
UpdateWriteableBitmap(wb, entry.Bgra, width, height);
|
|
return wb;
|
|
}
|
|
|
|
return CreateBitmap(entry.Bgra, width, height);
|
|
}
|
|
|
|
|
|
private static void ConvertBgrToBgra(byte[] bgr, byte[] bgra, int width, int height)
|
|
{
|
|
var si = 0;
|
|
var di = 0;
|
|
var totalPixels = width * height;
|
|
|
|
for (var i = 0; i < totalPixels; i++)
|
|
{
|
|
bgra[di + 0] = bgr[si + 0];
|
|
bgra[di + 1] = bgr[si + 1];
|
|
bgra[di + 2] = bgr[si + 2];
|
|
bgra[di + 3] = 255;
|
|
|
|
si += 3;
|
|
di += 4;
|
|
}
|
|
}
|
|
|
|
private static unsafe void UpdateWriteableBitmap(WriteableBitmap wb, byte[] bgra, int width, int height)
|
|
{
|
|
using var fb = wb.Lock();
|
|
|
|
var dstPtr = (byte*)fb.Address;
|
|
var dstStride = fb.RowBytes;
|
|
var srcStride = width * 4;
|
|
|
|
fixed (byte* srcPtr = bgra)
|
|
{
|
|
for (var y = 0; y < height; y++)
|
|
{
|
|
var srcRow = srcPtr + y * srcStride;
|
|
var dstRow = dstPtr + y * dstStride;
|
|
|
|
Buffer.MemoryCopy(srcRow, dstRow, dstStride, srcStride);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static unsafe Bitmap CreateBitmap(byte[] bgra, int width, int height)
|
|
{
|
|
var stride = width * 4;
|
|
|
|
fixed (byte* p = bgra)
|
|
{
|
|
return new WriteableBitmap(
|
|
PixelFormat.Bgra8888,
|
|
AlphaFormat.Premul,
|
|
(nint)p,
|
|
new PixelSize(width, height),
|
|
new Vector(96, 96),
|
|
stride);
|
|
}
|
|
}
|
|
}
|