{"id":108044,"date":"2023-04-12T07:00:00","date_gmt":"2023-04-12T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=108044"},"modified":"2023-04-12T12:06:48","modified_gmt":"2023-04-12T19:06:48","slug":"20230412-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230412-00\/?p=108044","title":{"rendered":"How can I convert a WIC bitmap to a Windows Runtime SoftwareBitmap? part 2: Via a buffer"},"content":{"rendered":"<p>Last time, we converted a WIC bitmap to a Windows Runtime SoftwareBitmap <a title=\"How can I convert a WIC bitmap to a Windows Runtime SoftwareBitmap? part 1: Via an encoded stream\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20230411-00\/?p=108037\"> by encoding the WIC bitmap to a stream, then decoding it back into a SoftwareBitmap<\/a>. But you don&#8217;t have to pass the pixels through a stream. The <code>SoftwareBitmap<\/code> lets you pass the pixels directly in the form of an <code>IBuffer<\/code>.<\/p>\n<pre>winrt::SoftwareBitmap ToSoftwareBitmap(IWICBitmapSource* wicBitmap)\r\n{\r\n    \/\/ Look up the Windows Runtime pixel format and alpha mode.\r\n    WICPixelFormatGUID format;\r\n    winrt::check_hresult(wicBitmap-&gt;GetPixelFormat(&amp;format));\r\n\r\n    static struct Mapping\r\n    {\r\n        WICPixelFormatGUID const&amp; format;\r\n        int bytesPerPixel;\r\n        winrt::BitmapPixelFormat pixelFormat;\r\n        winrt::BitmapAlphaMode alphaMode;\r\n    } const mappings[] = {\r\n        {\r\n            GUID_WICPixelFormat32bppPRGBA,\r\n            4,\r\n            winrt::BitmapPixelFormat::Rgba8,\r\n            winrt::BitmapAlphaMode::Premultiplied\r\n        },\r\n        { ... etc ... },\r\n    };\r\n\r\n    auto it = std::find_if(std::begin(mappings),\r\n    std::end(mappings), [&amp;](auto&amp;&amp; mapping)\r\n        { return mapping.format == format; });\r\n    if (it == std::end(mappings)) {\r\n        throw winrt::hresult_error(\r\n            WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT);\r\n    }\r\n\r\n    \/\/ Create a buffer that can hold the pixels.\r\n    UINT width, height;\r\n    winrt::check_hresult(wicBitmap-&gt;GetSize(&amp;width, &amp;height));\r\n    \/\/ Avoid zero-sized or oversized bitmaps (integer overflow)\r\n    if (width == 0 || height == 0 ||\r\n        width &gt; ~0U \/ it-&gt;bytesPerPixel \/ height) {\r\n        throw winrt::hresult_error(\r\n            WINCODEC_ERR_IMAGESIZEOUTOFRANGE);\r\n    }\r\n    auto size = width * height * it-&gt;bytesPerPixel;\r\n    winrt::Buffer buffer(size);\r\n    buffer.Length(size);\r\n\r\n    \/\/ Copy the pixels into the buffer.\r\n    winrt::check_hresult(wicBitmap-&gt;CopyPixels(\r\n        nullptr, width * it-&gt;bytesPerPixel, size,\r\n        buffer.data()));\r\n    winrt::SoftwareBitmap softwareBitmap(it-&gt;pixelFormat,\r\n        width, height, it-&gt;alphaMode);\r\n\r\n    \/\/ Create a SoftwareBitmap from the buffer.\r\n    return winrt::SoftwareBitmap::CreateCopyFromBuffer(\r\n        buffer, pixelFormat, width, height, alphaMode);\r\n}\r\n<\/pre>\n<p>We no longer use the Windows Runtime <code>BitmapDecoder<\/code>, which means that we can do all of our work synchronously and return a <code>Software\u00adBitmap<\/code>.<\/p>\n<p>The idea here is that we peek at the <code>IWICBitmap<\/code> to see what its pixel format is, copy the pixels to a buffer, and then create a <code>Software\u00adBitmap<\/code> of a matching format from that buffer. Unfortunately, there doesn&#8217;t appear to be an easy way to convert between WIC pixel formats and Windows Runtime pixel formats, so we had to create a huge lookup table.<\/p>\n<p>If you would rather force the <code>Software\u00adBitmap<\/code> into a specific pixel format, then you can get rid of the format-sniffing code and instead use <code>WICConvert\u00adBitmap\u00adSource<\/code> to convert the <code>wicBitmap<\/code> to a matching source, and then just hard-code all the pixel format nonsense.<\/p>\n<p>It turns out that even this is working too hard. The pixels for the bitmap get copied twice: Once from the <code>wicBitmap<\/code> to the buffer, and then again from the buffer to the final <code>Software\u00adBitmap<\/code>. Next time, we&#8217;ll reduce it to just one copy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Passing raw pixels across.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-108044","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Passing raw pixels across.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=108044"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/108044\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=108044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=108044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=108044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}