Synchronize with trunk r58606.
[reactos.git] / dll / win32 / windowscodecs / bmpencode.c
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
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 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <config.h>
24
25 #include <stdarg.h>
26
27 #define COBJMACROS
28
29 #include <windef.h>
30 #include <winbase.h>
31 //#include "winreg.h"
32 #include <wingdi.h>
33 #include <objbase.h>
34 #include <wincodec.h>
35
36 #include "wincodecs_private.h"
37
38 #include <wine/debug.h>
39
40 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
41
42 struct bmp_pixelformat {
43 const WICPixelFormatGUID *guid;
44 UINT bpp;
45 DWORD compression;
46 DWORD redmask;
47 DWORD greenmask;
48 DWORD bluemask;
49 DWORD alphamask;
50 };
51
52 static const struct bmp_pixelformat formats[] = {
53 {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB},
54 {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB},
55 {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0},
56 {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB},
57 #if 0
58 /* Windows doesn't seem to support this one. */
59 {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000},
60 #endif
61 {NULL}
62 };
63
64 typedef struct BmpFrameEncode {
65 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
66 LONG ref;
67 IStream *stream;
68 BOOL initialized;
69 UINT width, height;
70 BYTE *bits;
71 const struct bmp_pixelformat *format;
72 double xres, yres;
73 UINT lineswritten;
74 UINT stride;
75 BOOL committed;
76 } BmpFrameEncode;
77
78 static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
79 {
80 return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
81 }
82
83 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
84 void **ppv)
85 {
86 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
87 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
88
89 if (!ppv) return E_INVALIDARG;
90
91 if (IsEqualIID(&IID_IUnknown, iid) ||
92 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
93 {
94 *ppv = &This->IWICBitmapFrameEncode_iface;
95 }
96 else
97 {
98 *ppv = NULL;
99 return E_NOINTERFACE;
100 }
101
102 IUnknown_AddRef((IUnknown*)*ppv);
103 return S_OK;
104 }
105
106 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
107 {
108 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
109 ULONG ref = InterlockedIncrement(&This->ref);
110
111 TRACE("(%p) refcount=%u\n", iface, ref);
112
113 return ref;
114 }
115
116 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
117 {
118 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
119 ULONG ref = InterlockedDecrement(&This->ref);
120
121 TRACE("(%p) refcount=%u\n", iface, ref);
122
123 if (ref == 0)
124 {
125 if (This->stream) IStream_Release(This->stream);
126 HeapFree(GetProcessHeap(), 0, This->bits);
127 HeapFree(GetProcessHeap(), 0, This);
128 }
129
130 return ref;
131 }
132
133 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
134 IPropertyBag2 *pIEncoderOptions)
135 {
136 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
137 TRACE("(%p,%p)\n", iface, pIEncoderOptions);
138
139 if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
140
141 This->initialized = TRUE;
142
143 return S_OK;
144 }
145
146 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
147 UINT uiWidth, UINT uiHeight)
148 {
149 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
150 TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
151
152 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
153
154 This->width = uiWidth;
155 This->height = uiHeight;
156
157 return S_OK;
158 }
159
160 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
161 double dpiX, double dpiY)
162 {
163 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
164 TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
165
166 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
167
168 This->xres = dpiX;
169 This->yres = dpiY;
170
171 return S_OK;
172 }
173
174 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
175 WICPixelFormatGUID *pPixelFormat)
176 {
177 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
178 int i;
179 TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
180
181 if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
182
183 for (i=0; formats[i].guid; i++)
184 {
185 if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
186 break;
187 }
188
189 if (!formats[i].guid) i = 0;
190
191 This->format = &formats[i];
192 memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
193
194 return S_OK;
195 }
196
197 static HRESULT WINAPI BmpFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
198 UINT cCount, IWICColorContext **ppIColorContext)
199 {
200 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
201 return E_NOTIMPL;
202 }
203
204 static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
205 IWICPalette *pIPalette)
206 {
207 FIXME("(%p,%p): stub\n", iface, pIPalette);
208 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
209 }
210
211 static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
212 IWICBitmapSource *pIThumbnail)
213 {
214 FIXME("(%p,%p): stub\n", iface, pIThumbnail);
215 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
216 }
217
218 static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
219 {
220 if (!This->bits)
221 {
222 if (!This->initialized || !This->width || !This->height || !This->format)
223 return WINCODEC_ERR_WRONGSTATE;
224
225 This->stride = (((This->width * This->format->bpp)+31)/32)*4;
226 This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height);
227 if (!This->bits) return E_OUTOFMEMORY;
228 }
229
230 return S_OK;
231 }
232
233 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
234 UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
235 {
236 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
237 HRESULT hr;
238 WICRect rc;
239 TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
240
241 if (!This->initialized || !This->width || !This->height || !This->format)
242 return WINCODEC_ERR_WRONGSTATE;
243
244 hr = BmpFrameEncode_AllocateBits(This);
245 if (FAILED(hr)) return hr;
246
247 rc.X = 0;
248 rc.Y = 0;
249 rc.Width = This->width;
250 rc.Height = lineCount;
251
252 hr = copy_pixels(This->format->bpp, pbPixels, This->width, lineCount, cbStride,
253 &rc, This->stride, This->stride*(This->height-This->lineswritten),
254 This->bits + This->stride*This->lineswritten);
255
256 if (SUCCEEDED(hr))
257 This->lineswritten += lineCount;
258
259 return hr;
260 }
261
262 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
263 IWICBitmapSource *pIBitmapSource, WICRect *prc)
264 {
265 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
266 HRESULT hr;
267 WICRect rc;
268 WICPixelFormatGUID guid;
269 TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
270
271 if (!This->initialized || !This->width || !This->height)
272 return WINCODEC_ERR_WRONGSTATE;
273
274 if (!This->format)
275 {
276 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
277 if (FAILED(hr)) return hr;
278 hr = BmpFrameEncode_SetPixelFormat(iface, &guid);
279 if (FAILED(hr)) return hr;
280 }
281
282 hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
283 if (FAILED(hr)) return hr;
284 if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
285 {
286 /* should use WICConvertBitmapSource to convert, but that's unimplemented */
287 ERR("format %s unsupported\n", debugstr_guid(&guid));
288 return E_FAIL;
289 }
290
291 if (This->xres == 0.0 || This->yres == 0.0)
292 {
293 double xres, yres;
294 hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
295 if (FAILED(hr)) return hr;
296 hr = BmpFrameEncode_SetResolution(iface, xres, yres);
297 if (FAILED(hr)) return hr;
298 }
299
300 if (!prc)
301 {
302 UINT width, height;
303 hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
304 if (FAILED(hr)) return hr;
305 rc.X = 0;
306 rc.Y = 0;
307 rc.Width = width;
308 rc.Height = height;
309 prc = &rc;
310 }
311
312 if (prc->Width != This->width) return E_INVALIDARG;
313
314 hr = BmpFrameEncode_AllocateBits(This);
315 if (FAILED(hr)) return hr;
316
317 hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, This->stride,
318 This->stride*(This->height-This->lineswritten),
319 This->bits + This->stride*This->lineswritten);
320
321 This->lineswritten += prc->Height;
322
323 return S_OK;
324 }
325
326 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
327 {
328 BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
329 BITMAPFILEHEADER bfh;
330 BITMAPV5HEADER bih;
331 UINT info_size;
332 LARGE_INTEGER pos;
333 ULONG byteswritten;
334 HRESULT hr;
335
336 TRACE("(%p)\n", iface);
337
338 if (!This->bits || This->committed || This->height != This->lineswritten)
339 return WINCODEC_ERR_WRONGSTATE;
340
341 bfh.bfType = 0x4d42; /* "BM" */
342 bfh.bfReserved1 = 0;
343 bfh.bfReserved2 = 0;
344
345 bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER);
346 bih.bV5Width = This->width;
347 bih.bV5Height = -This->height; /* top-down bitmap */
348 bih.bV5Planes = 1;
349 bih.bV5BitCount = This->format->bpp;
350 bih.bV5Compression = This->format->compression;
351 bih.bV5SizeImage = This->stride*This->height;
352 bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254;
353 bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254;
354 bih.bV5ClrUsed = 0;
355 bih.bV5ClrImportant = 0;
356
357 if (This->format->compression == BI_BITFIELDS)
358 {
359 if (This->format->alphamask)
360 bih.bV5Size = info_size = sizeof(BITMAPV4HEADER);
361 else
362 info_size = sizeof(BITMAPINFOHEADER)+12;
363 bih.bV5RedMask = This->format->redmask;
364 bih.bV5GreenMask = This->format->greenmask;
365 bih.bV5BlueMask = This->format->bluemask;
366 bih.bV5AlphaMask = This->format->alphamask;
367 bih.bV5AlphaMask = LCS_DEVICE_RGB;
368 }
369
370 bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage;
371 bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size;
372
373 pos.QuadPart = 0;
374 hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL);
375 if (FAILED(hr)) return hr;
376
377 hr = IStream_Write(This->stream, &bfh, sizeof(BITMAPFILEHEADER), &byteswritten);
378 if (FAILED(hr)) return hr;
379 if (byteswritten != sizeof(BITMAPFILEHEADER)) return E_FAIL;
380
381 hr = IStream_Write(This->stream, &bih, info_size, &byteswritten);
382 if (FAILED(hr)) return hr;
383 if (byteswritten != info_size) return E_FAIL;
384
385 hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten);
386 if (FAILED(hr)) return hr;
387 if (byteswritten != bih.bV5SizeImage) return E_FAIL;
388
389 This->committed = TRUE;
390
391 return S_OK;
392 }
393
394 static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
395 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
396 {
397 FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
398 return E_NOTIMPL;
399 }
400
401 static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
402 BmpFrameEncode_QueryInterface,
403 BmpFrameEncode_AddRef,
404 BmpFrameEncode_Release,
405 BmpFrameEncode_Initialize,
406 BmpFrameEncode_SetSize,
407 BmpFrameEncode_SetResolution,
408 BmpFrameEncode_SetPixelFormat,
409 BmpFrameEncode_SetColorContexts,
410 BmpFrameEncode_SetPalette,
411 BmpFrameEncode_SetThumbnail,
412 BmpFrameEncode_WritePixels,
413 BmpFrameEncode_WriteSource,
414 BmpFrameEncode_Commit,
415 BmpFrameEncode_GetMetadataQueryWriter
416 };
417
418 typedef struct BmpEncoder {
419 IWICBitmapEncoder IWICBitmapEncoder_iface;
420 LONG ref;
421 IStream *stream;
422 BmpFrameEncode *frame;
423 } BmpEncoder;
424
425 static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
426 {
427 return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
428 }
429
430 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
431 void **ppv)
432 {
433 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
434 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
435
436 if (!ppv) return E_INVALIDARG;
437
438 if (IsEqualIID(&IID_IUnknown, iid) ||
439 IsEqualIID(&IID_IWICBitmapEncoder, iid))
440 {
441 *ppv = &This->IWICBitmapEncoder_iface;
442 }
443 else
444 {
445 *ppv = NULL;
446 return E_NOINTERFACE;
447 }
448
449 IUnknown_AddRef((IUnknown*)*ppv);
450 return S_OK;
451 }
452
453 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
454 {
455 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
456 ULONG ref = InterlockedIncrement(&This->ref);
457
458 TRACE("(%p) refcount=%u\n", iface, ref);
459
460 return ref;
461 }
462
463 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
464 {
465 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
466 ULONG ref = InterlockedDecrement(&This->ref);
467
468 TRACE("(%p) refcount=%u\n", iface, ref);
469
470 if (ref == 0)
471 {
472 if (This->stream) IStream_Release(This->stream);
473 if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
474 HeapFree(GetProcessHeap(), 0, This);
475 }
476
477 return ref;
478 }
479
480 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
481 IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
482 {
483 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
484
485 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
486
487 IStream_AddRef(pIStream);
488 This->stream = pIStream;
489
490 return S_OK;
491 }
492
493 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
494 GUID *pguidContainerFormat)
495 {
496 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
497 return S_OK;
498 }
499
500 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
501 IWICBitmapEncoderInfo **ppIEncoderInfo)
502 {
503 FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
504 return E_NOTIMPL;
505 }
506
507 static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface,
508 UINT cCount, IWICColorContext **ppIColorContext)
509 {
510 FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
511 return E_NOTIMPL;
512 }
513
514 static HRESULT WINAPI BmpEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
515 {
516 TRACE("(%p,%p)\n", iface, pIPalette);
517 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
518 }
519
520 static HRESULT WINAPI BmpEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
521 {
522 TRACE("(%p,%p)\n", iface, pIThumbnail);
523 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
524 }
525
526 static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
527 {
528 TRACE("(%p,%p)\n", iface, pIPreview);
529 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
530 }
531
532 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
533 IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
534 {
535 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
536 BmpFrameEncode *encode;
537 HRESULT hr;
538
539 TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
540
541 if (This->frame) return WINCODEC_ERR_UNSUPPORTEDOPERATION;
542
543 if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED;
544
545 hr = CreatePropertyBag2(ppIEncoderOptions);
546 if (FAILED(hr)) return hr;
547
548 encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode));
549 if (!encode)
550 {
551 IPropertyBag2_Release(*ppIEncoderOptions);
552 *ppIEncoderOptions = NULL;
553 return E_OUTOFMEMORY;
554 }
555 encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
556 encode->ref = 2;
557 IStream_AddRef(This->stream);
558 encode->stream = This->stream;
559 encode->initialized = FALSE;
560 encode->width = 0;
561 encode->height = 0;
562 encode->bits = NULL;
563 encode->format = NULL;
564 encode->xres = 0.0;
565 encode->yres = 0.0;
566 encode->lineswritten = 0;
567 encode->committed = FALSE;
568
569 *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
570 This->frame = encode;
571
572 return S_OK;
573 }
574
575 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
576 {
577 BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
578 TRACE("(%p)\n", iface);
579
580 if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
581
582 return S_OK;
583 }
584
585 static HRESULT WINAPI BmpEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
586 IWICMetadataQueryWriter **ppIMetadataQueryWriter)
587 {
588 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
589 return E_NOTIMPL;
590 }
591
592 static const IWICBitmapEncoderVtbl BmpEncoder_Vtbl = {
593 BmpEncoder_QueryInterface,
594 BmpEncoder_AddRef,
595 BmpEncoder_Release,
596 BmpEncoder_Initialize,
597 BmpEncoder_GetContainerFormat,
598 BmpEncoder_GetEncoderInfo,
599 BmpEncoder_SetColorContexts,
600 BmpEncoder_SetPalette,
601 BmpEncoder_SetThumbnail,
602 BmpEncoder_SetPreview,
603 BmpEncoder_CreateNewFrame,
604 BmpEncoder_Commit,
605 BmpEncoder_GetMetadataQueryWriter
606 };
607
608 HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
609 {
610 BmpEncoder *This;
611 HRESULT ret;
612
613 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
614
615 *ppv = NULL;
616
617 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
618
619 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
620 if (!This) return E_OUTOFMEMORY;
621
622 This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
623 This->ref = 1;
624 This->stream = NULL;
625 This->frame = NULL;
626
627 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
628 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
629
630 return ret;
631 }