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.