Правильный способ вывода неуправляемого растрового изображения на экран

#c# #xaml #user-interface #bitmap #uwp

#c# #xaml #Пользовательский интерфейс #Растровое изображение #uwp

Вопрос:

Я занят созданием представления xaml для вывода растрового изображения из неуправляемого кода на экран — с использованием Canvas фона Brush . Есть несколько вещей, в которых я не уверен (тем более, что документы минимальны / отсутствуют).

Я использую SkiaSharp для рисования, поэтому блок памяти должен быть доступен в неуправляемой памяти, и я хочу избежать копирования туда и обратно.

Я нашел несколько способов сделать это, но я не уверен в работе фреймворка, чтобы знать, правильно ли я это сделал. Первый способ — использовать a byte[] и a WriteableBitmap :

 int width, height, length = ...;

// create the bits (once off)
byte[] pixels = new byte[length];
GCHandle buff = GCHandle.Alloc(pixels, GCHandleType.Pinned);
WriteableBitmap bitmap = new WriteableBitmap(width, height);
this.Background = new ImageBrush { ImageSource = bitmap };

// draw (in a game loop)
DrawUsingSkiaSharp(buff.AddrOfPinnedObject());

// update the UI
var stream = bitmap.PixelBuffer.AsStream();
stream.Seek(0, SeekOrigin.Begin);
stream.Write(pixels, 0, pixels.Length);
bitmap.Invalidate();
  

Это работает нормально, и я копирую только «один раз» за кадр. Кроме того, я могу рисовать на одном и том же изображении, а растровое изображение действует как двойной буфер. Но, bitmap.Invalidate получается ли в результате вторая копия на экран?

Я обнаружил, что я SoftwareBitmap тоже могу использовать:

 // create
SoftwareBitmap bitmap = new SoftwareBitmap(
    BitmapPixelFormat.Bgra8, 
    width, height, 
    BitmapAlphaMode.Premultiplied);

// draw
using (var buffer = bitmap.LockBuffer(BitmapBufferAccessMode.ReadWrite))
using (var bufferRef = buffer.CreateReference())
{
    byte* b;
    uint capacity;
    ((IMemoryBufferByteAccess)bufferRef).GetBuffer(out b, out capacity);
    DrawUsingSkiaSharp(b);
}

// update
var source = new SoftwareBitmapSource();
this.Background = new ImageBrush { };
var action = source.SetBitmapAsync(bitmap);
action.Completed = (asyncInfo, asyncStatus) {
    ((ImageBrush)this.Background).ImageSource = source;
};
  

Но как только я назначил растровое изображение кисти, я не могу рисовать на нем снова (создает блокировочный буфер). Способ обойти это — создать второе растровое изображение и скопировать его. Но является ли это улучшением WriteableBitmap — особенно теперь мне приходится иметь дело с асинхронными сложностями? Что SetBitmapAsync на самом деле делает и почему оно асинхронное? Разве источник не может просто прочитать его — или здесь тоже есть копия?

Есть ли третий и лучший способ, должен ли я использовать один или другой, или есть другой способ сделать это? Например, не использовать кисть и рисовать непосредственно на Canvas (или есть лучший контроль)

Кроме того, как правильно использовать SoftwareBitmap и SoftwareBitmapSource при рисовании с использованием игрового цикла?

Так много вариантов и никакой документации! 🙂

Комментарии:

1. Хотя в этом пакете nuget отсутствует документ, вы все равно можете провести некоторые исследования по некоторым вопросам, например, почему метод является асинхронным, попробуйте поискать его в Google. Вы уже проверили пример SkiaSharp ? Вы разрабатывали приложение uwp? Поскольку ваших вопросов слишком много и у них нет центральной темы, поэтому он может потратить больше времени на то, чтобы ответить вам.