如何使用C++访问WriteableBitmap.PixelBuffer像素?

问题描述 投票:0回答:3

MSDN 上有很多 C# 的示例,但只有一些 C++ 的代码片段。我已经把它放在一起,我认为它会起作用,但我不确定我是否要释放所有必须的 COM 引用。

com windows-runtime winrt-xaml c++-cx
3个回答
5
投票

您的代码是正确的——

IBufferByteAccess
*buffer
接口上的引用计数通过调用
QueryInterface
而增加,并且您必须调用
Release
一次才能释放该引用。

但是,如果你使用

ComPtr<T>
,这就变得更简单了——使用
ComPtr<T>
,你不能调用
IUnknown
的三个成员中的任何一个(
AddRef
Release
QueryInterface
);它会阻止您给他们打电话。相反,它以一种很难把事情搞砸的方式封装了对这些成员函数的调用。下面是一个示例:

// Get the buffer from the WriteableBitmap:
IBuffer^ buffer = bitmap->PixelBuffer;

// Convert from C++/CX to the ABI IInspectable*:
ComPtr<IInspectable> bufferInspectable(AsInspectable(buffer));

// Get the IBufferByteAccess interface:
ComPtr<IBufferByteAccess> bufferBytes;
ThrowIfFailed(bufferInspectable.As(&bufferBytes));

// Use it:
byte* pixels(nullptr);
ThrowIfFailed(bufferBytes->Buffer(&pixels));

bufferInspectable.As(&bufferBytes)
的调用执行安全的
QueryInterface
:它根据
bufferBytes
的类型计算 IID,执行
QueryInterface
,并将结果指针附加到
bufferBytes
。当
bufferBytes
超出范围时,会自动调用
Release
。该代码与您的代码具有相同的效果,但没有容易出错的显式资源管理。

该示例使用以下两个实用程序,有助于保持代码整洁:

auto AsInspectable(Object^ const object) -> Microsoft::WRL::ComPtr<IInspectable>
{
    return reinterpret_cast<IInspectable*>(object);
}

auto ThrowIfFailed(HRESULT const hr) -> void
{
    if (FAILED(hr))
        throw Platform::Exception::CreateException(hr);
}

细心的读者会注意到,由于此代码使用

ComPtr
来代替我们从
IInspectable*
获得的
buffer
,因此与原始代码相比,此代码实际上执行了额外的
AddRef
/
Release
。我认为这种影响性能的可能性很小,最好从易于验证正确的代码开始,然后在了解热点后优化性能。


1
投票

使用 C++/WinRT(而不是 C++/CX)时,有一个更方便(也更危险)的替代方案。语言投影在

data()
接口上生成
IBuffer
辅助函数,该函数将
uint8_t*
返回到内存缓冲区中。

假设

bitmap
WriteableBitmap 类型,代码可以缩减为:

uint8_t* pixels{ bitmap.PixelBuffer().data() };

// *** Do the work on the bytes here ***

// No cleanup required; it has already been dealt with inside data()'s implementation

在代码中,

pixels
是指向由
bitmap
实例控制的数据的原始指针。因此,它仅在
bitmap
存在时才有效,但代码中没有任何内容可以帮助编译器(或读者)跟踪该依赖关系。

作为参考,WriteableBitmap::PixelBuffer文档中有一个

示例
,说明了(否则未记录的)辅助函数的使用
data()


更新:

扩展 Windows 运行时 API 的 C++/WinRT 函数已被记录,包括

IBuffer
接口上的函数。


0
投票

这是我迄今为止尝试过的:

// Get the buffer from the WriteableBitmap
IBuffer^ buffer = bitmap->PixelBuffer;

// Get access to the base COM interface of the buffer (IUnknown)
IUnknown* pUnk = reinterpret_cast<IUnknown*>(buffer);

// Use IUnknown to get the IBufferByteAccess interface of the buffer to get access to the bytes
// This requires #include <Robuffer.h>
IBufferByteAccess* pBufferByteAccess = nullptr;
HRESULT hr = pUnk->QueryInterface(IID_PPV_ARGS(&pBufferByteAccess));

if (FAILED(hr))
{
    throw Platform::Exception::CreateException(hr);
}

// Get the pointer to the bytes of the buffer
byte *pixels = nullptr;
pBufferByteAccess->Buffer(&pixels);

// *** Do the work on the bytes here ***

// Release reference to IBufferByteAccess created by QueryInterface.
// Perhaps this might be done before doing more work with the pixels buffer,
// but it's possible that without it - the buffer might get released or moved
// by the time you are done using it.
pBufferByteAccess->Release();
© www.soinside.com 2019 - 2024. All rights reserved.