Как связать объект Bitmap с ImageSource в WPF?

Как связать указатель на Bitmap с Image элементом WPF, чтобы обновления в Bitmap отображались без конвертации и создания новых объектов, особенно если нужно рендерить 10000 кадров в секунду? Надеялся, что `WritableBitmap` будет хорошим решением, но что-то пошло не так. Как можно правильно настроить это связывание один раз в инициализаторе и не беспокоиться о нем в дальнейшем?
  • 22 июня 2024 г. 12:02
Ответы на вопрос 2
Для связывания объекта Bitmap с элементом Image в WPF и обновления его без конвертации и создания новых объектов, можно воспользоваться классом WriteableBitmap. Данный класс предоставляет возможность изменять пиксели изображения напрямую, что делает его отличным выбором для быстрой и эффективной работы с большим количеством кадров в секунду.

Для этого необходимо создать объект WriteableBitmap и установить его как источник изображения для элемента Image. После этого можно обновлять сам объект WriteableBitmap, и изменения будут отображаться на элементе Image без создания новых объектов.

Пример инициализации и связывания объекта WriteableBitmap с элементом Image:

```csharp
WriteableBitmap writeableBitmap = new WriteableBitmap(width, height, dpiX, dpiY, PixelFormats.Bgr32, null);
image.Source = writeableBitmap;
```

После этого можно обновлять пиксели в объекте WriteableBitmap напрямую:

```csharp
// Получение пиксельных данных из Bitmap
IntPtr buffer = bitmapData.Scan0;
int stride = bitmapData.Stride;
int bytesPerPixel = Bitmap.GetPixelFormatSize(bitmap.PixelFormat) / 8;

// Копирование пиксельных данных в WriteableBitmap
writeableBitmap.Lock();
unsafe
{
    byte* pStart = (byte*)writeableBitmap.BackBuffer;
    byte* pCurrent = pStart;
    
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < width; x++)
        {
            // Копирование пикселя из Bitmap в WriteableBitmap
            // Пример для формата Bgr24
            pCurrent[0] = buffer[(y * stride) + (x * bytesPerPixel) + 2];
            pCurrent[1] = buffer[(y * stride) + (x * bytesPerPixel) + 1];
            pCurrent[2] = buffer[(y * stride) + (x * bytesPerPixel)];
            
            pCurrent += 4; // увеличение указателя на 4 байта, так как формат Bgr32
        }
    }
}
writeableBitmap.AddDirtyRect(new Int32Rect(0, 0, width, height));
writeableBitmap.Unlock();
```

При таком подходе необходимо обращать внимание на правильное копирование пиксельных данных из Bitmap в WriteableBitmap в зависимости от формата изображения. Также следует знать, что данный пример не содержит проверок на выход за границы массива пикселей, что может привести к ошибкам.

Таким образом, связывание объекта WriteableBitmap с элементом Image и обновление его без конвертации и создания новых объектов может быть достигнуто с помощью прямой работы с пикселями изображения через WriteableBitmap.
Если глаз воспринимает только 24 кадра в секунду, то зачем выводить 10000 кадров? Просто скипайте кадры по времени. Выводите один кадр в 40 ms. 
Свой WriteableBitmap сразу в xaml пропишите и в ViewModel просто инициируйте PropertyChanged для этого свойства модели после изменений в Bitmap
Похожие вопросы