如何将Lumia :: Imaging :: Bitmap指向C ++中的字节缓冲区?

时间:2015-11-04 16:27:10

标签: c++-cx lumia-imaging-sdk

对于某些上下文,我们有一个包含三个项目的Visual Studio解决方案。主项目是一个C#应用程序,我们有一个C ++库,它本质上是一个图像渲染管道,我们有一个c ++ / cx WinRT组件作为两者之间的桥梁。

我们将一些图像过滤器链(在C ++库中)卸载到c ++ / cx WinRT项目中的Lumia Imaging SDK。由于我们正在使用字节缓冲区,因此我们不确定如何在不进行复制的情况下将Lumia :: Imaging :: Bitmap ^指向缓冲区。 (我们无法在uchar *(即我们的字节数组)上调用AsBuffer(),因为我们在C ++版本中无法使用该扩展方法。)

所以问题是:给某个实现Lumia过滤器链的方法输入uchar *,我们如何创建一个不会导致复制缓冲区的Bitmap(或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); 
}

1 个答案:

答案 0 :(得分:2)

好的,所以这里有一些黑客攻击我们没做到我们需要的东西,因为它创建了一个副本:

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上这篇文章的帮助:

https://social.msdn.microsoft.com/Forums/en-US/816e5718-224d-4bb7-bf06-230e9c6cda5b/how-to-create-an-ibuffer-from-scratch?forum=winappswithnativecode

以下是我们对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;
};

我们使用interop来创建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);
}

希望这对某人有帮助!