Release 1.5.29.
[wine] / dlls / windowscodecs / tests / converter.c
1 /*
2  * Copyright 2009 Vincent Povirk
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20 #include <math.h>
21
22 #define COBJMACROS
23 #define CONST_VTABLE
24
25 #include "windef.h"
26 #include "objbase.h"
27 #include "wincodec.h"
28 #include "wine/test.h"
29
30 typedef struct bitmap_data {
31     const WICPixelFormatGUID *format;
32     UINT bpp;
33     const BYTE *bits;
34     UINT width;
35     UINT height;
36     double xres;
37     double yres;
38 } bitmap_data;
39
40 typedef struct BitmapTestSrc {
41     IWICBitmapSource IWICBitmapSource_iface;
42     LONG ref;
43     const bitmap_data *data;
44 } BitmapTestSrc;
45
46 static inline BitmapTestSrc *impl_from_IWICBitmapSource(IWICBitmapSource *iface)
47 {
48     return CONTAINING_RECORD(iface, BitmapTestSrc, IWICBitmapSource_iface);
49 }
50
51 static HRESULT WINAPI BitmapTestSrc_QueryInterface(IWICBitmapSource *iface, REFIID iid,
52     void **ppv)
53 {
54     if (!ppv) return E_INVALIDARG;
55
56     if (IsEqualIID(&IID_IUnknown, iid) ||
57         IsEqualIID(&IID_IWICBitmapSource, iid))
58         *ppv = iface;
59     else
60         return E_NOINTERFACE;
61
62     IUnknown_AddRef((IUnknown*)*ppv);
63     return S_OK;
64 }
65
66 static ULONG WINAPI BitmapTestSrc_AddRef(IWICBitmapSource *iface)
67 {
68     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
69     ULONG ref = InterlockedIncrement(&This->ref);
70     return ref;
71 }
72
73 static ULONG WINAPI BitmapTestSrc_Release(IWICBitmapSource *iface)
74 {
75     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
76     ULONG ref = InterlockedDecrement(&This->ref);
77     return ref;
78 }
79
80 static HRESULT WINAPI BitmapTestSrc_GetSize(IWICBitmapSource *iface,
81     UINT *puiWidth, UINT *puiHeight)
82 {
83     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
84     *puiWidth = This->data->width;
85     *puiHeight = This->data->height;
86     return S_OK;
87 }
88
89 static HRESULT WINAPI BitmapTestSrc_GetPixelFormat(IWICBitmapSource *iface,
90     WICPixelFormatGUID *pPixelFormat)
91 {
92     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
93     memcpy(pPixelFormat, This->data->format, sizeof(GUID));
94     return S_OK;
95 }
96
97 static HRESULT WINAPI BitmapTestSrc_GetResolution(IWICBitmapSource *iface,
98     double *pDpiX, double *pDpiY)
99 {
100     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
101     *pDpiX = This->data->xres;
102     *pDpiY = This->data->yres;
103     return S_OK;
104 }
105
106 static HRESULT WINAPI BitmapTestSrc_CopyPalette(IWICBitmapSource *iface,
107     IWICPalette *pIPalette)
108 {
109     return E_NOTIMPL;
110 }
111
112 static HRESULT WINAPI BitmapTestSrc_CopyPixels(IWICBitmapSource *iface,
113     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
114 {
115     BitmapTestSrc *This = impl_from_IWICBitmapSource(iface);
116     UINT bytesperrow;
117     UINT srcstride;
118     UINT row_offset;
119     WICRect rc;
120
121     if (!prc)
122     {
123         rc.X = 0;
124         rc.Y = 0;
125         rc.Width = This->data->width;
126         rc.Height = This->data->height;
127         prc = &rc;
128     }
129     else
130     {
131         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->data->width || prc->Y+prc->Height > This->data->height)
132             return E_INVALIDARG;
133     }
134
135     bytesperrow = ((This->data->bpp * prc->Width)+7)/8;
136     srcstride = ((This->data->bpp * This->data->width)+7)/8;
137
138     if (cbStride < bytesperrow)
139         return E_INVALIDARG;
140
141     if ((cbStride * prc->Height) > cbBufferSize)
142         return E_INVALIDARG;
143
144     row_offset = prc->X * This->data->bpp;
145
146     if (row_offset % 8 == 0)
147     {
148         UINT row;
149         const BYTE *src;
150         BYTE *dst;
151
152         src = This->data->bits + (row_offset / 8) + prc->Y * srcstride;
153         dst = pbBuffer;
154         for (row=0; row < prc->Height; row++)
155         {
156             memcpy(dst, src, bytesperrow);
157             src += srcstride;
158             dst += cbStride;
159         }
160         return S_OK;
161     }
162     else
163     {
164         ok(0, "bitmap %p was asked to copy pixels not aligned on a byte boundary\n", iface);
165         return E_FAIL;
166     }
167 }
168
169 static const IWICBitmapSourceVtbl BitmapTestSrc_Vtbl = {
170     BitmapTestSrc_QueryInterface,
171     BitmapTestSrc_AddRef,
172     BitmapTestSrc_Release,
173     BitmapTestSrc_GetSize,
174     BitmapTestSrc_GetPixelFormat,
175     BitmapTestSrc_GetResolution,
176     BitmapTestSrc_CopyPalette,
177     BitmapTestSrc_CopyPixels
178 };
179
180 static void CreateTestBitmap(const bitmap_data *data, BitmapTestSrc **This)
181 {
182     *This = HeapAlloc(GetProcessHeap(), 0, sizeof(**This));
183
184     if (*This)
185     {
186         (*This)->IWICBitmapSource_iface.lpVtbl = &BitmapTestSrc_Vtbl;
187         (*This)->ref = 1;
188         (*This)->data = data;
189     }
190 }
191
192 static void DeleteTestBitmap(BitmapTestSrc *This)
193 {
194     ok(This->IWICBitmapSource_iface.lpVtbl == &BitmapTestSrc_Vtbl, "test bitmap %p deleted with incorrect vtable\n", This);
195     ok(This->ref == 1, "test bitmap %p deleted with %i references instead of 1\n", This, This->ref);
196     HeapFree(GetProcessHeap(), 0, This);
197 }
198
199 static void compare_bitmap_data(const struct bitmap_data *expect, IWICBitmapSource *source, const char *name)
200 {
201     BYTE *converted_bits;
202     UINT width, height;
203     double xres, yres;
204     WICRect prc;
205     UINT stride, buffersize;
206     GUID dst_pixelformat;
207     HRESULT hr;
208
209     hr = IWICBitmapSource_GetSize(source, &width, &height);
210     ok(SUCCEEDED(hr), "GetSize(%s) failed, hr=%x\n", name, hr);
211     ok(width == expect->width, "expecting %u, got %u (%s)\n", expect->width, width, name);
212     ok(height == expect->height, "expecting %u, got %u (%s)\n", expect->height, height, name);
213
214     hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
215     ok(SUCCEEDED(hr), "GetResolution(%s) failed, hr=%x\n", name, hr);
216     ok(fabs(xres - expect->xres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->xres, xres, name);
217     ok(fabs(yres - expect->yres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->yres, yres, name);
218
219     hr = IWICBitmapSource_GetPixelFormat(source, &dst_pixelformat);
220     ok(SUCCEEDED(hr), "GetPixelFormat(%s) failed, hr=%x\n", name, hr);
221     ok(IsEqualGUID(&dst_pixelformat, expect->format), "got unexpected pixel format (%s)\n", name);
222
223     prc.X = 0;
224     prc.Y = 0;
225     prc.Width = expect->width;
226     prc.Height = expect->height;
227
228     stride = (expect->bpp * expect->width + 7) / 8;
229     buffersize = stride * expect->height;
230
231     converted_bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
232     hr = IWICBitmapSource_CopyPixels(source, &prc, stride, buffersize, converted_bits);
233     ok(SUCCEEDED(hr), "CopyPixels(%s) failed, hr=%x\n", name, hr);
234     if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
235     {
236         /* ignore the padding byte when comparing data */
237         UINT i;
238         BOOL equal=TRUE;
239         const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
240         for (i=0; i<(buffersize/4); i++)
241             if ((a[i]&0xffffff) != (b[i]&0xffffff))
242             {
243                 equal = FALSE;
244                 break;
245             }
246         ok(equal, "unexpected pixel data (%s)\n", name);
247     }
248     else
249         ok(memcmp(expect->bits, converted_bits, buffersize) == 0, "unexpected pixel data (%s)\n", name);
250
251     /* Test with NULL rectangle - should copy the whole bitmap */
252     hr = IWICBitmapSource_CopyPixels(source, NULL, stride, buffersize, converted_bits);
253     ok(SUCCEEDED(hr), "CopyPixels(%s,rc=NULL) failed, hr=%x\n", name, hr);
254     if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
255     {
256         /* ignore the padding byte when comparing data */
257         UINT i;
258         BOOL equal=TRUE;
259         const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
260         for (i=0; i<(buffersize/4); i++)
261             if ((a[i]&0xffffff) != (b[i]&0xffffff))
262             {
263                 equal = FALSE;
264                 break;
265             }
266         ok(equal, "unexpected pixel data with rc=NULL (%s)\n", name);
267     }
268     else
269         ok(memcmp(expect->bits, converted_bits, buffersize) == 0, "unexpected pixel data with rc=NULL (%s)\n", name);
270
271     HeapFree(GetProcessHeap(), 0, converted_bits);
272 }
273
274 static const BYTE bits_24bppBGR[] = {
275     255,0,0, 0,255,0, 0,0,255, 0,0,0,
276     0,255,255, 255,0,255, 255,255,0, 255,255,255};
277 static const struct bitmap_data testdata_24bppBGR = {
278     &GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR, 4, 2, 96.0, 96.0};
279
280 static const BYTE bits_24bppRGB[] = {
281     0,0,255, 0,255,0, 255,0,0, 0,0,0,
282     255,255,0, 255,0,255, 0,255,255, 255,255,255};
283 static const struct bitmap_data testdata_24bppRGB = {
284     &GUID_WICPixelFormat24bppRGB, 24, bits_24bppRGB, 4, 2, 96.0, 96.0};
285
286 static const BYTE bits_32bppBGR[] = {
287     255,0,0,80, 0,255,0,80, 0,0,255,80, 0,0,0,80,
288     0,255,255,80, 255,0,255,80, 255,255,0,80, 255,255,255,80};
289 static const struct bitmap_data testdata_32bppBGR = {
290     &GUID_WICPixelFormat32bppBGR, 32, bits_32bppBGR, 4, 2, 96.0, 96.0};
291
292 static const BYTE bits_32bppBGRA[] = {
293     255,0,0,255, 0,255,0,255, 0,0,255,255, 0,0,0,255,
294     0,255,255,255, 255,0,255,255, 255,255,0,255, 255,255,255,255};
295 static const struct bitmap_data testdata_32bppBGRA = {
296     &GUID_WICPixelFormat32bppBGRA, 32, bits_32bppBGRA, 4, 2, 96.0, 96.0};
297
298 static void test_conversion(const struct bitmap_data *src, const struct bitmap_data *dst, const char *name, BOOL todo)
299 {
300     BitmapTestSrc *src_obj;
301     IWICBitmapSource *dst_bitmap;
302     HRESULT hr;
303
304     CreateTestBitmap(src, &src_obj);
305
306     hr = WICConvertBitmapSource(dst->format, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
307     if (todo)
308         todo_wine ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
309     else
310         ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
311
312     if (SUCCEEDED(hr))
313     {
314         compare_bitmap_data(dst, dst_bitmap, name);
315
316         IWICBitmapSource_Release(dst_bitmap);
317     }
318
319     DeleteTestBitmap(src_obj);
320 }
321
322 static void test_invalid_conversion(void)
323 {
324     BitmapTestSrc *src_obj;
325     IWICBitmapSource *dst_bitmap;
326     HRESULT hr;
327
328     CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
329
330     /* convert to a non-pixel-format GUID */
331     hr = WICConvertBitmapSource(&GUID_VendorMicrosoft, &src_obj->IWICBitmapSource_iface, &dst_bitmap);
332     ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "WICConvertBitmapSource returned %x\n", hr);
333
334     DeleteTestBitmap(src_obj);
335 }
336
337 static void test_default_converter(void)
338 {
339     BitmapTestSrc *src_obj;
340     IWICFormatConverter *converter;
341     BOOL can_convert=1;
342     HRESULT hr;
343
344     CreateTestBitmap(&testdata_32bppBGRA, &src_obj);
345
346     hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER,
347         &IID_IWICFormatConverter, (void**)&converter);
348     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
349     if (SUCCEEDED(hr))
350     {
351         hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA,
352             &GUID_WICPixelFormat32bppBGR, &can_convert);
353         ok(SUCCEEDED(hr), "CanConvert returned %x\n", hr);
354         ok(can_convert, "expected TRUE, got %i\n", can_convert);
355
356         hr = IWICFormatConverter_Initialize(converter, &src_obj->IWICBitmapSource_iface,
357             &GUID_WICPixelFormat32bppBGR, WICBitmapDitherTypeNone, NULL, 0.0,
358             WICBitmapPaletteTypeCustom);
359         ok(SUCCEEDED(hr), "Initialize returned %x\n", hr);
360
361         if (SUCCEEDED(hr))
362             compare_bitmap_data(&testdata_32bppBGR, (IWICBitmapSource*)converter, "default converter");
363
364         IWICFormatConverter_Release(converter);
365     }
366
367     DeleteTestBitmap(src_obj);
368 }
369
370 typedef struct property_opt_test_data
371 {
372     LPCOLESTR name;
373     VARTYPE var_type;
374     VARTYPE initial_var_type;
375     int i_init_val;
376     float f_init_val;
377 } property_opt_test_data;
378
379 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};
380 static const WCHAR wszCompressionQuality[] = {'C','o','m','p','r','e','s','s','i','o','n','Q','u','a','l','i','t','y',0};
381
382 static const struct property_opt_test_data testdata_tiff_props[] = {
383     { wszTiffCompressionMethod, VT_UI1,         VT_UI1,  WICTiffCompressionDontCare },
384     { wszCompressionQuality,    VT_R4,          VT_EMPTY },
385     { NULL }
386 };
387
388 static int find_property_index(const WCHAR* name, PROPBAG2* all_props, int all_prop_cnt)
389 {
390     int i;
391     for (i=0; i < all_prop_cnt; i++)
392     {
393         if (lstrcmpW(name, all_props[i].pstrName) == 0)
394             return i;
395     }
396     return -1;
397 }
398
399 static void test_specific_encoder_properties(IPropertyBag2 *options, const property_opt_test_data* data, PROPBAG2* all_props, int all_prop_cnt)
400 {
401     HRESULT hr;
402     int i = 0;
403     VARIANT pvarValue;
404     HRESULT phrError = S_OK;
405
406     while (data[i].name)
407     {
408         int idx = find_property_index(data[i].name, all_props, all_prop_cnt);
409         PROPBAG2 pb = {0};
410         pb.pstrName = (LPOLESTR)data[i].name;
411
412         hr = IPropertyBag2_Read(options, 1, &pb, NULL, &pvarValue, &phrError);
413
414         ok(idx >= 0, "Property %s not in output of GetPropertyInfo\n",
415            wine_dbgstr_w(data[i].name));
416         if (idx >= 0)
417         {
418             ok(all_props[idx].vt == data[i].var_type, "Property %s has unexpected vt type, vt=%i\n",
419                wine_dbgstr_w(data[i].name), all_props[idx].vt);
420             ok(all_props[idx].dwType == PROPBAG2_TYPE_DATA, "Property %s has unexpected dw type, vt=%i\n",
421                wine_dbgstr_w(data[i].name), all_props[idx].dwType);
422             ok(all_props[idx].cfType == 0, "Property %s has unexpected cf type, vt=%i\n",
423                wine_dbgstr_w(data[i].name), all_props[idx].cfType);
424         }
425
426         ok(SUCCEEDED(hr), "Reading property %s from bag failed, hr=%x\n",
427            wine_dbgstr_w(data[i].name), hr);
428
429         if (SUCCEEDED(hr))
430         {
431             /* On XP the initial type is always VT_EMPTY */
432             ok(V_VT(&pvarValue) == data[i].initial_var_type || V_VT(&pvarValue) == VT_EMPTY,
433                "Property %s has unexpected initial type, V_VT=%i\n",
434                wine_dbgstr_w(data[i].name), V_VT(&pvarValue));
435
436             if(V_VT(&pvarValue) == data[i].initial_var_type)
437             {
438                 switch (data[i].initial_var_type)
439                 {
440                     case VT_BOOL:
441                     case VT_UI1:
442                         ok(V_UNION(&pvarValue, bVal) == data[i].i_init_val, "Property %s has an unexpected initial value, pvarValue=%i\n",
443                            wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, bVal));
444                         break;
445                     case VT_R4:
446                         ok(V_UNION(&pvarValue, fltVal) == data[i].f_init_val, "Property %s has an unexpected initial value, pvarValue=%f\n",
447                            wine_dbgstr_w(data[i].name), V_UNION(&pvarValue, fltVal));
448                         break;
449                     default:
450                         break;
451                 }
452             }
453
454             VariantClear(&pvarValue);
455         }
456
457         i++;
458     }
459 }
460
461 static void test_encoder_properties(const CLSID* clsid_encoder, IPropertyBag2 *options)
462 {
463     HRESULT hr;
464     ULONG cProperties = 0;
465     ULONG cProperties2 = 0;
466     PROPBAG2 all_props[64] = {{0}}; /* Should be enough for every encoder out there */
467     int i;
468
469     /* CountProperties */
470     {
471         hr = IPropertyBag2_CountProperties(options, &cProperties);
472         ok(SUCCEEDED(hr), "Reading property count, hr=%x\n", hr);
473     }
474
475     /* GetPropertyInfo */
476     {
477         hr = IPropertyBag2_GetPropertyInfo(options, cProperties, 1, all_props, &cProperties2);
478         ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - iProperty out of bounce handled wrong, hr=%x\n", hr);
479
480         hr = IPropertyBag2_GetPropertyInfo(options, 0, cProperties+1, all_props, &cProperties2);
481         ok(hr == WINCODEC_ERR_VALUEOUTOFRANGE, "IPropertyBag2::GetPropertyInfo - cProperty out of bounce handled wrong, hr=%x\n", hr);
482
483         if (cProperties == 0) /* GetPropertyInfo can be called for zero items on Windows 8 but not on Windows 7 (wine behaves like Win8) */
484         {
485             cProperties2 = cProperties;
486             hr = S_OK;
487         }
488         else
489         {
490             hr = IPropertyBag2_GetPropertyInfo(options, 0, min(64, cProperties), all_props, &cProperties2);
491             ok(SUCCEEDED(hr), "Reading infos from property bag failed, hr=%x\n", hr);
492         }
493
494         if (FAILED(hr))
495             return;
496
497         ok(cProperties == cProperties2, "Missmatch of property count (IPropertyBag2::CountProperties=%i, IPropertyBag2::GetPropertyInfo=%i)\n",
498            (int)cProperties, (int)cProperties2);
499     }
500
501     if (clsid_encoder == &CLSID_WICTiffEncoder)
502         test_specific_encoder_properties(options, testdata_tiff_props, all_props, cProperties2);
503
504     for (i=0; i < cProperties2; i++)
505     {
506         ok(all_props[i].pstrName != NULL, "Unset property name in output of IPropertyBag2::GetPropertyInfo\n");
507         CoTaskMemFree(all_props[i].pstrName);
508     }
509 }
510
511 static void test_multi_encoder(const struct bitmap_data **srcs, const CLSID* clsid_encoder,
512     const struct bitmap_data **dsts, const CLSID *clsid_decoder, const char *name)
513 {
514     HRESULT hr;
515     IWICBitmapEncoder *encoder;
516     BitmapTestSrc *src_obj;
517     HGLOBAL hglobal;
518     IStream *stream;
519     IWICBitmapFrameEncode *frameencode;
520     IPropertyBag2 *options=NULL;
521     IWICBitmapDecoder *decoder;
522     IWICBitmapFrameDecode *framedecode;
523     WICPixelFormatGUID pixelformat;
524     int i;
525
526     hr = CoCreateInstance(clsid_encoder, NULL, CLSCTX_INPROC_SERVER,
527         &IID_IWICBitmapEncoder, (void**)&encoder);
528     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
529     if (SUCCEEDED(hr))
530     {
531         hglobal = GlobalAlloc(GMEM_MOVEABLE, 0);
532         ok(hglobal != NULL, "GlobalAlloc failed\n");
533         if (hglobal)
534         {
535             hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
536             ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
537         }
538
539         if (hglobal && SUCCEEDED(hr))
540         {
541             hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
542             ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
543
544             i=0;
545             while (SUCCEEDED(hr) && srcs[i])
546             {
547                 CreateTestBitmap(srcs[i], &src_obj);
548
549                 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &options);
550                 ok(SUCCEEDED(hr), "CreateFrame failed, hr=%x\n", hr);
551                 if (SUCCEEDED(hr))
552                 {
553                     ok(options != NULL, "Encoder initialization has not created an property bag\n");
554                     if(options)
555                         test_encoder_properties(clsid_encoder, options);
556
557                     hr = IWICBitmapFrameEncode_Initialize(frameencode, options);
558                     ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
559
560                     memcpy(&pixelformat, srcs[i]->format, sizeof(GUID));
561                     hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &pixelformat);
562                     ok(SUCCEEDED(hr), "SetPixelFormat failed, hr=%x\n", hr);
563                     ok(IsEqualGUID(&pixelformat, srcs[i]->format), "SetPixelFormat changed the format\n");
564
565                     hr = IWICBitmapFrameEncode_SetSize(frameencode, srcs[i]->width, srcs[i]->height);
566                     ok(SUCCEEDED(hr), "SetSize failed, hr=%x\n", hr);
567
568                     hr = IWICBitmapFrameEncode_WriteSource(frameencode, &src_obj->IWICBitmapSource_iface, NULL);
569                     ok(SUCCEEDED(hr), "WriteSource failed, hr=%x\n", hr);
570
571                     hr = IWICBitmapFrameEncode_Commit(frameencode);
572                     ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
573
574                     IWICBitmapFrameEncode_Release(frameencode);
575                     IPropertyBag2_Release(options);
576                 }
577
578                 DeleteTestBitmap(src_obj);
579
580                 i++;
581             }
582
583             if (SUCCEEDED(hr))
584             {
585                 hr = IWICBitmapEncoder_Commit(encoder);
586                 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
587             }
588
589             if (SUCCEEDED(hr))
590             {
591                 hr = CoCreateInstance(clsid_decoder, NULL, CLSCTX_INPROC_SERVER,
592                     &IID_IWICBitmapDecoder, (void**)&decoder);
593                 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
594             }
595
596             if (SUCCEEDED(hr))
597             {
598                 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand);
599                 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
600
601                 i=0;
602                 while (SUCCEEDED(hr) && dsts[i])
603                 {
604                     hr = IWICBitmapDecoder_GetFrame(decoder, i, &framedecode);
605                     ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
606
607                     if (SUCCEEDED(hr))
608                     {
609                         compare_bitmap_data(dsts[i], (IWICBitmapSource*)framedecode, name);
610
611                         IWICBitmapFrameDecode_Release(framedecode);
612                     }
613
614                     i++;
615                 }
616
617                 IWICBitmapDecoder_Release(decoder);
618             }
619
620             IStream_Release(stream);
621         }
622
623         IWICBitmapEncoder_Release(encoder);
624     }
625 }
626
627 static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encoder,
628     const struct bitmap_data *dst, const CLSID *clsid_decoder, const char *name)
629 {
630     const struct bitmap_data *srcs[2];
631     const struct bitmap_data *dsts[2];
632
633     srcs[0] = src;
634     srcs[1] = NULL;
635     dsts[0] = dst;
636     dsts[1] = NULL;
637
638     test_multi_encoder(srcs, clsid_encoder, dsts, clsid_decoder, name);
639 }
640
641 static const struct bitmap_data *multiple_frames[3] = {
642     &testdata_24bppBGR,
643     &testdata_24bppBGR,
644     NULL};
645
646 START_TEST(converter)
647 {
648     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
649
650     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGR, "BGRA -> BGR", 0);
651     test_conversion(&testdata_32bppBGR, &testdata_32bppBGRA, "BGR -> BGRA", 0);
652     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGRA, "BGRA -> BGRA", 0);
653
654     test_conversion(&testdata_24bppBGR, &testdata_24bppBGR, "24bppBGR -> 24bppBGR", 0);
655     test_conversion(&testdata_24bppBGR, &testdata_24bppRGB, "24bppBGR -> 24bppRGB", 0);
656
657     test_conversion(&testdata_24bppRGB, &testdata_24bppRGB, "24bppRGB -> 24bppRGB", 0);
658     test_conversion(&testdata_24bppRGB, &testdata_24bppBGR, "24bppRGB -> 24bppBGR", 0);
659
660     test_conversion(&testdata_32bppBGR, &testdata_24bppRGB, "32bppBGR -> 24bppRGB", 0);
661     test_conversion(&testdata_24bppRGB, &testdata_32bppBGR, "24bppRGB -> 32bppBGR", 0);
662
663     test_invalid_conversion();
664     test_default_converter();
665
666     test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
667                  &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
668
669     test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
670                  &testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
671
672     test_encoder(&testdata_24bppBGR, &CLSID_WICTiffEncoder,
673                  &testdata_24bppBGR, &CLSID_WICTiffDecoder, "TIFF encoder 24bppBGR");
674
675     test_multi_encoder(multiple_frames, &CLSID_WICTiffEncoder,
676                        multiple_frames, &CLSID_WICTiffDecoder, "TIFF encoder multi-frame");
677
678     CoUninitialize();
679 }