windowscodecs: Add test for BMP encoder.
[wine/multimedia.git] / dlls / windowscodecs / tests / converter.c
blob680c3509f6cf7bc101c807f07bbc127763a31936
1 /*
2 * Copyright 2009 Vincent Povirk
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.
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.
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
19 #include <stdarg.h>
20 #include <math.h>
22 #define COBJMACROS
24 #include "windef.h"
25 #include "objbase.h"
26 #include "wincodec.h"
27 #include "wine/test.h"
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;
39 typedef struct BitmapTestSrc {
40 const IWICBitmapSourceVtbl *lpVtbl;
41 LONG ref;
42 const bitmap_data *data;
43 } BitmapTestSrc;
45 static HRESULT WINAPI BitmapTestSrc_QueryInterface(IWICBitmapSource *iface, REFIID iid,
46 void **ppv)
48 if (!ppv) return E_INVALIDARG;
50 if (IsEqualIID(&IID_IUnknown, iid) ||
51 IsEqualIID(&IID_IWICBitmapSource, iid))
52 *ppv = iface;
53 else
54 return E_NOINTERFACE;
56 IUnknown_AddRef((IUnknown*)*ppv);
57 return S_OK;
60 static ULONG WINAPI BitmapTestSrc_AddRef(IWICBitmapSource *iface)
62 BitmapTestSrc *This = (BitmapTestSrc*)iface;
63 ULONG ref = InterlockedIncrement(&This->ref);
64 return ref;
67 static ULONG WINAPI BitmapTestSrc_Release(IWICBitmapSource *iface)
69 BitmapTestSrc *This = (BitmapTestSrc*)iface;
70 ULONG ref = InterlockedDecrement(&This->ref);
71 return ref;
74 static HRESULT WINAPI BitmapTestSrc_GetSize(IWICBitmapSource *iface,
75 UINT *puiWidth, UINT *puiHeight)
77 BitmapTestSrc *This = (BitmapTestSrc*)iface;
78 *puiWidth = This->data->width;
79 *puiHeight = This->data->height;
80 return S_OK;
83 static HRESULT WINAPI BitmapTestSrc_GetPixelFormat(IWICBitmapSource *iface,
84 WICPixelFormatGUID *pPixelFormat)
86 BitmapTestSrc *This = (BitmapTestSrc*)iface;
87 memcpy(pPixelFormat, This->data->format, sizeof(GUID));
88 return S_OK;
91 static HRESULT WINAPI BitmapTestSrc_GetResolution(IWICBitmapSource *iface,
92 double *pDpiX, double *pDpiY)
94 BitmapTestSrc *This = (BitmapTestSrc*)iface;
95 *pDpiX = This->data->xres;
96 *pDpiY = This->data->yres;
97 return S_OK;
100 static HRESULT WINAPI BitmapTestSrc_CopyPalette(IWICBitmapSource *iface,
101 IWICPalette *pIPalette)
103 return E_NOTIMPL;
106 static HRESULT WINAPI BitmapTestSrc_CopyPixels(IWICBitmapSource *iface,
107 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
109 BitmapTestSrc *This = (BitmapTestSrc*)iface;
110 UINT bytesperrow;
111 UINT srcstride;
112 UINT row_offset;
114 if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->data->width || prc->Y+prc->Height > This->data->height)
115 return E_INVALIDARG;
117 bytesperrow = ((This->data->bpp * prc->Width)+7)/8;
118 srcstride = ((This->data->bpp * This->data->width)+7)/8;
120 if (cbStride < bytesperrow)
121 return E_INVALIDARG;
123 if ((cbStride * prc->Height) > cbBufferSize)
124 return E_INVALIDARG;
126 row_offset = prc->X * This->data->bpp;
128 if (row_offset % 8 == 0)
130 UINT row;
131 const BYTE *src;
132 BYTE *dst;
134 src = This->data->bits + (row_offset / 8) + prc->Y * srcstride;
135 dst = pbBuffer;
136 for (row=0; row < prc->Height; row++)
138 memcpy(dst, src, bytesperrow);
139 src += srcstride;
140 dst += cbStride;
142 return S_OK;
144 else
146 ok(0, "bitmap %p was asked to copy pixels not aligned on a byte boundary\n", iface);
147 return E_FAIL;
151 static const IWICBitmapSourceVtbl BitmapTestSrc_Vtbl = {
152 BitmapTestSrc_QueryInterface,
153 BitmapTestSrc_AddRef,
154 BitmapTestSrc_Release,
155 BitmapTestSrc_GetSize,
156 BitmapTestSrc_GetPixelFormat,
157 BitmapTestSrc_GetResolution,
158 BitmapTestSrc_CopyPalette,
159 BitmapTestSrc_CopyPixels
162 static void CreateTestBitmap(const bitmap_data *data, IWICBitmapSource **bitmap)
164 BitmapTestSrc *This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapTestSrc));
166 if (This)
168 This->lpVtbl = &BitmapTestSrc_Vtbl;
169 This->ref = 1;
170 This->data = data;
171 *bitmap = (IWICBitmapSource*)This;
173 else
174 *bitmap = NULL;
177 static void DeleteTestBitmap(IWICBitmapSource *bitmap)
179 BitmapTestSrc *This = (BitmapTestSrc*)bitmap;
180 ok(This->lpVtbl == &BitmapTestSrc_Vtbl, "test bitmap %p deleted with incorrect vtable\n", bitmap);
181 ok(This->ref == 1, "test bitmap %p deleted with %i references instead of 1\n", bitmap, This->ref);
182 HeapFree(GetProcessHeap(), 0, This);
185 static void compare_bitmap_data(const struct bitmap_data *expect, IWICBitmapSource *source, const char *name)
187 BYTE *converted_bits;
188 UINT width, height;
189 double xres, yres;
190 WICRect prc;
191 UINT stride, buffersize;
192 GUID dst_pixelformat;
193 HRESULT hr;
195 hr = IWICBitmapSource_GetSize(source, &width, &height);
196 ok(SUCCEEDED(hr), "GetSize(%s) failed, hr=%x\n", name, hr);
197 ok(width == expect->width, "expecting %u, got %u (%s)\n", expect->width, width, name);
198 ok(height == expect->height, "expecting %u, got %u (%s)\n", expect->height, height, name);
200 hr = IWICBitmapSource_GetResolution(source, &xres, &yres);
201 ok(SUCCEEDED(hr), "GetResolution(%s) failed, hr=%x\n", name, hr);
202 ok(fabs(xres - expect->xres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->xres, xres, name);
203 ok(fabs(yres - expect->yres) < 0.02, "expecting %0.2f, got %0.2f (%s)\n", expect->yres, yres, name);
205 hr = IWICBitmapSource_GetPixelFormat(source, &dst_pixelformat);
206 ok(SUCCEEDED(hr), "GetPixelFormat(%s) failed, hr=%x\n", name, hr);
207 ok(IsEqualGUID(&dst_pixelformat, expect->format), "got unexpected pixel format (%s)\n", name);
209 prc.X = 0;
210 prc.Y = 0;
211 prc.Width = expect->width;
212 prc.Height = expect->height;
214 stride = (expect->bpp * expect->width + 7) / 8;
215 buffersize = stride * expect->height;
217 converted_bits = HeapAlloc(GetProcessHeap(), 0, buffersize);
218 hr = IWICBitmapSource_CopyPixels(source, &prc, stride, buffersize, converted_bits);
219 ok(SUCCEEDED(hr), "CopyPixels(%s) failed, hr=%x\n", name, hr);
220 if (IsEqualGUID(expect->format, &GUID_WICPixelFormat32bppBGR))
222 /* ignore the padding byte when comparing data */
223 UINT i;
224 BOOL equal=TRUE;
225 const DWORD *a=(const DWORD*)expect->bits, *b=(const DWORD*)converted_bits;
226 for (i=0; i<(buffersize/4); i++)
227 if ((a[i]&0xffffff) != (b[i]&0xffffff))
229 equal = FALSE;
230 break;
232 ok(equal, "unexpected pixel data (%s)\n", name);
234 else
235 ok(memcmp(expect->bits, converted_bits, buffersize) == 0, "unexpected pixel data (%s)\n", name);
236 HeapFree(GetProcessHeap(), 0, converted_bits);
239 static const BYTE bits_32bppBGR[] = {
240 255,0,0,80, 0,255,0,80, 0,0,255,80, 0,0,0,80,
241 0,255,255,80, 255,0,255,80, 255,255,0,80, 255,255,255,80};
242 static const struct bitmap_data testdata_32bppBGR = {
243 &GUID_WICPixelFormat32bppBGR, 32, bits_32bppBGR, 4, 2, 96.0, 96.0};
245 static const BYTE bits_32bppBGRA[] = {
246 255,0,0,255, 0,255,0,255, 0,0,255,255, 0,0,0,255,
247 0,255,255,255, 255,0,255,255, 255,255,0,255, 255,255,255,255};
248 static const struct bitmap_data testdata_32bppBGRA = {
249 &GUID_WICPixelFormat32bppBGRA, 32, bits_32bppBGRA, 4, 2, 96.0, 96.0};
251 static void test_conversion(const struct bitmap_data *src, const struct bitmap_data *dst, const char *name, BOOL todo)
253 IWICBitmapSource *src_bitmap, *dst_bitmap;
254 HRESULT hr;
256 CreateTestBitmap(src, &src_bitmap);
258 hr = WICConvertBitmapSource(dst->format, src_bitmap, &dst_bitmap);
259 if (todo)
260 todo_wine ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
261 else
262 ok(SUCCEEDED(hr), "WICConvertBitmapSource(%s) failed, hr=%x\n", name, hr);
264 if (SUCCEEDED(hr))
266 compare_bitmap_data(dst, dst_bitmap, name);
268 IWICBitmapSource_Release(dst_bitmap);
271 DeleteTestBitmap(src_bitmap);
274 static void test_invalid_conversion(void)
276 IWICBitmapSource *src_bitmap, *dst_bitmap;
277 HRESULT hr;
279 CreateTestBitmap(&testdata_32bppBGRA, &src_bitmap);
281 /* convert to a non-pixel-format GUID */
282 hr = WICConvertBitmapSource(&GUID_VendorMicrosoft, src_bitmap, &dst_bitmap);
283 ok(hr == WINCODEC_ERR_COMPONENTNOTFOUND, "WICConvertBitmapSource returned %x\n", hr);
285 DeleteTestBitmap(src_bitmap);
288 static void test_default_converter(void)
290 IWICBitmapSource *src_bitmap;
291 IWICFormatConverter *converter;
292 BOOL can_convert=1;
293 HRESULT hr;
295 CreateTestBitmap(&testdata_32bppBGRA, &src_bitmap);
297 hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER,
298 &IID_IWICFormatConverter, (void**)&converter);
299 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
300 if (SUCCEEDED(hr))
302 hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA,
303 &GUID_WICPixelFormat32bppBGR, &can_convert);
304 ok(SUCCEEDED(hr), "CanConvert returned %x\n", hr);
305 ok(can_convert, "expected TRUE, got %i\n", can_convert);
307 hr = IWICFormatConverter_Initialize(converter, src_bitmap,
308 &GUID_WICPixelFormat32bppBGR, WICBitmapDitherTypeNone, NULL, 0.0,
309 WICBitmapPaletteTypeCustom);
310 ok(SUCCEEDED(hr), "Initialize returned %x\n", hr);
312 if (SUCCEEDED(hr))
313 compare_bitmap_data(&testdata_32bppBGR, (IWICBitmapSource*)converter, "default converter");
315 IWICFormatConverter_Release(converter);
318 DeleteTestBitmap(src_bitmap);
321 static void test_encoder(const struct bitmap_data *src, const CLSID* clsid_encoder,
322 const struct bitmap_data *dst, const CLSID *clsid_decoder, const char *name)
324 HRESULT hr;
325 IWICBitmapEncoder *encoder;
326 IWICBitmapSource *src_bitmap;
327 HGLOBAL hglobal;
328 IStream *stream;
329 IWICBitmapFrameEncode *frameencode;
330 IPropertyBag2 *options=NULL;
331 IWICBitmapDecoder *decoder;
332 IWICBitmapFrameDecode *framedecode;
333 WICPixelFormatGUID pixelformat;
335 CreateTestBitmap(src, &src_bitmap);
337 hr = CoCreateInstance(clsid_encoder, NULL, CLSCTX_INPROC_SERVER,
338 &IID_IWICBitmapEncoder, (void**)&encoder);
339 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
340 if (SUCCEEDED(hr))
342 hglobal = GlobalAlloc(GMEM_MOVEABLE, 0);
343 ok(hglobal != NULL, "GlobalAlloc failed\n");
344 if (hglobal)
346 hr = CreateStreamOnHGlobal(hglobal, TRUE, &stream);
347 ok(SUCCEEDED(hr), "CreateStreamOnHGlobal failed, hr=%x\n", hr);
350 if (hglobal && SUCCEEDED(hr))
352 hr = IWICBitmapEncoder_Initialize(encoder, stream, WICBitmapEncoderNoCache);
353 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
355 hr = IWICBitmapEncoder_CreateNewFrame(encoder, &frameencode, &options);
356 ok(SUCCEEDED(hr), "CreateFrame failed, hr=%x\n", hr);
357 if (SUCCEEDED(hr))
359 hr = IWICBitmapFrameEncode_Initialize(frameencode, options);
360 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
362 memcpy(&pixelformat, src->format, sizeof(GUID));
363 hr = IWICBitmapFrameEncode_SetPixelFormat(frameencode, &pixelformat);
364 ok(SUCCEEDED(hr), "SetPixelFormat failed, hr=%x\n", hr);
365 ok(IsEqualGUID(&pixelformat, src->format), "SetPixelFormat changed the format\n");
367 hr = IWICBitmapFrameEncode_SetSize(frameencode, src->width, src->height);
368 ok(SUCCEEDED(hr), "SetSize failed, hr=%x\n", hr);
370 hr = IWICBitmapFrameEncode_WriteSource(frameencode, src_bitmap, NULL);
371 ok(SUCCEEDED(hr), "WriteSource failed, hr=%x\n", hr);
373 hr = IWICBitmapFrameEncode_Commit(frameencode);
374 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
376 hr = IWICBitmapEncoder_Commit(encoder);
377 ok(SUCCEEDED(hr), "Commit failed, hr=%x\n", hr);
379 IWICBitmapFrameEncode_Release(frameencode);
380 IPropertyBag2_Release(options);
383 if (SUCCEEDED(hr))
385 hr = CoCreateInstance(clsid_decoder, NULL, CLSCTX_INPROC_SERVER,
386 &IID_IWICBitmapDecoder, (void**)&decoder);
387 ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%x\n", hr);
390 if (SUCCEEDED(hr))
392 hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnDemand);
393 ok(SUCCEEDED(hr), "Initialize failed, hr=%x\n", hr);
395 hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
396 ok(SUCCEEDED(hr), "GetFrame failed, hr=%x\n", hr);
398 if (SUCCEEDED(hr))
400 compare_bitmap_data(dst, (IWICBitmapSource*)framedecode, name);
402 IWICBitmapFrameDecode_Release(framedecode);
405 IWICBitmapDecoder_Release(decoder);
408 IStream_Release(stream);
412 DeleteTestBitmap(src_bitmap);
415 START_TEST(converter)
417 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
419 test_conversion(&testdata_32bppBGRA, &testdata_32bppBGR, "BGRA -> BGR", 0);
420 test_conversion(&testdata_32bppBGR, &testdata_32bppBGRA, "BGR -> BGRA", 0);
421 test_conversion(&testdata_32bppBGRA, &testdata_32bppBGRA, "BGRA -> BGRA", 0);
422 test_invalid_conversion();
423 test_default_converter();
425 test_encoder(&testdata_32bppBGR, &CLSID_WICBmpEncoder,
426 &testdata_32bppBGR, &CLSID_WICBmpDecoder, "BMP encoder 32bppBGR");
428 CoUninitialize();