Say you have produced a bitmap with the Windows Imaging Component, also known as WIC, and you want to convert it to a Windows Runtime SoftwareÂBitmap
, say, because you want to use it as a XAML SoftwareÂBitmapÂSource
so you can display it in a XAML BitmapImage
.
We’ll be trying to solve this problem over the next few days, coming up with simpler and simpler solutions, until we get down to a one-liner. But let’s not get ahead of ourselves.
Well, let’s see. There are only a few Windows Runtime methods that produce a SoftwareÂBitmap
. There are some conversion methods on SoftwareÂBitmap
itself, but they assume you already have a SoftwareÂBitmap
. Fortunately, there’s also BitmapÂDecoder
.
So you might come up with this:
namespace winrt { using namespace winrt::Windows::Foundation; using namespace winrt::Windows::Graphics::Imaging; using namespace winrt::Windows::Storage::Streams; } winrt::IAsyncOperation<winrt::SoftwareBitmap> ToSoftwareBitmap(IWICBitmapSource* wicBitmap) { // Boilerplate code to save the bitmap as a PNG stream winrt::com_ptr<::IStream> stream; winrt::check_hresult( CreateStreamOnHGlobal(nullptr, TRUE, stream.put())); auto bitmapEncoder = winrt::create_instance< IWICBitmapEncoder>(CLSID_WICPngEncoder); winrt::check_hresult(bitmapEncoder->Initialize( stream.get(), WICBitmapEncoderNoCache)); winrt::com_ptr<IWICBitmapFrameEncode> frameEncoder; winrt::check_hresult(bitmapEncoder->CreateNewFrame( frameEncoder.put(), nullptr)); winrt::check_hresult(frameEncoder->Initialize(nullptr)); winrt::check_hresult(frameEncoder->WriteSource( wicBitmap, nullptr)); winrt::check_hresult(frameEncoder->Commit()); winrt::check_hresult(bitmapEncoder->Commit()); // Rewind the stream so we can load it into a BitmapDecoder winrt::check_hresult(stream->Seek( { 0, 0 }, STREAM_SEEK_SET, nullptr)); // Convert to a Windows Runtime RandomAccessStream. auto randomAccessStream = winrt::capture< winrt::IRandomAccessStream>( CreateRandomAccessStreamOverStream, stream.get(), BSOS_DEFAULT); // Convert the stream to a SoftwareBitmap. auto decoder = co_await winrt::BitmapDecoder::CreateAsync( randomAccessStream); co_return co_await decoder.GetSoftwareBitmapAsync(); }
This is very straightforward, but quite cumbersome. And you might feel a littly icky that you’re encoding the bitmap as a PNG, only to immediately decode it back into a bitmap. Plus there’s the complication that the Windows Runtime BitmapDecoder
decodes asynchronously, so you have to do coroutine stuff to get the answer out.
Fortunately, there’s a better way. We’ll look at it next time.
0 comments