1 /*
2  * Copyright 2009 Vincent Povirk
3  * Copyright 2016 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "precomp.h"
21 
22 static IWICImagingFactory *factory;
23 
24 typedef struct bitmap_data {
25     const WICPixelFormatGUID *format;
26     UINT bpp;
27     const BYTE *bits;
28     UINT width;
29     UINT height;
30     double xres;
31     double yres;
32     const struct bitmap_data *alt_data;
33 } bitmap_data;
34 
35 typedef struct BitmapTestSrc {
36     IWICBitmapSource IWICBitmapSource_iface;
37     LONG ref;
38     const bitmap_data *data;
39 } BitmapTestSrc;
40 
41 extern HRESULT STDMETHODCALLTYPE IWICBitmapFrameEncode_WriteSource_Proxy(IWICBitmapFrameEncode* This,
42     IWICBitmapSource *pIBitmapSource, WICRect *prc);
43 
44 static BOOL near_equal(float a, float b)
45 {
46     return fabsf(a - b) < 0.001;
47 }
48 
49 static inline BitmapTestSrc *impl_from_IWICBitmapSource(IWICBitmapSource *iface)
50 {
51     return CONTAINING_RECORD(iface, BitmapTestSrc, IWICBitmapSource_iface);
52 }
53 
54 static HRESULT WINAPI BitmapTestSrc_QueryInterface(IWICBitmapSource *iface, REFIID iid,
55     void **ppv)
56 {
57     if (!ppv) return E_INVALIDARG;
58 
59     if (IsEqualIID(&IID_IUnknown, iid) ||
60         IsEqualIID(&IID_IWICBitmapSource, iid))
61         *ppv = iface;
62     else
63         return E_NOINTERFACE;
64 
65     IUnknown_AddRef((IUnknown*)*ppv);
66     return S_OK;
67 }
68 
69 static ULONG WINAPI BitmapTestSrc_AddRef(IWICBitmapSource *iface)
70 {
71     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
72     ULONG ref = InterlockedIncrement(&This->ref);
73     return ref;
74 }
75 
76 static ULONG WINAPI BitmapTestSrc_Release(IWICBitmapSource *iface)
77 {
78     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
79     ULONG ref = InterlockedDecrement(&This->ref);
80     return ref;
81 }
82 
83 static HRESULT WINAPI BitmapTestSrc_GetSize(IWICBitmapSource *iface,
84     UINT *puiWidth, UINT *puiHeight)
85 {
86     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
87     *puiWidth = This->data->width;
88     *puiHeight = This->data->height;
89     return S_OK;
90 }
91 
92 static HRESULT WINAPI BitmapTestSrc_GetPixelFormat(IWICBitmapSource *iface,
93     WICPixelFormatGUID *pPixelFormat)
94 {
95     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
96     memcpy(pPixelFormat, This->data->format, sizeof(GUID));
97     return S_OK;
98 }
99 
100 static HRESULT WINAPI BitmapTestSrc_GetResolution(IWICBitmapSource *iface,
101     double *pDpiX, double *pDpiY)
102 {
103     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
104     *pDpiX = This->data->xres;
105     *pDpiY = This->data->yres;
106     return S_OK;
107 }
108 
109 static HRESULT WINAPI BitmapTestSrc_CopyPalette(IWICBitmapSource *iface,
110     IWICPalette *pIPalette)
111 {
112     return E_NOTIMPL;
113 }
114 
115 static HRESULT WINAPI BitmapTestSrc_CopyPixels(IWICBitmapSource *iface,
116     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
117 {
118     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
119     UINT bytesperrow;
120     UINT srcstride;
121     UINT row_offset;
122     WICRect rc;
123 
124     if (!prc)
125     {
126         rc.X = 0;
127         rc.Y = 0;
128         rc.Width = This->data->width;
129         rc.Height = This->data->height;
130         prc = &rc;
131     }
132     else
133     {
134         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->data->width || prc->Y+prc->Height > This->data->height)
135             return E_INVALIDARG;
136     }
137 
138     bytesperrow = ((This->data->bpp * prc->Width)+7)/8;
139     srcstride = ((This->data->bpp * This->data->width)+7)/8;
140 
141     if (cbStride < bytesperrow)
142         return E_INVALIDARG;
143 
144     if ((cbStride * prc->Height) > cbBufferSize)
145         return E_INVALIDARG;
146 
147     row_offset = prc->X * This->data->bpp;
148 
149     if (row_offset % 8 == 0)
150     {
151         UINT row;
152         const BYTE *src;
153         BYTE *dst;
154 
155         src = This->data->bits + (row_offset / 8) + prc->Y * srcstride;
156         dst = pbBuffer;
157         for (row=0; row < prc->Height; row++)
158         {
159             memcpy(dst, src, bytesperrow);
160             src += srcstride;
161             dst += cbStride;
162         }
163         return S_OK;
164     }
165     else
166     {
167         ok(0, "bitmap %p was asked to copy pixels not aligned on a byte boundary\n", iface);
168         return E_FAIL;
169     }
170 }
171 
172 static const IWICBitmapSourceVtbl BitmapTestSrc_Vtbl = {
173     BitmapTestSrc_QueryInterface,
174     BitmapTestSrc_AddRef,
175     BitmapTestSrc_Release,
176     BitmapTestSrc_GetSize,
177     BitmapTestSrc_GetPixelFormat,
178     BitmapTestSrc_GetResolution,
179     BitmapTestSrc_CopyPalette,
180     BitmapTestSrc_CopyPixels
181 };
182 
183 static void CreateTestBitmap(const bitmap_data *data, BitmapTestSrc **This)
184 {
185     *This = HeapAlloc(GetProcessHeap(), 0, sizeof(**This));
186 
187     if (*This)
188     {
189         (*This)->IWICBitmapSource_iface.lpVtbl = &BitmapTestSrc_Vtbl;
190         (*This)->ref = 1;
191         (*This)->data = data;
192     }
193 }
194 
195 static void DeleteTestBitmap(BitmapTestSrc *This)
196 {
197     ok(This->IWICBitmapSource_iface.lpVtbl == &BitmapTestSrc_Vtbl, "test bitmap %p deleted with incorrect vtable\n", This);
198     ok(This->ref == 1, "test bitmap %p deleted with %i references instead of 1\n", This, This->ref);
199     HeapFree(GetProcessHeap(), 0, This);
200 }
201 
202 static BOOL compare_bits(const struct bitmap_data *expect, UINT buffersize, const BYTE *converted_bits)
203 {
204     BOOL equal;
205 
206     if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
207     {
208         /* ignore the padding byte when comparing data */
209         UINT i;
210         const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
211         equal=TRUE;
212         for (i=0; i<(buffersize/4); i++)
213             if ((a[i]&0xffffff) != (b[i]&0xffffff))
214             {
215                 equal = FALSE;
216                 break;
217             }
218     }
219     else if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppGrayFloat))
220     {
221         UINT i;
222         const float *a=(const float*)expect->bits, *b=(const float*)converted_bits;
223         equal=TRUE;
224         for (i=0; i<(buffersize/4); i++)
225             if (!near_equal(a[i], b[i]))
226             {
227                 equal = FALSE;
228                 break;
229             }
230     }
231     else if (IsEqualGUID(expect->format, &GUID_WICPixelFormatBlackWhite) ||
232              IsEqualGUID(expect->format, &GUID_WICPixelFormat1bppIndexed))
233     {
234         UINT i;
235         const BYTE *a=(const BYTE*)expect->bits, *b=(const BYTE*)converted_bits;
236         equal=TRUE;
237         for (i=0; i<buffersize; i++)
238             if (a[i] != b[i] && b[i] != 0xff /* BMP encoder B&W */)
239             {
240                 equal = FALSE;
241                 break;
242             }
243     }
244     else
245         equal = (memcmp(expect->bits, converted_bits, buffersize) == 0);
246 
247     if (!equal && expect->alt_data)
248         equal = compare_bits(expect->alt_data, buffersize, converted_bits);
249 
250     return equal;
251 }
252 
253 static void compare_bitmap_data(const struct bitmap_data *expect, IWICBitmapSource *source, const char *name)
254 {
255     BYTE *converted_bits;
256     UINT width, height;
257     double xres, yres;
258     WICRect prc;
259     UINT stride, buffersize;
260     GUID dst_pixelformat;
261     HRESULT hr;
262 
263     hr = IWICBitmapSource_GetSize(source, &width, &height);
264     ok(SUCCEEDED(hr), "GetSize(%s) failed, hr=%x\n", name, hr);
265     ok(width == expect->width, "expecting %u, got %u (%s)\n", expect->width, width, name);
266     ok(height == expect->height, "expecting %u, got %u (%s)\n", expect->height, height, name);
267 
268     hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
269     ok(SUCCEEDED(hr), "GetResolution(%s) failed, hr=%x\n", name, hr);
270     ok(fabs(xres - expect->xres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->xres, xres, name);
271     ok(fabs(yres - expect->yres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->yres, yres, name);
272 
273     hr = IWICBitmapSource_GetPixelFormat(source, &dst_pixelformat);
274     ok(SUCCEEDED(hr), "GetPixelFormat(%s) failed, hr=%x\n", name, hr);
275     ok(IsEqualGUID(&dst_pixelformat, expect->format), "got unexpected pixel format %s (%s)\n", wine_dbgstr_guid(&dst_pixelformat), name);
276 
277     prc.X = 0;
278     prc.Y = 0;
279     prc.Width = expect->width;
280     prc.Height = expect->height;
281 
282     stride = (expect->bpp * expect->width + 7) / 8;
283     buffersize = stride * expect->height;
284 
285     converted_bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
286     hr = IWICBitmapSource_CopyPixels(source, &prc, stride, buffersize, converted_bits);
287     ok(SUCCEEDED(hr), "CopyPixels(%s) failed, hr=%x\n", name, hr);
288     ok(compare_bits(expect, buffersize, converted_bits), "unexpected pixel data (%s)\n", name);
289 
290     /* Test with NULL rectangle - should copy the whole bitmap */
291     memset(converted_bits, 0xaa, buffersize);
292     hr = IWICBitmapSource_CopyPixels(source, NULL, stride, buffersize, converted_bits);
293     ok(SUCCEEDED(hr), "CopyPixels(%s,rc=NULL) failed, hr=%x\n", name, hr);
294     ok(compare_bits(expect, buffersize, converted_bits), "unexpected pixel data (%s)\n", name);
295 
296     HeapFree(GetProcessHeap(), 0, converted_bits);
297 }
298 
299 /* some encoders (like BMP) require data to be 4-bytes aligned */
300 static const BYTE bits_1bpp[] = {
301     0x55,0x55,0x55,0x55,  /*01010101*/
302     0xaa,0xaa,0xaa,0xaa}; /*10101010*/
303 static const struct bitmap_data testdata_BlackWhite = {
304     &GUID_WICPixelFormatBlackWhite, 1, bits_1bpp, 32, 2, 96.0, 96.0};
305 static const struct bitmap_data testdata_1bppIndexed = {
306     &GUID_WICPixelFormat1bppIndexed, 1, bits_1bpp, 32, 2, 96.0, 96.0};
307 
308 static const BYTE bits_8bpp[] = {
309     0,1,2,3,
310     4,5,6,7};
311 static const struct bitmap_data testdata_8bppIndexed = {
312     &GUID_WICPixelFormat8bppIndexed, 8, bits_8bpp, 4, 2, 96.0, 96.0};
313 
314 static const BYTE bits_24bppBGR[] = {
315     255,0,0, 0,255,0, 0,0,255, 0,0,0,
316     0,255,255, 255,0,255, 255,255,0, 255,255,255};
317 static const struct bitmap_data testdata_24bppBGR = {
318     &GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR, 4, 2, 96.0, 96.0};
319 
320 static const BYTE bits_24bppRGB[] = {
321     0,0,255, 0,255,0, 255,0,0, 0,0,0,
322     255,255,0, 255,0,255, 0,255,255, 255,255,255};
323 static const struct bitmap_data testdata_24bppRGB = {
324     &GUID_WICPixelFormat24bppRGB, 24, bits_24bppRGB, 4, 2, 96.0, 96.0};
325 
326 static const BYTE bits_32bppBGR[] = {
327     255,0,0,80, 0,255,0,80, 0,0,255,80, 0,0,0,80,
328     0,255,255,80, 255,0,255,80, 255,255,0,80, 255,255,255,80};
329 static const struct bitmap_data testdata_32bppBGR = {
330     &GUID_WICPixelFormat32bppBGR, 32, bits_32bppBGR, 4, 2, 96.0, 96.0};
331 
332 static const BYTE bits_32bppBGRA[] = {
333     255,0,0,255, 0,255,0,255, 0,0,255,255, 0,0,0,255,
334     0,255,255,255, 255,0,255,255, 255,255,0,255, 255,255,255,255};
335 static const struct bitmap_data testdata_32bppBGRA = {
336     &GUID_WICPixelFormat32bppBGRA, 32, bits_32bppBGRA, 4, 2, 96.0, 96.0};
337 
338 /* XP and 2003 use linear color conversion, later versions use sRGB gamma */
339 static const float bits_32bppGrayFloat_xp[] = {
340     0.114000f,0.587000f,0.299000f,0.000000f,
341     0.886000f,0.413000f,0.701000f,1.000000f};
342 static const struct bitmap_data testdata_32bppGrayFloat_xp = {
343     &GUID_WICPixelFormat32bppGrayFloat, 32, (const BYTE *)bits_32bppGrayFloat_xp, 4, 2, 96.0, 96.0};
344 
345 static const float bits_32bppGrayFloat[] = {
346     0.072200f,0.715200f,0.212600f,0.000000f,
347     0.927800f,0.284800f,0.787400f,1.000000f};
348 static const struct bitmap_data testdata_32bppGrayFloat = {
349     &GUID_WICPixelFormat32bppGrayFloat, 32, (const BYTE *)bits_32bppGrayFloat, 4, 2, 96.0, 96.0, &testdata_32bppGrayFloat_xp};
350 
351 static const BYTE bits_8bppGray_xp[] = {
352     29,150,76,0,
353     226,105,179,255};
354 static const struct bitmap_data testdata_8bppGray_xp = {
355     &GUID_WICPixelFormat8bppGray, 8, bits_8bppGray_xp, 4, 2, 96.0, 96.0};
356 
357 static const BYTE bits_8bppGray[] = {
358     76,220,127,0,
359     247,145,230,255};
360 static const struct bitmap_data testdata_8bppGray = {
361     &GUID_WICPixelFormat8bppGray, 8, bits_8bppGray, 4, 2, 96.0, 96.0, &testdata_8bppGray_xp};
362 
363 static const BYTE bits_24bppBGR_gray[] = {
364     76,76,76, 220,220,220, 127,127,127, 0,0,0,
365     247,247,247, 145,145,145, 230,230,230, 255,255,255};
366 static const struct bitmap_data testdata_24bppBGR_gray = {
367     &GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR_gray, 4, 2, 96.0, 96.0};
368 
369 static void test_conversion(const struct bitmap_data *src, const struct bitmap_data *dst, const char *name, BOOL todo)
370 {
371     BitmapTestSrc *src_obj;
372     IWICBitmapSource *dst_bitmap;
373     HRESULT hr;
374 
375     CreateTestBitmap(src, &src_obj);
376 
377     hr = WICConvertBitmapSource(dst->format, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
378     todo_wine_if (todo)
379         ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
380 
381     if (SUCCEEDED(hr))
382     {
383         compare_bitmap_data(dst, dst_bitmap, name);
384 
385         IWICBitmapSource_Release(dst_bitmap);
386     }
387 
388     DeleteTestBitmap(src_obj);
389 }
390 
391 static void test_invalid_conversion(void)
392 {
393     BitmapTestSrc *src_obj;
394     IWICBitmapSource *dst_bitmap;
395     HRESULT hr;
396 
397     CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
398 
399     /* convert to a non-pixel-format GUID */
400     hr = WICConvertBitmapSource(&GUID_VendorMicrosoft, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
401     ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "WICConvertBitmapSource returned %x\n", hr);
402 
403     DeleteTestBitmap(src_obj);
404 }
405 
406 static void test_default_converter(void)
407 {
408     BitmapTestSrc *src_obj;
409     IWICFormatConverter *converter;
410     BOOL can_convert = TRUE;
411     HRESULT hr;
412 
413     CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
414 
415     hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER,
416         &IID_IWICFormatConverter, (void**)&converter);
417     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
418     if (SUCCEEDED(hr))
419     {
420         hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA,
421             &GUID_WICPixelFormat32bppBGR, &can_convert);
422         ok(SUCCEEDED(hr), "CanConvert returned %x\n", hr);
423         ok(can_convert, "expected TRUE, got %i\n", can_convert);
424 
425         hr = IWICFormatConverter_Initialize(converter, &src_obj->IWICBitmapSource_iface,
426             &GUID_WICPixelFormat32bppBGR, WICBitmapDitherTypeNone, NULL, 0.0,
427             WICBitmapPaletteTypeCustom);
428         ok(SUCCEEDED(hr), "Initialize returned %x\n", hr);
429 
430         if (SUCCEEDED(hr))
431             compare_bitmap_data(&testdata_32bppBGR, (IWICBitmapSource*)converter, "default converter");
432 
433         IWICFormatConverter_Release(converter);
434     }
435 
436     DeleteTestBitmap(src_obj);
437 }
438 
439 typedef struct property_opt_test_data
440 {
441     LPCOLESTR name;
442     VARTYPE var_type;
443     VARTYPE initial_var_type;
444     int i_init_val;
445     float f_init_val;
446     BOOL skippable;
447 } property_opt_test_data;
448 
449 static const WCHAR wszTiffCompressionMethod[] = {'T','i','f','f','C','o','m','p','r','e','s','s','i','o','n','M','e','t','h','o','d',0};
450 static const WCHAR wszCompressionQuality[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
451 static const WCHAR wszInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0};
452 static const WCHAR wszFilterOption[] = {'F','i','l','t','e','r','O','p','t','i','o','n',0};
453 static const WCHAR wszImageQuality[] = {'I','m','a','g','e','Q','u','a','l','i','t','y',0};
454 static const WCHAR wszBitmapTransform[] = {'B','i','t','m','a','p','T','r','a','n','s','f','o','r','m',0};
455 static const WCHAR wszLuminance[] = {'L','u','m','i','n','a','n','c','e',0};
456 static const WCHAR wszChrominance[] = {'C','h','r','o','m','i','n','a','n','c','e',0};
457 static const WCHAR wszJpegYCrCbSubsampling[] = {'J','p','e','g','Y','C','r','C','b','S','u','b','s','a','m','p','l','i','n','g',0};
458 static const WCHAR wszSuppressApp0[] = {'S','u','p','p','r','e','s','s','A','p','p','0',0};
459 
460 static const struct property_opt_test_data testdata_tiff_props[] = {
461     { wszTiffCompressionMethod, VT_UI1,         VT_UI1,  WICTiffCompressionDontCare },
462     { wszCompressionQuality,    VT_R4,          VT_EMPTY },
463     { NULL }
464 };
465 
466 static const struct property_opt_test_data testdata_png_props[] = {
467     { wszInterlaceOption, VT_BOOL, VT_BOOL, 0 },
468     { wszFilterOption,    VT_UI1,  VT_UI1, WICPngFilterUnspecified, 0.0f, TRUE /* not supported on XP/2k3 */},
469     { NULL }
470 };
471 
472 static const struct property_opt_test_data testdata_jpeg_props[] = {
473     { wszImageQuality,         VT_R4,           VT_EMPTY },
474     { wszBitmapTransform,      VT_UI1,          VT_UI1, WICBitmapTransformRotate0 },
475     { wszLuminance,            VT_I4|VT_ARRAY,  VT_EMPTY },
476     { wszChrominance,          VT_I4|VT_ARRAY,  VT_EMPTY },
477     { wszJpegYCrCbSubsampling, VT_UI1,          VT_UI1, WICJpegYCrCbSubsamplingDefault, 0.0f, TRUE }, /* not supported on XP/2k3 */
478     { wszSuppressApp0,         VT_BOOL,         VT_BOOL, FALSE },
479     { NULL }
480 };
481 
482 static int find_property_index(const WCHAR* name, PROPBAG2* all_props, int all_prop_cnt)
483 {
484     int i;
485     for (i=0; i < all_prop_cnt; i++)
486     {
487         if (lstrcmpW(name, all_props[i].pstrName) == 0)
488             return i;
489     }
490     return -1;
491 }
492 
493 static void test_specific_encoder_properties(IPropertyBag2 *options, const property_opt_test_data* data, PROPBAG2* all_props, int all_prop_cnt)
494 {
495     HRESULT hr;
496     int i = 0;
497     VARIANT pvarValue;
498     HRESULT phrError = S_OK;
499 
500     while (data[i].name)
501     {
502         int idx = find_property_index(data[i].name, all_props, all_prop_cnt);
503         PROPBAG2 pb = {0};
504         pb.pstrName = (LPOLESTR)data[i].name;
505 
506         hr = IPropertyBag2_Read(options, 1, &pb, NULL, &pvarValue, &phrError);
507 
508         if (data[i].skippable && idx == -1)
509         {
510             win_skip("Property %s is not supported on this machine.\n", wine_dbgstr_w(data[i].name));
511             i++;
512             continue;
513         }
514 
515         ok(idx >= 0, "Property %s not in output of GetPropertyInfo\n",
516            wine_dbgstr_w(data[i].name));
517         if (idx >= 0)
518         {
519             ok(all_props[idx].vt == data[i].var_type, "Property %s has unexpected vt type, vt=%i\n",
520                wine_dbgstr_w(data[i].name), all_props[idx].vt);
521             ok(all_props[idx].dwType == PROPBAG2_TYPE_DATA, "Property %s has unexpected dw type, vt=%i\n",
522                wine_dbgstr_w(data[i].name), all_props[idx].dwType);
523             ok(all_props[idx].cfType == 0, "Property %s has unexpected cf type, vt=%i\n",
524                wine_dbgstr_w(data[i].name), all_props[idx].cfType);
525         }
526 
527         ok(SUCCEEDED(hr), "Reading property %s from bag failed, hr=%x\n",
528            wine_dbgstr_w(data[i].name), hr);
529 
530         if (SUCCEEDED(hr))
531         {
532             /* On XP the initial type is always VT_EMPTY */
533             ok(V_VT(&pvarValue) == data[i].initial_var_type || V_VT(&pvarValue) == VT_EMPTY,
534                "Property %s has unexpected initial type, V_VT=%i\n",
535                wine_dbgstr_w(data[i].name), V_VT(&pvarValue));
536 
537             if(V_VT(&pvarValue) == data[i].initial_var_type)
538             {
539                 switch (data[i].initial_var_type)
540                 {
541                     case VT_BOOL:
542                     case VT_UI1:
543                         ok(V_UNION(&pvarValue, bVal) == data[i].i_init_val, "Property %s has an unexpected initial value, pvarValue=%i\n",
544                            wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, bVal));
545                         break;
546                     case VT_R4:
547                         ok(V_UNION(&pvarValue, fltVal) == data[i].f_init_val, "Property %s has an unexpected initial value, pvarValue=%f\n",
548                            wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, fltVal));
549                         break;
550                     default:
551                         break;
552                 }
553             }
554 
555             VariantClear(&pvarValue);
556         }
557 
558         i++;
559     }
560 }
561 
562 static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *options)
563 {
564     HRESULT hr;
565     ULONG cProperties = 0;
566     ULONG cProperties2 = 0;
567     PROPBAG2 all_props[64] = {{0}}; /* Should be enough for every encoder out there */
568     int i;
569 
570     /* CountProperties */
571     {
572         hr = IPropertyBag2_CountProperties(options, &cProperties);
573         ok(SUCCEEDED(hr), "Reading property count, hr=%x\n", hr);
574     }
575 
576     /* GetPropertyInfo */
577     {
578         hr = IPropertyBag2_GetPropertyInfo(options, cProperties, 1, all_props, &cProperties2);
579         ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - iProperty out of bounce handled wrong, hr=%x\n", hr);
580 
581         hr = IPropertyBag2_GetPropertyInfo(options, 0, cProperties+1, all_props, &cProperties2);
582         ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - cProperty out of bounce handled wrong, hr=%x\n", hr);
583 
584         if (cProperties == 0) /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
585         {
586             cProperties2 = cProperties;
587             hr = S_OK;
588         }
589         else
590         {
591             hr = IPropertyBag2_GetPropertyInfo(options, 0, min(64, cProperties), all_props, &cProperties2);
592             ok(SUCCEEDED(hr), "Reading infos from property bag failed, hr=%x\n", hr);
593         }
594 
595         if (FAILED(hr))
596             return;
597 
598         ok(cProperties == cProperties2, "Mismatch of property count (IPropertyBag2::CountProperties=%i, IPropertyBag2::GetPropertyInfo=%i)\n",
599            (int)cProperties, (int)cProperties2);
600     }
601 
602     if (IsEqualCLSID(clsid_encoder, &CLSID_WICTiffEncoder))
603         test_specific_encoder_properties(options, testdata_tiff_props, all_props, cProperties2);
604     else if (IsEqualCLSID(clsid_encoder, &CLSID_WICPngEncoder))
605         test_specific_encoder_properties(options, testdata_png_props, all_props, cProperties2);
606     else if (IsEqualCLSID(clsid_encoder, &CLSID_WICJpegEncoder))
607         test_specific_encoder_properties(options, testdata_jpeg_props, all_props, cProperties2);
608 
609     for (i=0; i < cProperties2; i++)
610     {
611         ok(all_props[i].pstrName != NULL, "Unset property name in output of IPropertyBag2::GetPropertyInfo\n");
612         CoTaskMemFree(all_props[i].pstrName);
613     }
614 }
615 
616 static void check_bmp_format(IStream *stream, const WICPixelFormatGUID *format)
617 {
618     /* FIXME */
619 }
620 
621 static void check_tiff_format(IStream *stream, const WICPixelFormatGUID *format)
622 {
623     /* FIXME */
624 }
625 
626 static unsigned be_uint(unsigned val)
627 {
628     union
629     {
630         unsigned val;
631         char c[4];
632     } u;
633 
634     u.val = val;
635     return (u.c[0] << 24) | (u.c[1] << 16) | (u.c[2] << 8) | u.c[3];
636 }
637 
638 static void check_png_format(IStream *stream, const WICPixelFormatGUID *format)
639 {
640     static const char png_sig[8] = {0x89,'P','N','G',0x0d,0x0a,0x1a,0x0a};
641     static const char png_IHDR[8] = {0,0,0,0x0d,'I','H','D','R'};
642     HRESULT hr;
643     struct
644     {
645         char png_sig[8];
646         char ihdr_sig[8];
647         unsigned width, height;
648         char bit_depth, color_type, compression, filter, interlace;
649     } png;
650 
651     memset(&png, 0, sizeof(png));
652     hr = IStream_Read(stream, &png, sizeof(png), NULL);
653     ok(hr == S_OK, "IStream_Read error %#x\n", hr);
654 
655     ok(!memcmp(png.png_sig, png_sig, sizeof(png_sig)), "expected PNG signature\n");
656     ok(!memcmp(png.ihdr_sig, png_IHDR, sizeof(png_IHDR)), "expected PNG IHDR\n");
657 
658     if (IsEqualGUID(format, &GUID_WICPixelFormatBlackWhite))
659     {
660         ok(be_uint(png.width) == 32, "wrong width %u\n", be_uint(png.width));
661         ok(be_uint(png.height) == 2, "wrong height %u\n", be_uint(png.height));
662 
663         ok(png.bit_depth == 1, "wrong bit_depth %d\n", png.bit_depth);
664         ok(png.color_type == 0, "wrong color_type %d\n", png.color_type);
665         ok(png.compression == 0, "wrong compression %d\n", png.compression);
666         ok(png.filter == 0, "wrong filter %d\n", png.filter);
667         ok(png.interlace == 0, "wrong interlace %d\n", png.interlace);
668     }
669     else if (IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed))
670     {
671         ok(be_uint(png.width) == 32, "wrong width %u\n", be_uint(png.width));
672         ok(be_uint(png.height) == 2, "wrong height %u\n", be_uint(png.height));
673 
674         ok(png.bit_depth == 1, "wrong bit_depth %d\n", png.bit_depth);
675         ok(png.color_type == 3, "wrong color_type %d\n", png.color_type);
676         ok(png.compression == 0, "wrong compression %d\n", png.compression);
677         ok(png.filter == 0, "wrong filter %d\n", png.filter);
678         ok(png.interlace == 0, "wrong interlace %d\n", png.interlace);
679     }
680     else if (IsEqualGUID(format, &GUID_WICPixelFormat8bppIndexed))
681     {
682         ok(be_uint(png.width) == 4, "wrong width %u\n", be_uint(png.width));
683         ok(be_uint(png.height) == 2, "wrong height %u\n", be_uint(png.height));
684 
685         ok(png.bit_depth == 8, "wrong bit_depth %d\n", png.bit_depth);
686         ok(png.color_type == 3, "wrong color_type %d\n", png.color_type);
687         ok(png.compression == 0, "wrong compression %d\n", png.compression);
688         ok(png.filter == 0, "wrong filter %d\n", png.filter);
689         ok(png.interlace == 0, "wrong interlace %d\n", png.interlace);
690     }
691     else if (IsEqualGUID(format, &GUID_WICPixelFormat24bppBGR))
692     {
693         ok(be_uint(png.width) == 4, "wrong width %u\n", be_uint(png.width));
694         ok(be_uint(png.height) == 2, "wrong height %u\n", be_uint(png.height));
695 
696         ok(png.bit_depth == 8, "wrong bit_depth %d\n", png.bit_depth);
697         ok(png.color_type == 2, "wrong color_type %d\n", png.color_type);
698         ok(png.compression == 0, "wrong compression %d\n", png.compression);
699         ok(png.filter == 0, "wrong filter %d\n", png.filter);
700         ok(png.interlace == 0 || png.interlace == 1, "wrong interlace %d\n", png.interlace);
701     }
702     else
703         ok(0, "unknown PNG pixel format %s\n", wine_dbgstr_guid(format));
704 }
705 
706 static void check_bitmap_format(IStream *stream, const CLSID *encoder, const WICPixelFormatGUID *format)
707 {
708     HRESULT hr;
709     LARGE_INTEGER pos;
710 
711     pos.QuadPart = 0;
712     hr = IStream_Seek(stream, pos, SEEK_SET, (ULARGE_INTEGER *)&pos);
713     ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
714 
715     if (IsEqualGUID(encoder, &CLSID_WICPngEncoder))
716         check_png_format(stream, format);
717     else if (IsEqualGUID(encoder, &CLSID_WICBmpEncoder))
718         check_bmp_format(stream, format);
719     else if (IsEqualGUID(encoder, &CLSID_WICTiffEncoder))
720         check_tiff_format(stream, format);
721     else
722         ok(0, "unknown encoder %s\n", wine_dbgstr_guid(encoder));
723 
724     hr = IStream_Seek(stream, pos, SEEK_SET, NULL);
725     ok(hr == S_OK, "IStream_Seek error %#x\n", hr);
726 }
727 
728 struct setting {
729     const WCHAR *name;
730     PROPBAG2_TYPE type;
731     VARTYPE vt;
732     void *value;
733 };
734 
735 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
736 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
737 {
738     ULONG rc;
739     IUnknown_AddRef(obj);
740     rc = IUnknown_Release(obj);
741     ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
742 }
743 
744 static void test_set_frame_palette(IWICBitmapFrameEncode *frameencode)
745 {
746     IWICComponentFactory *factory;
747     IWICPalette *palette;
748     HRESULT hr;
749 
750     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
751         &IID_IWICComponentFactory, (void **)&factory);
752     ok(hr == S_OK, "CoCreateInstance failed, hr=%x\n", hr);
753 
754     hr = IWICBitmapFrameEncode_SetPalette(frameencode, NULL);
755     ok(hr == E_INVALIDARG, "SetPalette failed, hr=%x\n", hr);
756 
757     hr = IWICComponentFactory_CreatePalette(factory, &palette);
758     ok(hr == S_OK, "CreatePalette failed, hr=%x\n", hr);
759 
760     hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
761 todo_wine
762     ok(hr == WINCODEC_ERR_NOTINITIALIZED, "Unexpected hr=%x\n", hr);
763 
764     hr = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedHalftone256, FALSE);
765     ok(hr == S_OK, "InitializePredefined failed, hr=%x\n", hr);
766 
767     EXPECT_REF(palette, 1);
768     hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
769     ok(hr == S_OK, "SetPalette failed, hr=%x\n", hr);
770     EXPECT_REF(palette, 1);
771 
772     hr = IWICBitmapFrameEncode_SetPalette(frameencode, NULL);
773     ok(hr == E_INVALIDARG, "SetPalette failed, hr=%x\n", hr);
774 
775     IWICPalette_Release(palette);
776     IWICComponentFactory_Release(factory);
777 }
778 
779 static void test_multi_encoder(const struct bitmap_data **srcs, const CLSID* clsid_encoder,
780     const struct bitmap_data **dsts, const CLSID *clsid_decoder, WICRect *rc,
781     const struct setting *settings, const char *name, IWICPalette *palette)
782 {
783     HRESULT hr;
784     IWICBitmapEncoder *encoder;
785     BitmapTestSrc *src_obj;
786     HGLOBAL hglobal;
787     IStream *stream;
788     IWICBitmapFrameEncode *frameencode;
789     IPropertyBag2 *options=NULL;
790     IWICBitmapDecoder *decoder;
791     IWICBitmapFrameDecode *framedecode;
792     WICPixelFormatGUID pixelformat;
793     int i;
794 
795     hr = CoCreateInstance(clsid_encoder, NULL, CLSCTX_INPROC_SERVER,
796         &IID_IWICBitmapEncoder, (void**)&encoder);
797     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
798     if (SUCCEEDED(hr))
799     {
800         hglobal = GlobalAlloc(GMEM_MOVEABLE, 0);
801         ok(hglobal != NULL, "GlobalAlloc failed\n");
802         if (hglobal)
803         {
804             hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
805             ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
806         }
807 
808         if (hglobal && SUCCEEDED(hr))
809         {
810             if (palette)
811             {
812                 hr = IWICBitmapEncoder_SetPalette(encoder, palette);
813                 ok(hr == WINCODEC_ERR_NOTINITIALIZED, "wrong error %#x (%s)\n", hr, name);
814             }
815 
816             hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
817             ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
818 
819             if (palette)
820             {
821                 hr = IWICBitmapEncoder_SetPalette(encoder, palette);
822                 ok(hr == WINCODEC_ERR_UNSUPPORTEDOPERATION, "wrong error %#x\n", hr);
823                 hr = S_OK;
824             }
825 
826             i=0;
827             while (SUCCEEDED(hr) && srcs[i])
828             {
829                 CreateTestBitmap(srcs[i], &src_obj);
830 
831                 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &options);
832                 ok(SUCCEEDED(hr), "CreateFrame failed, hr=%x\n", hr);
833                 if (SUCCEEDED(hr))
834                 {
835                     ok(options != NULL, "Encoder initialization has not created an property bag\n");
836                     if(options)
837                         test_encoder_properties(clsid_encoder, options);
838 
839                     if (settings)
840                     {
841                         int j;
842                         for (j=0; settings[j].name; j++)
843                         {
844                             PROPBAG2 propbag;
845                             VARIANT var;
846 
847                             memset(&propbag, 0, sizeof(propbag));
848                             memset(&var, 0, sizeof(var));
849                             propbag.pstrName = (LPOLESTR)settings[j].name;
850                             propbag.dwType = settings[j].type;
851                             V_VT(&var) = settings[j].vt;
852                             V_UNKNOWN(&var) = settings[j].value;
853 
854                             hr = IPropertyBag2_Write(options, 1, &propbag, &var);
855                             ok(SUCCEEDED(hr), "Writing property %s failed, hr=%x\n", wine_dbgstr_w(settings[j].name), hr);
856                         }
857                     }
858 
859                     if (palette)
860                     {
861                         hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
862                         ok(hr == WINCODEC_ERR_NOTINITIALIZED, "wrong error %#x\n", hr);
863                     }
864 
865                     hr = IWICBitmapFrameEncode_Initialize(frameencode, options);
866                     ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
867 
868                     memcpy(&pixelformat, srcs[i]->format, sizeof(GUID));
869                     hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &pixelformat);
870                     ok(SUCCEEDED(hr), "SetPixelFormat failed, hr=%x\n", hr);
871                     ok(IsEqualGUID(&pixelformat, dsts[i]->format), "SetPixelFormat changed the format to %s (%s)\n",
872                        wine_dbgstr_guid(&pixelformat), name);
873 
874                     hr = IWICBitmapFrameEncode_SetSize(frameencode, srcs[i]->width, srcs[i]->height);
875                     ok(SUCCEEDED(hr), "SetSize failed, hr=%x\n", hr);
876 
877                     if (IsEqualGUID(clsid_encoder, &CLSID_WICPngEncoder))
878                         test_set_frame_palette(frameencode);
879 
880                     if (palette)
881                     {
882                         WICColor colors[256];
883 
884                         hr = IWICBitmapFrameEncode_SetPalette(frameencode, palette);
885                         ok(SUCCEEDED(hr), "SetPalette failed, hr=%x (%s)\n", hr, name);
886 
887                         /* trash the assigned palette */
888                         memset(colors, 0, sizeof(colors));
889                         hr = IWICPalette_InitializeCustom(palette, colors, 256);
890                         ok(hr == S_OK, "InitializeCustom error %#x\n", hr);
891                     }
892 
893                     hr = IWICBitmapFrameEncode_WriteSource(frameencode, &src_obj->IWICBitmapSource_iface, rc);
894                     if (rc && (rc->Width <= 0 || rc->Height <= 0))
895                     {
896                         /* WriteSource fails but WriteSource_Proxy succeeds. */
897                         ok(hr == E_INVALIDARG, "WriteSource should fail, hr=%x (%s)\n", hr, name);
898                         hr = IWICBitmapFrameEncode_WriteSource_Proxy(frameencode, &src_obj->IWICBitmapSource_iface, rc);
899                         ok(SUCCEEDED(hr), "WriteSource_Proxy failed, %dx%d, hr=%x (%s)\n", rc->Width, rc->Height, hr, name);
900                     }
901                     else
902                     {
903                         if (rc)
904                             ok(SUCCEEDED(hr), "WriteSource(%dx%d) failed, hr=%x (%s)\n", rc->Width, rc->Height, hr, name);
905                         else
906                             ok(hr == S_OK ||
907                                broken(hr == E_INVALIDARG && IsEqualGUID(clsid_encoder, &CLSID_WICBmpEncoder) && IsEqualGUID(srcs[i]->format, &GUID_WICPixelFormatBlackWhite)) /* XP */,
908                                "WriteSource(NULL) failed, hr=%x (%s)\n", hr, name);
909                     }
910 
911                     if (SUCCEEDED(hr))
912                     {
913                         hr = IWICBitmapFrameEncode_Commit(frameencode);
914                         ok(SUCCEEDED(hr), "Commit failed, hr=%x (%s)\n", hr, name);
915                     }
916 
917                     IWICBitmapFrameEncode_Release(frameencode);
918                     IPropertyBag2_Release(options);
919                 }
920 
921                 DeleteTestBitmap(src_obj);
922 
923                 i++;
924             }
925 
926             if (clsid_decoder == NULL)
927             {
928                 IStream_Release(stream);
929                 IWICBitmapEncoder_Release(encoder);
930                 return;
931             }
932 
933             if (SUCCEEDED(hr))
934             {
935                 hr = IWICBitmapEncoder_Commit(encoder);
936                 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
937 
938                 check_bitmap_format(stream, clsid_encoder, dsts[0]->format);
939             }
940 
941             if (SUCCEEDED(hr))
942             {
943                 hr = CoCreateInstance(clsid_decoder, NULL, CLSCTX_INPROC_SERVER,
944                     &IID_IWICBitmapDecoder, (void**)&decoder);
945                 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
946             }
947 
948             if (SUCCEEDED(hr))
949             {
950                 IWICPalette *frame_palette;
951 
952                 hr = IWICImagingFactory_CreatePalette(factory, &frame_palette);
953                 ok(hr == S_OK, "CreatePalette error %#x\n", hr);
954 
955                 hr = IWICBitmapDecoder_CopyPalette(decoder, frame_palette);
956                 ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, "wrong error %#x\n", hr);
957 
958                 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand);
959                 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
960 
961                 hr = IWICBitmapDecoder_CopyPalette(decoder, frame_palette);
962                 ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, "wrong error %#x\n", hr);
963 
964                 hr = S_OK;
965                 i=0;
966                 while (SUCCEEDED(hr) && dsts[i])
967                 {
968                     hr = IWICBitmapDecoder_GetFrame(decoder, i, &framedecode);
969                     ok(SUCCEEDED(hr), "GetFrame failed, hr=%x (%s)\n", hr, name);
970 
971                     if (SUCCEEDED(hr))
972                     {
973                         compare_bitmap_data(dsts[i], (IWICBitmapSource*)framedecode, name);
974 
975                         hr = IWICBitmapFrameDecode_CopyPalette(framedecode, frame_palette);
976                         if (winetest_debug > 1)
977                             trace("%s, bpp %d, %s, hr %#x\n", name, dsts[i]->bpp, wine_dbgstr_guid(dsts[i]->format), hr);
978                         if (dsts[i]->bpp > 8 || IsEqualGUID(dsts[i]->format, &GUID_WICPixelFormatBlackWhite))
979                             ok(hr == WINCODEC_ERR_PALETTEUNAVAILABLE, "wrong error %#x\n", hr);
980                         else
981                         {
982                             UINT count, ret;
983                             WICColor colors[256];
984 
985                             ok(hr == S_OK, "CopyPalette error %#x (%s)\n", hr, name);
986 
987                             count = 0;
988                             hr = IWICPalette_GetColorCount(frame_palette, &count);
989                             ok(hr == S_OK, "GetColorCount error %#x\n", hr);
990 
991                             memset(colors, 0, sizeof(colors));
992                             ret = 0;
993                             hr = IWICPalette_GetColors(frame_palette, count, colors, &ret);
994                             ok(hr == S_OK, "GetColors error %#x\n", hr);
995                             ok(ret == count, "expected %u, got %u\n", count, ret);
996                             if (IsEqualGUID(clsid_decoder, &CLSID_WICPngDecoder))
997                             {
998                                 ok(count == 256 || count == 2 /* newer libpng versions */, "expected 256, got %u (%s)\n", count, name);
999 
1000                                 ok(colors[0] == 0x11111111, "got %08x (%s)\n", colors[0], name);
1001                                 ok(colors[1] == 0x22222222, "got %08x (%s)\n", colors[1], name);
1002                                 if (count > 2)
1003                                 {
1004                                     ok(colors[2] == 0x33333333, "got %08x (%s)\n", colors[2], name);
1005                                     ok(colors[3] == 0x44444444, "got %08x (%s)\n", colors[3], name);
1006                                     ok(colors[4] == 0x55555555, "got %08x (%s)\n", colors[4], name);
1007                                     ok(colors[5] == 0, "got %08x (%s)\n", colors[5], name);
1008                                 }
1009                             }
1010                             else if (IsEqualGUID(clsid_decoder, &CLSID_WICBmpDecoder) ||
1011                                      IsEqualGUID(clsid_decoder, &CLSID_WICTiffDecoder))
1012                             {
1013                                 if (IsEqualGUID(dsts[i]->format, &GUID_WICPixelFormatBlackWhite) ||
1014                                     IsEqualGUID(dsts[i]->format, &GUID_WICPixelFormat8bppIndexed))
1015                                 {
1016                                     ok(count == 256, "expected 256, got %u (%s)\n", count, name);
1017 
1018                                     ok(colors[0] == 0xff111111, "got %08x (%s)\n", colors[0], name);
1019                                     ok(colors[1] == 0xff222222, "got %08x (%s)\n", colors[1], name);
1020                                     ok(colors[2] == 0xff333333, "got %08x (%s)\n", colors[2], name);
1021                                     ok(colors[3] == 0xff444444, "got %08x (%s)\n", colors[3], name);
1022                                     ok(colors[4] == 0xff555555, "got %08x (%s)\n", colors[4], name);
1023                                     ok(colors[5] == 0xff000000, "got %08x (%s)\n", colors[5], name);
1024                                 }
1025                                 else
1026                                 {
1027                                     ok(count == 2, "expected 2, got %u (%s)\n", count, name);
1028 
1029                                     ok(colors[0] == 0xff111111, "got %08x (%s)\n", colors[0], name);
1030                                     ok(colors[1] == 0xff222222, "got %08x (%s)\n", colors[1], name);
1031                                 }
1032                             }
1033                             else
1034                             {
1035                                 ok(count == 2, "expected 2, got %u (%s)\n", count, name);
1036 
1037                                 ok(colors[0] == 0xff111111, "got %08x\n", colors[0]);
1038                                 ok(colors[1] == 0xff222222, "got %08x\n", colors[1]);
1039                             }
1040                         }
1041 
1042                         IWICBitmapFrameDecode_Release(framedecode);
1043                     }
1044 
1045                     i++;
1046                 }
1047 
1048                 IWICPalette_Release(frame_palette);
1049                 IWICBitmapDecoder_Release(decoder);
1050             }
1051 
1052             IStream_Release(stream);
1053         }
1054 
1055         IWICBitmapEncoder_Release(encoder);
1056     }
1057 }
1058 
1059 static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encoder,
1060     const struct bitmap_data *dst, const CLSID *clsid_decoder, const char *name)
1061 {
1062     const struct bitmap_data *srcs[2];
1063     const struct bitmap_data *dsts[2];
1064     WICColor colors[256];
1065     IWICPalette *palette;
1066     HRESULT hr;
1067 
1068     hr = IWICImagingFactory_CreatePalette(factory, &palette);
1069     ok(hr == S_OK, "CreatePalette error %#x\n", hr);
1070 
1071     memset(colors, 0, sizeof(colors));
1072     colors[0] = 0x11111111;
1073     colors[1] = 0x22222222;
1074     colors[2] = 0x33333333;
1075     colors[3] = 0x44444444;
1076     colors[4] = 0x55555555;
1077     /* TIFF decoder fails to decode a 8bpp frame if palette has less than 256 colors */
1078     hr = IWICPalette_InitializeCustom(palette, colors, 256);
1079     ok(hr == S_OK, "InitializeCustom error %#x\n", hr);
1080 
1081     srcs[0] = src;
1082     srcs[1] = NULL;
1083     dsts[0] = dst;
1084     dsts[1] = NULL;
1085 
1086     test_multi_encoder(srcs, clsid_encoder, dsts, clsid_decoder, NULL, NULL, name, palette);
1087 
1088     IWICPalette_Release(palette);
1089 }
1090 
1091 static void test_encoder_rects(void)
1092 {
1093     const struct bitmap_data *srcs[2];
1094     const struct bitmap_data *dsts[2];
1095     WICRect rc;
1096 
1097     srcs[0] = &testdata_24bppBGR;
1098     srcs[1] = NULL;
1099     dsts[0] = &testdata_24bppBGR;
1100     dsts[1] = NULL;
1101 
1102     rc.X = 0;
1103     rc.Y = 0;
1104     rc.Width = 4;
1105     rc.Height = 2;
1106 
1107     test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects full", NULL);
1108 
1109     rc.Width = 0;
1110     test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects width=0", NULL);
1111 
1112     rc.Width = -1;
1113     test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects width=-1", NULL);
1114 
1115     rc.Width = 4;
1116     rc.Height = 0;
1117     test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects height=0", NULL);
1118 
1119     rc.Height = -1;
1120     test_multi_encoder(srcs, &CLSID_WICTiffEncoder, dsts, &CLSID_WICTiffDecoder, &rc, NULL, "test_encoder_rects height=-1", NULL);
1121 }
1122 
1123 static const struct bitmap_data *multiple_frames[3] = {
1124     &testdata_24bppBGR,
1125     &testdata_24bppBGR,
1126     NULL};
1127 
1128 static const struct bitmap_data *single_frame[2] = {
1129     &testdata_24bppBGR,
1130     NULL};
1131 
1132 static const struct setting png_interlace_settings[] = {
1133     {wszInterlaceOption, PROPBAG2_TYPE_DATA, VT_BOOL, (void*)VARIANT_TRUE},
1134     {NULL}
1135 };
1136 
1137 START_TEST(converter)
1138 {
1139     HRESULT hr;
1140 
1141     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1142 
1143     hr = CoCreateInstance(&CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
1144                           &IID_IWICImagingFactory, (void **)&factory);
1145     ok(hr == S_OK, "failed to create factory: %#x\n", hr);
1146 
1147     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGR, "BGRA -> BGR", FALSE);
1148     test_conversion(&testdata_32bppBGR, &testdata_32bppBGRA, "BGR -> BGRA", FALSE);
1149     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGRA, "BGRA -> BGRA", FALSE);
1150 
1151     test_conversion(&testdata_24bppBGR, &testdata_24bppBGR, "24bppBGR -> 24bppBGR", FALSE);
1152     test_conversion(&testdata_24bppBGR, &testdata_24bppRGB, "24bppBGR -> 24bppRGB", FALSE);
1153 
1154     test_conversion(&testdata_24bppRGB, &testdata_24bppRGB, "24bppRGB -> 24bppRGB", FALSE);
1155     test_conversion(&testdata_24bppRGB, &testdata_24bppBGR, "24bppRGB -> 24bppBGR", FALSE);
1156 
1157     test_conversion(&testdata_32bppBGR, &testdata_24bppRGB, "32bppBGR -> 24bppRGB", FALSE);
1158     test_conversion(&testdata_24bppRGB, &testdata_32bppBGR, "24bppRGB -> 32bppBGR", FALSE);
1159     test_conversion(&testdata_32bppBGRA, &testdata_24bppRGB, "32bppBGRA -> 24bppRGB", FALSE);
1160 
1161     test_conversion(&testdata_24bppRGB, &testdata_32bppGrayFloat, "24bppRGB -> 32bppGrayFloat", FALSE);
1162     test_conversion(&testdata_32bppBGR, &testdata_32bppGrayFloat, "32bppBGR -> 32bppGrayFloat", FALSE);
1163 
1164     test_conversion(&testdata_24bppBGR, &testdata_8bppGray, "24bppBGR -> 8bppGray", FALSE);
1165     test_conversion(&testdata_32bppBGR, &testdata_8bppGray, "32bppBGR -> 8bppGray", FALSE);
1166     test_conversion(&testdata_32bppGrayFloat, &testdata_24bppBGR_gray, "32bppGrayFloat -> 24bppBGR gray", FALSE);
1167     test_conversion(&testdata_32bppGrayFloat, &testdata_8bppGray, "32bppGrayFloat -> 8bppGray", FALSE);
1168 
1169     test_invalid_conversion();
1170     test_default_converter();
1171 
1172     test_encoder(&testdata_BlackWhite, &CLSID_WICPngEncoder,
1173                  &testdata_BlackWhite, &CLSID_WICPngDecoder, "PNG encoder BlackWhite");
1174     test_encoder(&testdata_1bppIndexed, &CLSID_WICPngEncoder,
1175                  &testdata_1bppIndexed, &CLSID_WICPngDecoder, "PNG encoder 1bppIndexed");
1176     test_encoder(&testdata_8bppIndexed, &CLSID_WICPngEncoder,
1177                  &testdata_8bppIndexed, &CLSID_WICPngDecoder, "PNG encoder 8bppIndexed");
1178     test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
1179                  &testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
1180 
1181 if (!strcmp(winetest_platform, "windows")) /* FIXME: enable once implemented in Wine */
1182 {
1183     test_encoder(&testdata_BlackWhite, &CLSID_WICBmpEncoder,
1184                  &testdata_1bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder BlackWhite");
1185     test_encoder(&testdata_1bppIndexed, &CLSID_WICBmpEncoder,
1186                  &testdata_1bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 1bppIndexed");
1187     test_encoder(&testdata_8bppIndexed, &CLSID_WICBmpEncoder,
1188                  &testdata_8bppIndexed, &CLSID_WICBmpDecoder, "BMP encoder 8bppIndexed");
1189 }
1190     test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
1191                  &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
1192 
1193     test_encoder(&testdata_BlackWhite, &CLSID_WICTiffEncoder,
1194                  &testdata_BlackWhite, &CLSID_WICTiffDecoder, "TIFF encoder BlackWhite");
1195 if (!strcmp(winetest_platform, "windows")) /* FIXME: enable once implemented in Wine */
1196 {
1197     test_encoder(&testdata_1bppIndexed, &CLSID_WICTiffEncoder,
1198                  &testdata_1bppIndexed, &CLSID_WICTiffDecoder, "TIFF encoder 1bppIndexed");
1199     test_encoder(&testdata_8bppIndexed, &CLSID_WICTiffEncoder,
1200                  &testdata_8bppIndexed, &CLSID_WICTiffDecoder, "TIFF encoder 8bppIndexed");
1201 }
1202     test_encoder(&testdata_24bppBGR, &CLSID_WICTiffEncoder,
1203                  &testdata_24bppBGR, &CLSID_WICTiffDecoder, "TIFF encoder 24bppBGR");
1204 
1205     test_encoder(&testdata_24bppBGR, &CLSID_WICJpegEncoder,
1206                  &testdata_24bppBGR, NULL, "JPEG encoder 24bppBGR");
1207 
1208     test_multi_encoder(multiple_frames, &CLSID_WICTiffEncoder,
1209                        multiple_frames, &CLSID_WICTiffDecoder, NULL, NULL, "TIFF encoder multi-frame", NULL);
1210 
1211     test_encoder_rects();
1212 
1213     test_multi_encoder(single_frame, &CLSID_WICPngEncoder,
1214                        single_frame, &CLSID_WICPngDecoder, NULL, png_interlace_settings, "PNG encoder interlaced", NULL);
1215 
1216     IWICImagingFactory_Release(factory);
1217 
1218     CoUninitialize();
1219 }
1220