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