include/msvcrt: Define more CPU control word flags.
[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
24 #include "windef.h"
25 #include "objbase.h"
26 #include "wincodec.h"
27 #include "wine/test.h"
28
29 typedef struct bitmap_data {
30     const WICPixelFormatGUID *format;
31     UINT bpp;
32     const BYTE *bits;
33     UINT width;
34     UINT height;
35     double xres;
36     double yres;
37 } bitmap_data;
38
39 typedef struct BitmapTestSrc {
40     const IWICBitmapSourceVtbl *lpVtbl;
41     LONG ref;
42     const bitmap_data *data;
43 } BitmapTestSrc;
44
45 static HRESULT WINAPI BitmapTestSrc_QueryInterface(IWICBitmapSource *iface, REFIID iid,
46     void **ppv)
47 {
48     if (!ppv) return E_INVALIDARG;
49
50     if (IsEqualIID(&IID_IUnknown, iid) ||
51         IsEqualIID(&IID_IWICBitmapSource, iid))
52         *ppv = iface;
53     else
54         return E_NOINTERFACE;
55
56     IUnknown_AddRef((IUnknown*)*ppv);
57     return S_OK;
58 }
59
60 static ULONG WINAPI BitmapTestSrc_AddRef(IWICBitmapSource *iface)
61 {
62     BitmapTestSrc *This = (BitmapTestSrc*)iface;
63     ULONG ref = InterlockedIncrement(&This->ref);
64     return ref;
65 }
66
67 static ULONG WINAPI BitmapTestSrc_Release(IWICBitmapSource *iface)
68 {
69     BitmapTestSrc *This = (BitmapTestSrc*)iface;
70     ULONG ref = InterlockedDecrement(&This->ref);
71     return ref;
72 }
73
74 static HRESULT WINAPI BitmapTestSrc_GetSize(IWICBitmapSource *iface,
75     UINT *puiWidth, UINT *puiHeight)
76 {
77     BitmapTestSrc *This = (BitmapTestSrc*)iface;
78     *puiWidth = This->data->width;
79     *puiHeight = This->data->height;
80     return S_OK;
81 }
82
83 static HRESULT WINAPI BitmapTestSrc_GetPixelFormat(IWICBitmapSource *iface,
84     WICPixelFormatGUID *pPixelFormat)
85 {
86     BitmapTestSrc *This = (BitmapTestSrc*)iface;
87     memcpy(pPixelFormat, This->data->format, sizeof(GUID));
88     return S_OK;
89 }
90
91 static HRESULT WINAPI BitmapTestSrc_GetResolution(IWICBitmapSource *iface,
92     double *pDpiX, double *pDpiY)
93 {
94     BitmapTestSrc *This = (BitmapTestSrc*)iface;
95     *pDpiX = This->data->xres;
96     *pDpiY = This->data->yres;
97     return S_OK;
98 }
99
100 static HRESULT WINAPI BitmapTestSrc_CopyPalette(IWICBitmapSource *iface,
101     IWICPalette *pIPalette)
102 {
103     return E_NOTIMPL;
104 }
105
106 static HRESULT WINAPI BitmapTestSrc_CopyPixels(IWICBitmapSource *iface,
107     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
108 {
109     BitmapTestSrc *This = (BitmapTestSrc*)iface;
110     UINT bytesperrow;
111     UINT srcstride;
112     UINT row_offset;
113     WICRect rc;
114
115     if (!prc)
116     {
117         rc.X = 0;
118         rc.Y = 0;
119         rc.Width = This->data->width;
120         rc.Height = This->data->height;
121         prc = &rc;
122     }
123     else
124     {
125         if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->data->width || prc->Y+prc->Height > This->data->height)
126             return E_INVALIDARG;
127     }
128
129     bytesperrow = ((This->data->bpp * prc->Width)+7)/8;
130     srcstride = ((This->data->bpp * This->data->width)+7)/8;
131
132     if (cbStride < bytesperrow)
133         return E_INVALIDARG;
134
135     if ((cbStride * prc->Height) > cbBufferSize)
136         return E_INVALIDARG;
137
138     row_offset = prc->X * This->data->bpp;
139
140     if (row_offset % 8 == 0)
141     {
142         UINT row;
143         const BYTE *src;
144         BYTE *dst;
145
146         src = This->data->bits + (row_offset / 8) + prc->Y * srcstride;
147         dst = pbBuffer;
148         for (row=0; row < prc->Height; row++)
149         {
150             memcpy(dst, src, bytesperrow);
151             src += srcstride;
152             dst += cbStride;
153         }
154         return S_OK;
155     }
156     else
157     {
158         ok(0, "bitmap %p was asked to copy pixels not aligned on a byte boundary\n", iface);
159         return E_FAIL;
160     }
161 }
162
163 static const IWICBitmapSourceVtbl BitmapTestSrc_Vtbl = {
164     BitmapTestSrc_QueryInterface,
165     BitmapTestSrc_AddRef,
166     BitmapTestSrc_Release,
167     BitmapTestSrc_GetSize,
168     BitmapTestSrc_GetPixelFormat,
169     BitmapTestSrc_GetResolution,
170     BitmapTestSrc_CopyPalette,
171     BitmapTestSrc_CopyPixels
172 };
173
174 static void CreateTestBitmap(const bitmap_data *data, IWICBitmapSource **bitmap)
175 {
176     BitmapTestSrc *This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapTestSrc));
177
178     if (This)
179     {
180         This->lpVtbl = &BitmapTestSrc_Vtbl;
181         This->ref = 1;
182         This->data = data;
183         *bitmap = (IWICBitmapSource*)This;
184     }
185     else
186         *bitmap = NULL;
187 }
188
189 static void DeleteTestBitmap(IWICBitmapSource *bitmap)
190 {
191     BitmapTestSrc *This = (BitmapTestSrc*)bitmap;
192     ok(This->lpVtbl == &BitmapTestSrc_Vtbl, "test bitmap %p deleted with incorrect vtable\n", bitmap);
193     ok(This->ref == 1, "test bitmap %p deleted with %i references instead of 1\n", bitmap, This->ref);
194     HeapFree(GetProcessHeap(), 0, This);
195 }
196
197 static void compare_bitmap_data(const struct bitmap_data *expect, IWICBitmapSource *source, const char *name)
198 {
199     BYTE *converted_bits;
200     UINT width, height;
201     double xres, yres;
202     WICRect prc;
203     UINT stride, buffersize;
204     GUID dst_pixelformat;
205     HRESULT hr;
206
207     hr = IWICBitmapSource_GetSize(source, &width, &height);
208     ok(SUCCEEDED(hr), "GetSize(%s) failed, hr=%x\n", name, hr);
209     ok(width == expect->width, "expecting %u, got %u (%s)\n", expect->width, width, name);
210     ok(height == expect->height, "expecting %u, got %u (%s)\n", expect->height, height, name);
211
212     hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
213     ok(SUCCEEDED(hr), "GetResolution(%s) failed, hr=%x\n", name, hr);
214     ok(fabs(xres - expect->xres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->xres, xres, name);
215     ok(fabs(yres - expect->yres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->yres, yres, name);
216
217     hr = IWICBitmapSource_GetPixelFormat(source, &dst_pixelformat);
218     ok(SUCCEEDED(hr), "GetPixelFormat(%s) failed, hr=%x\n", name, hr);
219     ok(IsEqualGUID(&dst_pixelformat, expect->format), "got unexpected pixel format (%s)\n", name);
220
221     prc.X = 0;
222     prc.Y = 0;
223     prc.Width = expect->width;
224     prc.Height = expect->height;
225
226     stride = (expect->bpp * expect->width + 7) / 8;
227     buffersize = stride * expect->height;
228
229     converted_bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
230     hr = IWICBitmapSource_CopyPixels(source, &prc, stride, buffersize, converted_bits);
231     ok(SUCCEEDED(hr), "CopyPixels(%s) failed, hr=%x\n", name, hr);
232     if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
233     {
234         /* ignore the padding byte when comparing data */
235         UINT i;
236         BOOL equal=TRUE;
237         const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
238         for (i=0; i<(buffersize/4); i++)
239             if ((a[i]&0xffffff) != (b[i]&0xffffff))
240             {
241                 equal = FALSE;
242                 break;
243             }
244         ok(equal, "unexpected pixel data (%s)\n", name);
245     }
246     else
247         ok(memcmp(expect->bits, converted_bits, buffersize) == 0, "unexpected pixel data (%s)\n", name);
248
249     /* Test with NULL rectangle - should copy the whole bitmap */
250     hr = IWICBitmapSource_CopyPixels(source, NULL, stride, buffersize, converted_bits);
251     ok(SUCCEEDED(hr), "CopyPixels(%s,rc=NULL) failed, hr=%x\n", name, hr);
252     if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
253     {
254         /* ignore the padding byte when comparing data */
255         UINT i;
256         BOOL equal=TRUE;
257         const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
258         for (i=0; i<(buffersize/4); i++)
259             if ((a[i]&0xffffff) != (b[i]&0xffffff))
260             {
261                 equal = FALSE;
262                 break;
263             }
264         ok(equal, "unexpected pixel data with rc=NULL (%s)\n", name);
265     }
266     else
267         ok(memcmp(expect->bits, converted_bits, buffersize) == 0, "unexpected pixel data with rc=NULL (%s)\n", name);
268
269     HeapFree(GetProcessHeap(), 0, converted_bits);
270 }
271
272 static const BYTE bits_24bppBGR[] = {
273     255,0,0, 0,255,0, 0,0,255, 0,0,0,
274     0,255,255, 255,0,255, 255,255,0, 255,255,255};
275 static const struct bitmap_data testdata_24bppBGR = {
276     &GUID_WICPixelFormat24bppBGR, 24, bits_24bppBGR, 4, 2, 96.0, 96.0};
277
278 static const BYTE bits_32bppBGR[] = {
279     255,0,0,80, 0,255,0,80, 0,0,255,80, 0,0,0,80,
280     0,255,255,80, 255,0,255,80, 255,255,0,80, 255,255,255,80};
281 static const struct bitmap_data testdata_32bppBGR = {
282     &GUID_WICPixelFormat32bppBGR, 32, bits_32bppBGR, 4, 2, 96.0, 96.0};
283
284 static const BYTE bits_32bppBGRA[] = {
285     255,0,0,255, 0,255,0,255, 0,0,255,255, 0,0,0,255,
286     0,255,255,255, 255,0,255,255, 255,255,0,255, 255,255,255,255};
287 static const struct bitmap_data testdata_32bppBGRA = {
288     &GUID_WICPixelFormat32bppBGRA, 32, bits_32bppBGRA, 4, 2, 96.0, 96.0};
289
290 static void test_conversion(const struct bitmap_data *src, const struct bitmap_data *dst, const char *name, BOOL todo)
291 {
292     IWICBitmapSource *src_bitmap, *dst_bitmap;
293     HRESULT hr;
294
295     CreateTestBitmap(src, &src_bitmap);
296
297     hr = WICConvertBitmapSource(dst->format, src_bitmap, &dst_bitmap);
298     if (todo)
299         todo_wine ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
300     else
301         ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
302
303     if (SUCCEEDED(hr))
304     {
305         compare_bitmap_data(dst, dst_bitmap, name);
306
307         IWICBitmapSource_Release(dst_bitmap);
308     }
309
310     DeleteTestBitmap(src_bitmap);
311 }
312
313 static void test_invalid_conversion(void)
314 {
315     IWICBitmapSource *src_bitmap, *dst_bitmap;
316     HRESULT hr;
317
318     CreateTestBitmap(&testdata_32bppBGRA, &src_bitmap);
319
320     /* convert to a non-pixel-format GUID */
321     hr = WICConvertBitmapSource(&GUID_VendorMicrosoft, src_bitmap, &dst_bitmap);
322     ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "WICConvertBitmapSource returned %x\n", hr);
323
324     DeleteTestBitmap(src_bitmap);
325 }
326
327 static void test_default_converter(void)
328 {
329     IWICBitmapSource *src_bitmap;
330     IWICFormatConverter *converter;
331     BOOL can_convert=1;
332     HRESULT hr;
333
334     CreateTestBitmap(&testdata_32bppBGRA, &src_bitmap);
335
336     hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER,
337         &IID_IWICFormatConverter, (void**)&converter);
338     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
339     if (SUCCEEDED(hr))
340     {
341         hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA,
342             &GUID_WICPixelFormat32bppBGR, &can_convert);
343         ok(SUCCEEDED(hr), "CanConvert returned %x\n", hr);
344         ok(can_convert, "expected TRUE, got %i\n", can_convert);
345
346         hr = IWICFormatConverter_Initialize(converter, src_bitmap,
347             &GUID_WICPixelFormat32bppBGR, WICBitmapDitherTypeNone, NULL, 0.0,
348             WICBitmapPaletteTypeCustom);
349         ok(SUCCEEDED(hr), "Initialize returned %x\n", hr);
350
351         if (SUCCEEDED(hr))
352             compare_bitmap_data(&testdata_32bppBGR, (IWICBitmapSource*)converter, "default converter");
353
354         IWICFormatConverter_Release(converter);
355     }
356
357     DeleteTestBitmap(src_bitmap);
358 }
359
360 static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encoder,
361     const struct bitmap_data *dst, const CLSID *clsid_decoder, const char *name)
362 {
363     HRESULT hr;
364     IWICBitmapEncoder *encoder;
365     IWICBitmapSource *src_bitmap;
366     HGLOBAL hglobal;
367     IStream *stream;
368     IWICBitmapFrameEncode *frameencode;
369     IPropertyBag2 *options=NULL;
370     IWICBitmapDecoder *decoder;
371     IWICBitmapFrameDecode *framedecode;
372     WICPixelFormatGUID pixelformat;
373
374     CreateTestBitmap(src, &src_bitmap);
375
376     hr = CoCreateInstance(clsid_encoder, NULL, CLSCTX_INPROC_SERVER,
377         &IID_IWICBitmapEncoder, (void**)&encoder);
378     ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
379     if (SUCCEEDED(hr))
380     {
381         hglobal = GlobalAlloc(GMEM_MOVEABLE, 0);
382         ok(hglobal != NULL, "GlobalAlloc failed\n");
383         if (hglobal)
384         {
385             hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
386             ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
387         }
388
389         if (hglobal && SUCCEEDED(hr))
390         {
391             hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
392             ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
393
394             hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &options);
395             ok(SUCCEEDED(hr), "CreateFrame failed, hr=%x\n", hr);
396             if (SUCCEEDED(hr))
397             {
398                 hr = IWICBitmapFrameEncode_Initialize(frameencode, options);
399                 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
400
401                 memcpy(&pixelformat, src->format, sizeof(GUID));
402                 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &pixelformat);
403                 ok(SUCCEEDED(hr), "SetPixelFormat failed, hr=%x\n", hr);
404                 ok(IsEqualGUID(&pixelformat, src->format), "SetPixelFormat changed the format\n");
405
406                 hr = IWICBitmapFrameEncode_SetSize(frameencode, src->width, src->height);
407                 ok(SUCCEEDED(hr), "SetSize failed, hr=%x\n", hr);
408
409                 hr = IWICBitmapFrameEncode_WriteSource(frameencode, src_bitmap, NULL);
410                 ok(SUCCEEDED(hr), "WriteSource failed, hr=%x\n", hr);
411
412                 hr = IWICBitmapFrameEncode_Commit(frameencode);
413                 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
414
415                 hr = IWICBitmapEncoder_Commit(encoder);
416                 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
417
418                 IWICBitmapFrameEncode_Release(frameencode);
419                 IPropertyBag2_Release(options);
420             }
421
422             if (SUCCEEDED(hr))
423             {
424                 hr = CoCreateInstance(clsid_decoder, NULL, CLSCTX_INPROC_SERVER,
425                     &IID_IWICBitmapDecoder, (void**)&decoder);
426                 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
427             }
428
429             if (SUCCEEDED(hr))
430             {
431                 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand);
432                 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
433
434                 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
435                 ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
436
437                 if (SUCCEEDED(hr))
438                 {
439                     compare_bitmap_data(dst, (IWICBitmapSource*)framedecode, name);
440
441                     IWICBitmapFrameDecode_Release(framedecode);
442                 }
443
444                 IWICBitmapDecoder_Release(decoder);
445             }
446
447             IStream_Release(stream);
448         }
449
450         IWICBitmapEncoder_Release(encoder);
451     }
452
453     DeleteTestBitmap(src_bitmap);
454 }
455
456 START_TEST(converter)
457 {
458     CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
459
460     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGR, "BGRA -> BGR", 0);
461     test_conversion(&testdata_32bppBGR, &testdata_32bppBGRA, "BGR -> BGRA", 0);
462     test_conversion(&testdata_32bppBGRA, &testdata_32bppBGRA, "BGRA -> BGRA", 0);
463     test_invalid_conversion();
464     test_default_converter();
465
466     test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
467                  &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
468
469     test_encoder(&testdata_24bppBGR, &CLSID_WICPngEncoder,
470                  &testdata_24bppBGR, &CLSID_WICPngDecoder, "PNG encoder 24bppBGR");
471
472     CoUninitialize();
473 }