#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? Поскольку ваших вопросов слишком много и у них нет центральной темы, поэтому он может потратить больше времени на то, чтобы ответить вам.