Last time, we converted a WIC bitmap to a Windows Runtime SoftwareBitmap by copying the pixels of the WIC bitmap directly into the SoftwareBitmap. But you don’t even have to copy pixels at all!
The ISoftwareBitmapNativeFactory::
method gives you a direct transfer of a IWICBitmap
into a SoftwareBitmap
.
#include <windows.graphics.imaging.interop.h> winrt::SoftwareBitmap ToSoftwareBitmap(IWICBitmap* wicBitmap) { winrt::SoftwareBitmap bitmap{ nullptr }; auto native = winrt::create_instance< ISoftwareBitmapNativeFactory>( CLSID_SoftwareBitmapNativeFactory); winrt::check_hresult(native->CreateFromWICBitmap( wicBitmap, true, winrt::guid_of<winrt::SoftwareBitmap>(), winrt::put_abi(bitmap))); return bitmap; }
First, we create a null SoftwareBitmap
that will hold the result.
Next, we ask for the ISoftwareBitmapNativeFactory
interface from a SoftwareBitmapNativeFactory
.
Finally, we call the CreateFromWICBitmap
method to transmogrify the wicBitmap
into a SoftwareBitmap
, saying that the resulting bitmap is read-only (true
).
And then we return the resulting bitmap.
The SoftwareBitmap
doesn’t make a copy of the IWICBitmap
. It just copies the reference. As a result, no pixels are copied at all!
Since the SoftwareBitmap
has a reference to the original IWICBitmap
, you have two usage patterns.
If you are “giving away” the IWICBitmap
, then you can pass forceReadOnly = false
to make the resulting SoftwareBitmap
read-write. The SoftwareBitmap
now owns the IWICBitmap
and may choose to modify it.
If you are sharing the IWICBitmap
, then pass forceReadOnly = true
to make the resulting SoftwareBitmap
read-only. That way, the SoftwareBitmap
won’t make changes to the IWICBitmap
.
If your IWICBitmap
is a no-cache bitmap created from a IWICBitmapSource
, then you need to pass forceReadOnly = true
because the pixels are being generated on the fly and there is no buffer to modify.
I wrote out the above sequence in multiple steps, but you can collapse it into a one-liner:
winrt::SoftwareBitmap ToSoftwareBitmap(IWICBitmap* wicBitmap) { return winrt::capture( winrt::create_instance <ISoftwareBitmapNativeFactory> (CLSID_SoftwareBitmapNativeFactory), &ISoftwareBitmapNativeFactory::CreateFromWICBitmap, wicBitmap, false); }
Note that this call will fail if the IWICBitmap
is in a format not supported by SoftwareBitmap
.
Bonus chatter: A SoftwareBitmap
can have an IWICBitmap
inside it, or it can have a IMF2DBuffer
inside (for video formats like NV12). If you have a SoftwareBitmap
, you can reach inside and access the inner bitmap buffer by using ISoftwareBitmapNative::
.
This looks like something that can easily be googled. Indeed, the Microsoft Docs page of CreateFromWICBitmap shows up as the literal first result when googling the keywords
windows.graphics.imaging.softwarebitmap iwicbitmap
. I guess the mini-series is intended to showcase the multiple ways you can create aSoftwareBitmap
, but it still feels a bit silly.The documentation somewhat misleadingly says “Creates an *ISoftwareBitmapNative* from the provided IWICBitmap.” So you’ll read the description and say, “That’s not what I want. I want a SoftwareBitmap, not an ISoftwareBitmapNative.” Believe it or not, this sequence was based on an actual customer asking how to create a SoftwareBitmap and trying out all sorts of things without ever considering CreateFromWICBitmap. Sorry you didn’t enjoy the trip.
Yeah, I reckon Raymond is running out of material. Telling us three ways not to do something, before telling us the obviously best way, fills a lot more pages.
Or there is a much simpler and logical explanation.
For example, suppose you don’t get the bitmap through WIC, how would you load it? This series showed the other ways of loading information into a bitmap.