C++ WinRT - 画布位图,如何动态创建位图,在其上绘制像素然后显示到屏幕上?



如何:

  1. 动态创建大小为 512x512 的位图。

  2. 位图上用 SetPixel( x, y, color) 等颜色绘制像素;

  3. 显示此位图创建到面板屏幕 ?

来自Win2D Github的作者建议使用CanvasBitmap.SetPixelBytes,显然很难在WinRT中找到C++工作示例,下载的Win2D Gallery源代码及其源代码仅在C#中,我必须将其转换为C++并且没有单像素写入功能。

可能是我是老人们和传统程序员,传统的编码方式是"直接写入屏幕",我发现很多人问过这样的事情,但找不到完整的解决方案,更不用说 WinRT C++的示例源代码。

我暂时不想进入Win2D,DirectX,Unity或任何与GPU或CPU相关的原因。此外,我的COM知识还不存在,看着DirectX模板源代码,已经吓跑了我,尽管我之前在Win32中用DirectX 2D编写过。

我是 WinRT 新手C++,只是想要一个基于上述 3 条语句编写的带有 UWP XAML C++ WinRT 中清晰的示例代码。

解决后,我可以轻松地将我的 3D 知识移植到 WinRT UWP 平台。

任何想法或参考都非常感谢。

请指教。

如前所述,WriteableBitmap 可用于呈现为内存中位图。

有关完整的工作示例,请从"空白应用 (C++/WinRT)"模板开始(称为"可写位图示例">)。这为您提供了一个良好的起点,一个具有单个页面的完整应用程序。

若要设置MainPage以便为位图腾出空间,请在生成的MainPage.xaml文件中使用以下代码:

<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();
}
}

现在进入实现(在主页内.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实现比看起来要慢得多。在PixelBuffer上呼叫data()成员将调用QueryInterfaceAddRefRelease呼叫。对于每个像素。

理想情况下,这应该从异步处理程序调用,但我无法从 UI 线程以外的线程操作WriteableBitmap。这似乎是DependencyObject的限制(参见DependencyObject.Dispatcher),WriteableBitmap从中派生出来。

查看WritableBitmap类,可以直接通过 WritableBitmap.PixelBuffer 属性操作位图的像素。

页面上有一个示例。 在页面的右上角,选择您的首选语言作为C++/WinRT

最新更新