Как уже отмечалось, WriteableBitmap может использоваться для рендеринга в растровое изображение в памяти.
Для полного рабочего примера начните с "Blank App (C ++ /WinRT) " шаблон (назовите его " WriteableBitmapSample ").Это дает вам хорошую отправную точку, полное приложение с одной страницей.
Чтобы настроить MainPage
, чтобы освободить место для растрового изображения, используйте следующий код внутри сгенерированного MainPage.xaml file:
<Page
...
<StackPanel Orientation="Vertical">
<Button x:Name="myButton" Click="ClickHandler" HorizontalAlignment="Stretch">Generate bitmap</Button>
<Image x:Name="myBitmap" Width="512" Height="512" />
</StackPanel>
</Page>
Удалите все, что не нужно, из сгенерированного MainPage.idl :
namespace WriteableBitmapSample
{
[default_interface]
runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
{
MainPage();
}
}
Теперь перейдем к реализации (внутри MainPage.cpp ).Большая часть этого реализована в ClickHandler
с глобальным SetPixel
помощником:
#include "pch.h"
#include "MainPage.h"
#include "MainPage.g.cpp"
#include <winrt/Windows.UI.Core.h>
#include <winrt/Windows.UI.Xaml.Media.Imaging.h>
#include <winrt/Windows.UI.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Media::Imaging;
namespace
{
void SetPixel(WriteableBitmap const& bitmap, int32_t const x, int32_t const y, Color const col)
{
auto w { bitmap.PixelWidth() };
// Get pointer to in-memory buffer
auto p { bitmap.PixelBuffer().data() };
// Calculate memory offset (4 bytes per pixel)
auto offset { w * y * 4 + x * 4 };
// Write pixel
auto pixel_address { p + offset };
*(pixel_address + 0) = col.B;
*(pixel_address + 1) = col.G;
*(pixel_address + 2) = col.R;
*(pixel_address + 3) = col.A;
}
} // namespace
namespace winrt::WriteableBitmapSample::implementation
{
MainPage::MainPage() { InitializeComponent(); }
void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
// Create bitmap
auto const width { 512 };
auto const height { 512 };
auto bitmap { WriteableBitmap(width, height) };
// Construct gradient bitmap
for (int32_t x = 0; x < width; ++x)
{
for (int32_t y = 0; y < height; ++y)
{
SetPixel(bitmap, x, y, ColorHelper::FromArgb(255, 255, x / 2, y / 2));
}
}
// Set image source for the XAML interface
myBitmap().Source(bitmap);
}
} // namespace winrt::WriteableBitmapSample::implementation
Обратите особое внимание, что реализация SetPixel
намного медленнее, чем кажется.Вызов члена data()
на PixelBuffer
вызывает вызов QueryInterface
, AddRef
и Release
.Для каждого пикселя.
В идеале это следует вызывать из асинхронного обработчика, но я не смог манипулировать WriteableBitmap
из потока, отличного от потока пользовательского интерфейса.Похоже, что это ограничение DependencyObject
(см. DependencyObject.Dispatcher ), из которого WriteableBitmap
происходит.