如何在 C++ 中将 Lumia::Imaging::Bitmap 指向字节缓冲区?
How do I point a Lumia::Imaging::Bitmap at a byte buffer in C++?
对于某些上下文,我们有一个包含三个项目的 Visual Studio 解决方案。主要项目是一个 C# 应用程序,我们有一个本质上是图像渲染管道的 C++ 库,我们有一个 c++/cx WinRT 组件作为两者之间的桥梁。
我们正在将一些图像过滤器链(在 C++ 库中)卸载到 c++/cx WinRT 项目中的 Lumia Imaging SDK。由于我们正在使用字节缓冲区,因此我们不确定如何在不进行复制的情况下将 Lumia::Imaging::Bitmap^ 指向我们的缓冲区。 (我们不能在 uchar*(即我们的字节数组)上调用 AsBuffer(),因为在 C++ 领域我们无法使用该扩展方法。)
所以问题是这样的:给一些将实现 Lumia 滤镜链的方法输入 uchar*,我们如何创建不会导致复制的位图(或 BitmapImageSource)缓冲区?
下面是一些我们需要填空的示例代码:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
IBuffer^ byteBuffer = ..... ????
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
好吧,我们做了一些黑客攻击,但没有达到我们的需要,因为它创建了一个副本:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
DataWriter^ writer = ref new DataWriter();
Platform::ArrayReference<uchar, 1> tempArray(imageBytes, imageWidth * imageHeight * 4);
writer->WriteBytes(tempArray);
IBuffer^ byteBuffer = writer->DetachBuffer();
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
但经过深思熟虑,我们决定尝试使用我们自己的实现子类化 IBuffer。感谢 jmorrill 在 MSDN 上对这个 post 的帮助:
这是我们对 IBuffer 的实现:
class ImageBuffer : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::IBufferByteAccess >
{
public:
virtual ~ImageBuffer()
{
}
STDMETHODIMP RuntimeClassInitialize(UINT totalSize, UCHAR* data)
{
_imageLength = totalSize;
_imageData = data;
return S_OK;
}
STDMETHODIMP Buffer( byte **value)
{
*value = &_imageData[0];
return S_OK;
}
STDMETHODIMP get_Capacity(UINT32 *value)
{
*value = _imageLength;
return S_OK;
}
STDMETHODIMP get_Length(UINT32 *value)
{
*value = _imageLength;
return S_OK;
}
STDMETHODIMP put_Length(UINT32 value)
{
if(value > _imageLength)
return E_INVALIDARG;
_imageLength = value;
return S_OK;
}
private:
UINT32 _imageLength;
UCHAR *_imageData;
};
我们使用互操作来创建 ImageBuffer 实例:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
ComPtr<ImageBuffer> imageBuffer;
MakeAndInitialize<ImageBuffer>(&imageBuffer, imageWidth * imageHeight * channels, imageBytes);
auto iinspectable = (IInspectable*)reinterpret_cast<IInspectable*>(imageBuffer.Get());
IBuffer^ byteBuffer = reinterpret_cast<IBuffer^>(iinspectable);
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
希望对大家有所帮助!
对于某些上下文,我们有一个包含三个项目的 Visual Studio 解决方案。主要项目是一个 C# 应用程序,我们有一个本质上是图像渲染管道的 C++ 库,我们有一个 c++/cx WinRT 组件作为两者之间的桥梁。
我们正在将一些图像过滤器链(在 C++ 库中)卸载到 c++/cx WinRT 项目中的 Lumia Imaging SDK。由于我们正在使用字节缓冲区,因此我们不确定如何在不进行复制的情况下将 Lumia::Imaging::Bitmap^ 指向我们的缓冲区。 (我们不能在 uchar*(即我们的字节数组)上调用 AsBuffer(),因为在 C++ 领域我们无法使用该扩展方法。)
所以问题是这样的:给一些将实现 Lumia 滤镜链的方法输入 uchar*,我们如何创建不会导致复制的位图(或 BitmapImageSource)缓冲区?
下面是一些我们需要填空的示例代码:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
IBuffer^ byteBuffer = ..... ????
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
好吧,我们做了一些黑客攻击,但没有达到我们的需要,因为它创建了一个副本:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
DataWriter^ writer = ref new DataWriter();
Platform::ArrayReference<uchar, 1> tempArray(imageBytes, imageWidth * imageHeight * 4);
writer->WriteBytes(tempArray);
IBuffer^ byteBuffer = writer->DetachBuffer();
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
但经过深思熟虑,我们决定尝试使用我们自己的实现子类化 IBuffer。感谢 jmorrill 在 MSDN 上对这个 post 的帮助:
这是我们对 IBuffer 的实现:
class ImageBuffer : public Microsoft::WRL::RuntimeClass<
Microsoft::WRL::RuntimeClassFlags< Microsoft::WRL::RuntimeClassType::WinRtClassicComMix >,
ABI::Windows::Storage::Streams::IBuffer,
Windows::Storage::Streams::IBufferByteAccess >
{
public:
virtual ~ImageBuffer()
{
}
STDMETHODIMP RuntimeClassInitialize(UINT totalSize, UCHAR* data)
{
_imageLength = totalSize;
_imageData = data;
return S_OK;
}
STDMETHODIMP Buffer( byte **value)
{
*value = &_imageData[0];
return S_OK;
}
STDMETHODIMP get_Capacity(UINT32 *value)
{
*value = _imageLength;
return S_OK;
}
STDMETHODIMP get_Length(UINT32 *value)
{
*value = _imageLength;
return S_OK;
}
STDMETHODIMP put_Length(UINT32 value)
{
if(value > _imageLength)
return E_INVALIDARG;
_imageLength = value;
return S_OK;
}
private:
UINT32 _imageLength;
UCHAR *_imageData;
};
我们使用互操作来创建 ImageBuffer 实例:
Bitmap^ MyClass::GetBitmapImageDestination(uchar *imageBytes, int imageWidth, int imageHeight, ColorMode colorMode) {
int channels = colorMode == ColorMode::Gray8 ? 1 : 4;
ComPtr<ImageBuffer> imageBuffer;
MakeAndInitialize<ImageBuffer>(&imageBuffer, imageWidth * imageHeight * channels, imageBytes);
auto iinspectable = (IInspectable*)reinterpret_cast<IInspectable*>(imageBuffer.Get());
IBuffer^ byteBuffer = reinterpret_cast<IBuffer^>(iinspectable);
return ref new Bitmap(Windows::Foundation::Size((float)imageWidth, (float)imageHeight), colorMode, (uint)(imageWidth * channels), byteBuffer);
}
希望对大家有所帮助!