xref: /aosp_15_r20/external/webp/imageio/wicdec.c (revision b2055c353e87c8814eb2b6b1b11112a1562253bd)
1*b2055c35SXin Li // Copyright 2013 Google Inc. All Rights Reserved.
2*b2055c35SXin Li //
3*b2055c35SXin Li // Use of this source code is governed by a BSD-style license
4*b2055c35SXin Li // that can be found in the COPYING file in the root of the source
5*b2055c35SXin Li // tree. An additional intellectual property rights grant can be found
6*b2055c35SXin Li // in the file PATENTS. All contributing project authors may
7*b2055c35SXin Li // be found in the AUTHORS file in the root of the source tree.
8*b2055c35SXin Li // -----------------------------------------------------------------------------
9*b2055c35SXin Li //
10*b2055c35SXin Li // Windows Imaging Component (WIC) decode.
11*b2055c35SXin Li 
12*b2055c35SXin Li #include "./wicdec.h"
13*b2055c35SXin Li 
14*b2055c35SXin Li #ifdef HAVE_CONFIG_H
15*b2055c35SXin Li #include "webp/config.h"
16*b2055c35SXin Li #endif
17*b2055c35SXin Li 
18*b2055c35SXin Li #include <assert.h>
19*b2055c35SXin Li #include <stdio.h>
20*b2055c35SXin Li #include <string.h>
21*b2055c35SXin Li 
22*b2055c35SXin Li #ifdef HAVE_WINCODEC_H
23*b2055c35SXin Li #ifdef __MINGW32__
24*b2055c35SXin Li #define INITGUID  // Without this GUIDs are declared extern and fail to link
25*b2055c35SXin Li #endif
26*b2055c35SXin Li #define CINTERFACE
27*b2055c35SXin Li #define COBJMACROS
28*b2055c35SXin Li #define _WIN32_IE 0x500  // Workaround bug in shlwapi.h when compiling C++
29*b2055c35SXin Li                          // code with COBJMACROS.
30*b2055c35SXin Li #include <ole2.h>  // CreateStreamOnHGlobal()
31*b2055c35SXin Li #include <shlwapi.h>
32*b2055c35SXin Li #include <tchar.h>
33*b2055c35SXin Li #include <windows.h>
34*b2055c35SXin Li #include <wincodec.h>
35*b2055c35SXin Li 
36*b2055c35SXin Li #include "../examples/unicode.h"
37*b2055c35SXin Li #include "./imageio_util.h"
38*b2055c35SXin Li #include "./metadata.h"
39*b2055c35SXin Li #include "webp/encode.h"
40*b2055c35SXin Li 
41*b2055c35SXin Li #define IFS(fn)                                                     \
42*b2055c35SXin Li   do {                                                              \
43*b2055c35SXin Li     if (SUCCEEDED(hr)) {                                            \
44*b2055c35SXin Li       hr = (fn);                                                    \
45*b2055c35SXin Li       if (FAILED(hr)) fprintf(stderr, #fn " failed %08lx\n", hr);   \
46*b2055c35SXin Li     }                                                               \
47*b2055c35SXin Li   } while (0)
48*b2055c35SXin Li 
49*b2055c35SXin Li // modified version of DEFINE_GUID from guiddef.h.
50*b2055c35SXin Li #define WEBP_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
51*b2055c35SXin Li   static const GUID name = \
52*b2055c35SXin Li       { l, w1, w2, { b1, b2,  b3,  b4,  b5,  b6,  b7,  b8 } }
53*b2055c35SXin Li 
54*b2055c35SXin Li #ifdef __cplusplus
55*b2055c35SXin Li #define MAKE_REFGUID(x) (x)
56*b2055c35SXin Li #else
57*b2055c35SXin Li #define MAKE_REFGUID(x) &(x)
58*b2055c35SXin Li #endif
59*b2055c35SXin Li 
60*b2055c35SXin Li typedef struct WICFormatImporter {
61*b2055c35SXin Li   const GUID* pixel_format;
62*b2055c35SXin Li   int bytes_per_pixel;
63*b2055c35SXin Li   int (*import)(WebPPicture* const, const uint8_t* const, int);
64*b2055c35SXin Li } WICFormatImporter;
65*b2055c35SXin Li 
66*b2055c35SXin Li // From Microsoft SDK 7.0a -- wincodec.h
67*b2055c35SXin Li // Create local copies for compatibility when building against earlier
68*b2055c35SXin Li // versions of the SDK.
69*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppBGR_,
70*b2055c35SXin Li                  0x6fddc324, 0x4e03, 0x4bfe,
71*b2055c35SXin Li                  0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
72*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat24bppRGB_,
73*b2055c35SXin Li                  0x6fddc324, 0x4e03, 0x4bfe,
74*b2055c35SXin Li                  0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
75*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppBGRA_,
76*b2055c35SXin Li                  0x6fddc324, 0x4e03, 0x4bfe,
77*b2055c35SXin Li                  0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
78*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat32bppRGBA_,
79*b2055c35SXin Li                  0xf5c7ad2d, 0x6a8d, 0x43dd,
80*b2055c35SXin Li                  0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
81*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppBGRA_,
82*b2055c35SXin Li                  0x1562ff7c, 0xd352, 0x46f9,
83*b2055c35SXin Li                  0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
84*b2055c35SXin Li WEBP_DEFINE_GUID(GUID_WICPixelFormat64bppRGBA_,
85*b2055c35SXin Li                  0x6fddc324, 0x4e03, 0x4bfe,
86*b2055c35SXin Li                  0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
87*b2055c35SXin Li 
OpenInputStream(const char * filename,IStream ** stream)88*b2055c35SXin Li static HRESULT OpenInputStream(const char* filename, IStream** stream) {
89*b2055c35SXin Li   HRESULT hr = S_OK;
90*b2055c35SXin Li   if (!WSTRCMP(filename, "-")) {
91*b2055c35SXin Li     const uint8_t* data = NULL;
92*b2055c35SXin Li     size_t data_size = 0;
93*b2055c35SXin Li     const int ok = ImgIoUtilReadFile(filename, &data, &data_size);
94*b2055c35SXin Li     if (ok) {
95*b2055c35SXin Li       HGLOBAL image = GlobalAlloc(GMEM_MOVEABLE, data_size);
96*b2055c35SXin Li       if (image != NULL) {
97*b2055c35SXin Li         void* const image_mem = GlobalLock(image);
98*b2055c35SXin Li         if (image_mem != NULL) {
99*b2055c35SXin Li           memcpy(image_mem, data, data_size);
100*b2055c35SXin Li           GlobalUnlock(image);
101*b2055c35SXin Li           IFS(CreateStreamOnHGlobal(image, TRUE, stream));
102*b2055c35SXin Li         } else {
103*b2055c35SXin Li           hr = E_FAIL;
104*b2055c35SXin Li         }
105*b2055c35SXin Li       } else {
106*b2055c35SXin Li         hr = E_OUTOFMEMORY;
107*b2055c35SXin Li       }
108*b2055c35SXin Li       free((void*)data);
109*b2055c35SXin Li     } else {
110*b2055c35SXin Li       hr = E_FAIL;
111*b2055c35SXin Li     }
112*b2055c35SXin Li   } else {
113*b2055c35SXin Li     IFS(SHCreateStreamOnFile((const LPTSTR)filename, STGM_READ, stream));
114*b2055c35SXin Li   }
115*b2055c35SXin Li 
116*b2055c35SXin Li   if (FAILED(hr)) {
117*b2055c35SXin Li     _ftprintf(stderr, _T("Error opening input file %s (%08lx)\n"),
118*b2055c35SXin Li               (const LPTSTR)filename, hr);
119*b2055c35SXin Li   }
120*b2055c35SXin Li   return hr;
121*b2055c35SXin Li }
122*b2055c35SXin Li 
123*b2055c35SXin Li // -----------------------------------------------------------------------------
124*b2055c35SXin Li // Metadata processing
125*b2055c35SXin Li 
126*b2055c35SXin Li // Stores the first non-zero sized color profile from 'frame' to 'iccp'.
127*b2055c35SXin Li // Returns an HRESULT to indicate success or failure. The caller is responsible
128*b2055c35SXin Li // for freeing 'iccp->bytes' in either case.
ExtractICCP(IWICImagingFactory * const factory,IWICBitmapFrameDecode * const frame,MetadataPayload * const iccp)129*b2055c35SXin Li static HRESULT ExtractICCP(IWICImagingFactory* const factory,
130*b2055c35SXin Li                            IWICBitmapFrameDecode* const frame,
131*b2055c35SXin Li                            MetadataPayload* const iccp) {
132*b2055c35SXin Li   HRESULT hr = S_OK;
133*b2055c35SXin Li   UINT i, count;
134*b2055c35SXin Li   IWICColorContext** color_contexts;
135*b2055c35SXin Li 
136*b2055c35SXin Li   IFS(IWICBitmapFrameDecode_GetColorContexts(frame, 0, NULL, &count));
137*b2055c35SXin Li   if (FAILED(hr) || count == 0) {
138*b2055c35SXin Li     // Treat unsupported operation as a non-fatal error. See crbug.com/webp/506.
139*b2055c35SXin Li     return (hr == WINCODEC_ERR_UNSUPPORTEDOPERATION) ? S_OK : hr;
140*b2055c35SXin Li   }
141*b2055c35SXin Li 
142*b2055c35SXin Li   color_contexts = (IWICColorContext**)calloc(count, sizeof(*color_contexts));
143*b2055c35SXin Li   if (color_contexts == NULL) return E_OUTOFMEMORY;
144*b2055c35SXin Li   for (i = 0; SUCCEEDED(hr) && i < count; ++i) {
145*b2055c35SXin Li     IFS(IWICImagingFactory_CreateColorContext(factory, &color_contexts[i]));
146*b2055c35SXin Li   }
147*b2055c35SXin Li 
148*b2055c35SXin Li   if (SUCCEEDED(hr)) {
149*b2055c35SXin Li     UINT num_color_contexts;
150*b2055c35SXin Li     IFS(IWICBitmapFrameDecode_GetColorContexts(frame,
151*b2055c35SXin Li                                                count, color_contexts,
152*b2055c35SXin Li                                                &num_color_contexts));
153*b2055c35SXin Li     assert(FAILED(hr) || num_color_contexts <= count);
154*b2055c35SXin Li     for (i = 0; SUCCEEDED(hr) && i < num_color_contexts; ++i) {
155*b2055c35SXin Li       WICColorContextType type;
156*b2055c35SXin Li       IFS(IWICColorContext_GetType(color_contexts[i], &type));
157*b2055c35SXin Li       if (SUCCEEDED(hr) && type == WICColorContextProfile) {
158*b2055c35SXin Li         UINT size;
159*b2055c35SXin Li         IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
160*b2055c35SXin Li                                              0, NULL, &size));
161*b2055c35SXin Li         if (SUCCEEDED(hr) && size > 0) {
162*b2055c35SXin Li           iccp->bytes = (uint8_t*)malloc(size);
163*b2055c35SXin Li           if (iccp->bytes == NULL) {
164*b2055c35SXin Li             hr = E_OUTOFMEMORY;
165*b2055c35SXin Li             break;
166*b2055c35SXin Li           }
167*b2055c35SXin Li           iccp->size = size;
168*b2055c35SXin Li           IFS(IWICColorContext_GetProfileBytes(color_contexts[i],
169*b2055c35SXin Li                                                (UINT)iccp->size, iccp->bytes,
170*b2055c35SXin Li                                                &size));
171*b2055c35SXin Li           if (SUCCEEDED(hr) && size != iccp->size) {
172*b2055c35SXin Li             fprintf(stderr, "Warning! ICC profile size (%u) != expected (%u)\n",
173*b2055c35SXin Li                     size, (uint32_t)iccp->size);
174*b2055c35SXin Li             iccp->size = size;
175*b2055c35SXin Li           }
176*b2055c35SXin Li           break;
177*b2055c35SXin Li         }
178*b2055c35SXin Li       }
179*b2055c35SXin Li     }
180*b2055c35SXin Li   }
181*b2055c35SXin Li   for (i = 0; i < count; ++i) {
182*b2055c35SXin Li     if (color_contexts[i] != NULL) IUnknown_Release(color_contexts[i]);
183*b2055c35SXin Li   }
184*b2055c35SXin Li   free(color_contexts);
185*b2055c35SXin Li   return hr;
186*b2055c35SXin Li }
187*b2055c35SXin Li 
ExtractMetadata(IWICImagingFactory * const factory,IWICBitmapFrameDecode * const frame,Metadata * const metadata)188*b2055c35SXin Li static HRESULT ExtractMetadata(IWICImagingFactory* const factory,
189*b2055c35SXin Li                                IWICBitmapFrameDecode* const frame,
190*b2055c35SXin Li                                Metadata* const metadata) {
191*b2055c35SXin Li   // TODO(jzern): add XMP/EXIF extraction.
192*b2055c35SXin Li   const HRESULT hr = ExtractICCP(factory, frame, &metadata->iccp);
193*b2055c35SXin Li   if (FAILED(hr)) MetadataFree(metadata);
194*b2055c35SXin Li   return hr;
195*b2055c35SXin Li }
196*b2055c35SXin Li 
197*b2055c35SXin Li // -----------------------------------------------------------------------------
198*b2055c35SXin Li 
HasPalette(GUID pixel_format)199*b2055c35SXin Li static int HasPalette(GUID pixel_format) {
200*b2055c35SXin Li   return (IsEqualGUID(MAKE_REFGUID(pixel_format),
201*b2055c35SXin Li                       MAKE_REFGUID(GUID_WICPixelFormat1bppIndexed)) ||
202*b2055c35SXin Li           IsEqualGUID(MAKE_REFGUID(pixel_format),
203*b2055c35SXin Li                       MAKE_REFGUID(GUID_WICPixelFormat2bppIndexed)) ||
204*b2055c35SXin Li           IsEqualGUID(MAKE_REFGUID(pixel_format),
205*b2055c35SXin Li                       MAKE_REFGUID(GUID_WICPixelFormat4bppIndexed)) ||
206*b2055c35SXin Li           IsEqualGUID(MAKE_REFGUID(pixel_format),
207*b2055c35SXin Li                       MAKE_REFGUID(GUID_WICPixelFormat8bppIndexed)));
208*b2055c35SXin Li }
209*b2055c35SXin Li 
HasAlpha(IWICImagingFactory * const factory,IWICBitmapDecoder * const decoder,IWICBitmapFrameDecode * const frame,GUID pixel_format)210*b2055c35SXin Li static int HasAlpha(IWICImagingFactory* const factory,
211*b2055c35SXin Li                     IWICBitmapDecoder* const decoder,
212*b2055c35SXin Li                     IWICBitmapFrameDecode* const frame,
213*b2055c35SXin Li                     GUID pixel_format) {
214*b2055c35SXin Li   int has_alpha;
215*b2055c35SXin Li   if (HasPalette(pixel_format)) {
216*b2055c35SXin Li     IWICPalette* frame_palette = NULL;
217*b2055c35SXin Li     IWICPalette* global_palette = NULL;
218*b2055c35SXin Li     BOOL frame_palette_has_alpha = FALSE;
219*b2055c35SXin Li     BOOL global_palette_has_alpha = FALSE;
220*b2055c35SXin Li 
221*b2055c35SXin Li     // A palette may exist at the frame or container level,
222*b2055c35SXin Li     // check IWICPalette::HasAlpha() for both if present.
223*b2055c35SXin Li     if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &frame_palette)) &&
224*b2055c35SXin Li         SUCCEEDED(IWICBitmapFrameDecode_CopyPalette(frame, frame_palette))) {
225*b2055c35SXin Li       IWICPalette_HasAlpha(frame_palette, &frame_palette_has_alpha);
226*b2055c35SXin Li     }
227*b2055c35SXin Li     if (SUCCEEDED(IWICImagingFactory_CreatePalette(factory, &global_palette)) &&
228*b2055c35SXin Li         SUCCEEDED(IWICBitmapDecoder_CopyPalette(decoder, global_palette))) {
229*b2055c35SXin Li       IWICPalette_HasAlpha(global_palette, &global_palette_has_alpha);
230*b2055c35SXin Li     }
231*b2055c35SXin Li     has_alpha = frame_palette_has_alpha || global_palette_has_alpha;
232*b2055c35SXin Li 
233*b2055c35SXin Li     if (frame_palette != NULL) IUnknown_Release(frame_palette);
234*b2055c35SXin Li     if (global_palette != NULL) IUnknown_Release(global_palette);
235*b2055c35SXin Li   } else {
236*b2055c35SXin Li     has_alpha = IsEqualGUID(MAKE_REFGUID(pixel_format),
237*b2055c35SXin Li                             MAKE_REFGUID(GUID_WICPixelFormat32bppRGBA_)) ||
238*b2055c35SXin Li                 IsEqualGUID(MAKE_REFGUID(pixel_format),
239*b2055c35SXin Li                             MAKE_REFGUID(GUID_WICPixelFormat32bppBGRA_)) ||
240*b2055c35SXin Li                 IsEqualGUID(MAKE_REFGUID(pixel_format),
241*b2055c35SXin Li                             MAKE_REFGUID(GUID_WICPixelFormat64bppRGBA_)) ||
242*b2055c35SXin Li                 IsEqualGUID(MAKE_REFGUID(pixel_format),
243*b2055c35SXin Li                             MAKE_REFGUID(GUID_WICPixelFormat64bppBGRA_));
244*b2055c35SXin Li   }
245*b2055c35SXin Li   return has_alpha;
246*b2055c35SXin Li }
247*b2055c35SXin Li 
ReadPictureWithWIC(const char * const filename,WebPPicture * const pic,int keep_alpha,Metadata * const metadata)248*b2055c35SXin Li int ReadPictureWithWIC(const char* const filename,
249*b2055c35SXin Li                        WebPPicture* const pic, int keep_alpha,
250*b2055c35SXin Li                        Metadata* const metadata) {
251*b2055c35SXin Li   // From Microsoft SDK 6.0a -- ks.h
252*b2055c35SXin Li   // Define a local copy to avoid link errors under mingw.
253*b2055c35SXin Li   WEBP_DEFINE_GUID(GUID_NULL_, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
254*b2055c35SXin Li   static const WICFormatImporter kAlphaFormatImporters[] = {
255*b2055c35SXin Li     { &GUID_WICPixelFormat32bppBGRA_, 4, WebPPictureImportBGRA },
256*b2055c35SXin Li     { &GUID_WICPixelFormat32bppRGBA_, 4, WebPPictureImportRGBA },
257*b2055c35SXin Li     { NULL, 0, NULL },
258*b2055c35SXin Li   };
259*b2055c35SXin Li   static const WICFormatImporter kNonAlphaFormatImporters[] = {
260*b2055c35SXin Li     { &GUID_WICPixelFormat24bppBGR_, 3, WebPPictureImportBGR },
261*b2055c35SXin Li     { &GUID_WICPixelFormat24bppRGB_, 3, WebPPictureImportRGB },
262*b2055c35SXin Li     { NULL, 0, NULL },
263*b2055c35SXin Li   };
264*b2055c35SXin Li   HRESULT hr = S_OK;
265*b2055c35SXin Li   IWICBitmapFrameDecode* frame = NULL;
266*b2055c35SXin Li   IWICFormatConverter* converter = NULL;
267*b2055c35SXin Li   IWICImagingFactory* factory = NULL;
268*b2055c35SXin Li   IWICBitmapDecoder* decoder = NULL;
269*b2055c35SXin Li   IStream* stream = NULL;
270*b2055c35SXin Li   UINT frame_count = 0;
271*b2055c35SXin Li   UINT width = 0, height = 0;
272*b2055c35SXin Li   BYTE* rgb = NULL;
273*b2055c35SXin Li   WICPixelFormatGUID src_pixel_format = GUID_WICPixelFormatUndefined;
274*b2055c35SXin Li   const WICFormatImporter* importer = NULL;
275*b2055c35SXin Li   GUID src_container_format = GUID_NULL_;
276*b2055c35SXin Li   // From Windows Kits\10\Include\10.0.19041.0\um\wincodec.h
277*b2055c35SXin Li   WEBP_DEFINE_GUID(GUID_ContainerFormatWebp_,
278*b2055c35SXin Li                    0xe094b0e2, 0x67f2, 0x45b3,
279*b2055c35SXin Li                    0xb0, 0xea, 0x11, 0x53, 0x37, 0xca, 0x7c, 0xf3);
280*b2055c35SXin Li   static const GUID* kAlphaContainers[] = {
281*b2055c35SXin Li     &GUID_ContainerFormatBmp,
282*b2055c35SXin Li     &GUID_ContainerFormatPng,
283*b2055c35SXin Li     &GUID_ContainerFormatTiff,
284*b2055c35SXin Li     &GUID_ContainerFormatWebp_,
285*b2055c35SXin Li     NULL
286*b2055c35SXin Li   };
287*b2055c35SXin Li   int has_alpha = 0;
288*b2055c35SXin Li   int64_t stride;
289*b2055c35SXin Li 
290*b2055c35SXin Li   if (filename == NULL || pic == NULL) return 0;
291*b2055c35SXin Li 
292*b2055c35SXin Li   IFS(CoInitialize(NULL));
293*b2055c35SXin Li   IFS(CoCreateInstance(MAKE_REFGUID(CLSID_WICImagingFactory), NULL,
294*b2055c35SXin Li                        CLSCTX_INPROC_SERVER,
295*b2055c35SXin Li                        MAKE_REFGUID(IID_IWICImagingFactory),
296*b2055c35SXin Li                        (LPVOID*)&factory));
297*b2055c35SXin Li   if (hr == REGDB_E_CLASSNOTREG) {
298*b2055c35SXin Li     fprintf(stderr,
299*b2055c35SXin Li             "Couldn't access Windows Imaging Component (are you running "
300*b2055c35SXin Li             "Windows XP SP3 or newer?). Most formats not available. "
301*b2055c35SXin Li             "Use -s for the available YUV input.\n");
302*b2055c35SXin Li   }
303*b2055c35SXin Li   // Prepare for image decoding.
304*b2055c35SXin Li   IFS(OpenInputStream(filename, &stream));
305*b2055c35SXin Li   IFS(IWICImagingFactory_CreateDecoderFromStream(
306*b2055c35SXin Li           factory, stream, NULL,
307*b2055c35SXin Li           WICDecodeMetadataCacheOnDemand, &decoder));
308*b2055c35SXin Li   IFS(IWICBitmapDecoder_GetFrameCount(decoder, &frame_count));
309*b2055c35SXin Li   if (SUCCEEDED(hr)) {
310*b2055c35SXin Li     if (frame_count == 0) {
311*b2055c35SXin Li       fprintf(stderr, "No frame found in input file.\n");
312*b2055c35SXin Li       hr = E_FAIL;
313*b2055c35SXin Li     } else if (frame_count > 1) {
314*b2055c35SXin Li       // WIC will be tried before native WebP decoding so avoid duplicating the
315*b2055c35SXin Li       // error message.
316*b2055c35SXin Li       hr = E_FAIL;
317*b2055c35SXin Li     }
318*b2055c35SXin Li   }
319*b2055c35SXin Li   IFS(IWICBitmapDecoder_GetFrame(decoder, 0, &frame));
320*b2055c35SXin Li   IFS(IWICBitmapFrameDecode_GetPixelFormat(frame, &src_pixel_format));
321*b2055c35SXin Li   IFS(IWICBitmapDecoder_GetContainerFormat(decoder, &src_container_format));
322*b2055c35SXin Li 
323*b2055c35SXin Li   if (SUCCEEDED(hr) && keep_alpha) {
324*b2055c35SXin Li     const GUID** guid;
325*b2055c35SXin Li     for (guid = kAlphaContainers; *guid != NULL; ++guid) {
326*b2055c35SXin Li       if (IsEqualGUID(MAKE_REFGUID(src_container_format),
327*b2055c35SXin Li                       MAKE_REFGUID(**guid))) {
328*b2055c35SXin Li         has_alpha = HasAlpha(factory, decoder, frame, src_pixel_format);
329*b2055c35SXin Li         break;
330*b2055c35SXin Li       }
331*b2055c35SXin Li     }
332*b2055c35SXin Li   }
333*b2055c35SXin Li 
334*b2055c35SXin Li   // Prepare for pixel format conversion (if necessary).
335*b2055c35SXin Li   IFS(IWICImagingFactory_CreateFormatConverter(factory, &converter));
336*b2055c35SXin Li 
337*b2055c35SXin Li   for (importer = has_alpha ? kAlphaFormatImporters : kNonAlphaFormatImporters;
338*b2055c35SXin Li        hr == S_OK && importer->import != NULL; ++importer) {
339*b2055c35SXin Li     BOOL can_convert;
340*b2055c35SXin Li     const HRESULT cchr = IWICFormatConverter_CanConvert(
341*b2055c35SXin Li         converter,
342*b2055c35SXin Li         MAKE_REFGUID(src_pixel_format),
343*b2055c35SXin Li         MAKE_REFGUID(*importer->pixel_format),
344*b2055c35SXin Li         &can_convert);
345*b2055c35SXin Li     if (SUCCEEDED(cchr) && can_convert) break;
346*b2055c35SXin Li   }
347*b2055c35SXin Li   if (importer->import == NULL) hr = E_FAIL;
348*b2055c35SXin Li 
349*b2055c35SXin Li   IFS(IWICFormatConverter_Initialize(converter, (IWICBitmapSource*)frame,
350*b2055c35SXin Li                                      importer->pixel_format,
351*b2055c35SXin Li                                      WICBitmapDitherTypeNone,
352*b2055c35SXin Li                                      NULL, 0.0, WICBitmapPaletteTypeCustom));
353*b2055c35SXin Li 
354*b2055c35SXin Li   // Decode.
355*b2055c35SXin Li   IFS(IWICFormatConverter_GetSize(converter, &width, &height));
356*b2055c35SXin Li   stride = (int64_t)importer->bytes_per_pixel * width * sizeof(*rgb);
357*b2055c35SXin Li   if (stride != (int)stride ||
358*b2055c35SXin Li       !ImgIoUtilCheckSizeArgumentsOverflow(stride, height)) {
359*b2055c35SXin Li     hr = E_FAIL;
360*b2055c35SXin Li   }
361*b2055c35SXin Li 
362*b2055c35SXin Li   if (SUCCEEDED(hr)) {
363*b2055c35SXin Li     rgb = (BYTE*)malloc((size_t)stride * height);
364*b2055c35SXin Li     if (rgb == NULL)
365*b2055c35SXin Li       hr = E_OUTOFMEMORY;
366*b2055c35SXin Li   }
367*b2055c35SXin Li   IFS(IWICFormatConverter_CopyPixels(converter, NULL,
368*b2055c35SXin Li                                      (UINT)stride, (UINT)stride * height, rgb));
369*b2055c35SXin Li 
370*b2055c35SXin Li   // WebP conversion.
371*b2055c35SXin Li   if (SUCCEEDED(hr)) {
372*b2055c35SXin Li     int ok;
373*b2055c35SXin Li     pic->width = width;
374*b2055c35SXin Li     pic->height = height;
375*b2055c35SXin Li     pic->use_argb = 1;    // For WIC, we always force to argb
376*b2055c35SXin Li     ok = importer->import(pic, rgb, (int)stride);
377*b2055c35SXin Li     if (!ok) hr = E_FAIL;
378*b2055c35SXin Li   }
379*b2055c35SXin Li   if (SUCCEEDED(hr)) {
380*b2055c35SXin Li     if (metadata != NULL) {
381*b2055c35SXin Li       hr = ExtractMetadata(factory, frame, metadata);
382*b2055c35SXin Li       if (FAILED(hr)) {
383*b2055c35SXin Li         fprintf(stderr, "Error extracting image metadata using WIC!\n");
384*b2055c35SXin Li       }
385*b2055c35SXin Li     }
386*b2055c35SXin Li   }
387*b2055c35SXin Li 
388*b2055c35SXin Li   // Cleanup.
389*b2055c35SXin Li   if (converter != NULL) IUnknown_Release(converter);
390*b2055c35SXin Li   if (frame != NULL) IUnknown_Release(frame);
391*b2055c35SXin Li   if (decoder != NULL) IUnknown_Release(decoder);
392*b2055c35SXin Li   if (factory != NULL) IUnknown_Release(factory);
393*b2055c35SXin Li   if (stream != NULL) IUnknown_Release(stream);
394*b2055c35SXin Li   free(rgb);
395*b2055c35SXin Li   return SUCCEEDED(hr);
396*b2055c35SXin Li }
397*b2055c35SXin Li #else  // !HAVE_WINCODEC_H
ReadPictureWithWIC(const char * const filename,struct WebPPicture * const pic,int keep_alpha,struct Metadata * const metadata)398*b2055c35SXin Li int ReadPictureWithWIC(const char* const filename,
399*b2055c35SXin Li                        struct WebPPicture* const pic, int keep_alpha,
400*b2055c35SXin Li                        struct Metadata* const metadata) {
401*b2055c35SXin Li   (void)filename;
402*b2055c35SXin Li   (void)pic;
403*b2055c35SXin Li   (void)keep_alpha;
404*b2055c35SXin Li   (void)metadata;
405*b2055c35SXin Li   fprintf(stderr, "Windows Imaging Component (WIC) support not compiled. "
406*b2055c35SXin Li                   "Visual Studio and mingw-w64 builds support WIC. Make sure "
407*b2055c35SXin Li                   "wincodec.h detection is working correctly if using autoconf "
408*b2055c35SXin Li                   "and HAVE_WINCODEC_H is defined before building.\n");
409*b2055c35SXin Li   return 0;
410*b2055c35SXin Li }
411*b2055c35SXin Li #endif  // HAVE_WINCODEC_H
412*b2055c35SXin Li 
413*b2055c35SXin Li // -----------------------------------------------------------------------------
414