windowscodecs: Implement conversion from BlackWhite to 32bppBGRA.
[wine] / dlls / windowscodecs / 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 "config.h"
20
21 #include <stdarg.h>
22
23 #define COBJMACROS
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "wincodec.h"
29
30 #include "wincodecs_private.h"
31
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
35
36 struct FormatConverter;
37
38 enum pixelformat {
39     format_1bppIndexed,
40     format_4bppIndexed,
41     format_8bppIndexed,
42     format_BlackWhite,
43     format_8bppGray,
44     format_16bppBGR555,
45     format_16bppBGR565,
46     format_24bppBGR,
47     format_32bppBGR,
48     format_32bppBGRA
49 };
50
51 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
52     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
53
54 struct pixelformatinfo {
55     enum pixelformat format;
56     const WICPixelFormatGUID *guid;
57     copyfunc copy_function;
58 };
59
60 typedef struct FormatConverter {
61     const IWICFormatConverterVtbl *lpVtbl;
62     LONG ref;
63     IWICBitmapSource *source;
64     const struct pixelformatinfo *dst_format, *src_format;
65     WICBitmapDitherType dither;
66     double alpha_threshold;
67     WICBitmapPaletteType palette_type;
68 } FormatConverter;
69
70 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
71     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
72 {
73     switch (source_format)
74     {
75     case format_1bppIndexed:
76     case format_BlackWhite:
77         if (prc)
78         {
79             HRESULT res;
80             UINT x, y;
81             BYTE *srcdata;
82             UINT srcstride, srcdatasize;
83             const BYTE *srcrow;
84             const BYTE *srcbyte;
85             BYTE *dstrow;
86             DWORD *dstpixel;
87             WICColor colors[2];
88             IWICPalette *palette;
89             UINT actualcolors;
90
91             if (source_format == format_1bppIndexed)
92             {
93                 res = PaletteImpl_Create(&palette);
94                 if (FAILED(res)) return res;
95
96                 res = IWICBitmapSource_CopyPalette(This->source, palette);
97                 if (SUCCEEDED(res))
98                     res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
99
100                 IWICPalette_Release(palette);
101
102                 if (FAILED(res)) return res;
103             }
104             else
105             {
106                 colors[0] = 0xff000000;
107                 colors[1] = 0xffffffff;
108             }
109
110             srcstride = (prc->Width+7)/8;
111             srcdatasize = srcstride * prc->Height;
112
113             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
114             if (!srcdata) return E_OUTOFMEMORY;
115
116             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
117
118             if (SUCCEEDED(res))
119             {
120                 srcrow = srcdata;
121                 dstrow = pbBuffer;
122                 for (y=0; y<prc->Height; y++) {
123                     srcbyte=(const BYTE*)srcrow;
124                     dstpixel=(DWORD*)dstrow;
125                     for (x=0; x<prc->Width; x+=8) {
126                         BYTE srcval;
127                         srcval=*srcbyte++;
128                         *dstpixel++ = colors[srcval>>7&1];
129                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
130                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
131                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
132                         if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
133                         if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
134                         if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
135                         if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
136                     }
137                     srcrow += srcstride;
138                     dstrow += cbStride;
139                 }
140             }
141
142             HeapFree(GetProcessHeap(), 0, srcdata);
143
144             return res;
145         }
146         return S_OK;
147     case format_4bppIndexed:
148         if (prc)
149         {
150             HRESULT res;
151             UINT x, y;
152             BYTE *srcdata;
153             UINT srcstride, srcdatasize;
154             const BYTE *srcrow;
155             const BYTE *srcbyte;
156             BYTE *dstrow;
157             DWORD *dstpixel;
158             WICColor colors[16];
159             IWICPalette *palette;
160             UINT actualcolors;
161
162             res = PaletteImpl_Create(&palette);
163             if (FAILED(res)) return res;
164
165             res = IWICBitmapSource_CopyPalette(This->source, palette);
166             if (SUCCEEDED(res))
167                 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
168
169             IWICPalette_Release(palette);
170
171             if (FAILED(res)) return res;
172
173             srcstride = (prc->Width+1)/2;
174             srcdatasize = srcstride * prc->Height;
175
176             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
177             if (!srcdata) return E_OUTOFMEMORY;
178
179             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
180
181             if (SUCCEEDED(res))
182             {
183                 srcrow = srcdata;
184                 dstrow = pbBuffer;
185                 for (y=0; y<prc->Height; y++) {
186                     srcbyte=(const BYTE*)srcrow;
187                     dstpixel=(DWORD*)dstrow;
188                     for (x=0; x<prc->Width; x+=2) {
189                         BYTE srcval;
190                         srcval=*srcbyte++;
191                         *dstpixel++ = colors[srcval>>4];
192                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
193                     }
194                     srcrow += srcstride;
195                     dstrow += cbStride;
196                 }
197             }
198
199             HeapFree(GetProcessHeap(), 0, srcdata);
200
201             return res;
202         }
203         return S_OK;
204     case format_8bppGray:
205         if (prc)
206         {
207             HRESULT res;
208             UINT x, y;
209             BYTE *srcdata;
210             UINT srcstride, srcdatasize;
211             const BYTE *srcrow;
212             const BYTE *srcbyte;
213             BYTE *dstrow;
214             DWORD *dstpixel;
215
216             srcstride = prc->Width;
217             srcdatasize = srcstride * prc->Height;
218
219             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
220             if (!srcdata) return E_OUTOFMEMORY;
221
222             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
223
224             if (SUCCEEDED(res))
225             {
226                 srcrow = srcdata;
227                 dstrow = pbBuffer;
228                 for (y=0; y<prc->Height; y++) {
229                     srcbyte=(const BYTE*)srcrow;
230                     dstpixel=(DWORD*)dstrow;
231                     for (x=0; x<prc->Width; x++)
232                     {
233                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
234                         srcbyte++;
235                     }
236                     srcrow += srcstride;
237                     dstrow += cbStride;
238                 }
239             }
240
241             HeapFree(GetProcessHeap(), 0, srcdata);
242
243             return res;
244         }
245         return S_OK;
246     case format_8bppIndexed:
247         if (prc)
248         {
249             HRESULT res;
250             UINT x, y;
251             BYTE *srcdata;
252             UINT srcstride, srcdatasize;
253             const BYTE *srcrow;
254             const BYTE *srcbyte;
255             BYTE *dstrow;
256             DWORD *dstpixel;
257             WICColor colors[256];
258             IWICPalette *palette;
259             UINT actualcolors;
260
261             res = PaletteImpl_Create(&palette);
262             if (FAILED(res)) return res;
263
264             res = IWICBitmapSource_CopyPalette(This->source, palette);
265             if (SUCCEEDED(res))
266                 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
267
268             IWICPalette_Release(palette);
269
270             if (FAILED(res)) return res;
271
272             srcstride = prc->Width;
273             srcdatasize = srcstride * prc->Height;
274
275             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
276             if (!srcdata) return E_OUTOFMEMORY;
277
278             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
279
280             if (SUCCEEDED(res))
281             {
282                 srcrow = srcdata;
283                 dstrow = pbBuffer;
284                 for (y=0; y<prc->Height; y++) {
285                     srcbyte=(const BYTE*)srcrow;
286                     dstpixel=(DWORD*)dstrow;
287                     for (x=0; x<prc->Width; x++)
288                         *dstpixel++ = colors[*srcbyte++];
289                     srcrow += srcstride;
290                     dstrow += cbStride;
291                 }
292             }
293
294             HeapFree(GetProcessHeap(), 0, srcdata);
295
296             return res;
297         }
298         return S_OK;
299     case format_16bppBGR555:
300         if (prc)
301         {
302             HRESULT res;
303             UINT x, y;
304             BYTE *srcdata;
305             UINT srcstride, srcdatasize;
306             const BYTE *srcrow;
307             const WORD *srcpixel;
308             BYTE *dstrow;
309             DWORD *dstpixel;
310
311             srcstride = 2 * prc->Width;
312             srcdatasize = srcstride * prc->Height;
313
314             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
315             if (!srcdata) return E_OUTOFMEMORY;
316
317             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
318
319             if (SUCCEEDED(res))
320             {
321                 srcrow = srcdata;
322                 dstrow = pbBuffer;
323                 for (y=0; y<prc->Height; y++) {
324                     srcpixel=(const WORD*)srcrow;
325                     dstpixel=(DWORD*)dstrow;
326                     for (x=0; x<prc->Width; x++) {
327                         WORD srcval;
328                         srcval=*srcpixel++;
329                         *dstpixel++=0xff000000 | /* constant 255 alpha */
330                                     ((srcval << 9) & 0xf80000) | /* r */
331                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
332                                     ((srcval << 6) & 0x00f800) | /* g */
333                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
334                                     ((srcval << 3) & 0x0000f8) | /* b */
335                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
336                     }
337                     srcrow += srcstride;
338                     dstrow += cbStride;
339                 }
340             }
341
342             HeapFree(GetProcessHeap(), 0, srcdata);
343
344             return res;
345         }
346         return S_OK;
347     case format_16bppBGR565:
348         if (prc)
349         {
350             HRESULT res;
351             UINT x, y;
352             BYTE *srcdata;
353             UINT srcstride, srcdatasize;
354             const BYTE *srcrow;
355             const WORD *srcpixel;
356             BYTE *dstrow;
357             DWORD *dstpixel;
358
359             srcstride = 2 * prc->Width;
360             srcdatasize = srcstride * prc->Height;
361
362             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
363             if (!srcdata) return E_OUTOFMEMORY;
364
365             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
366
367             if (SUCCEEDED(res))
368             {
369                 srcrow = srcdata;
370                 dstrow = pbBuffer;
371                 for (y=0; y<prc->Height; y++) {
372                     srcpixel=(const WORD*)srcrow;
373                     dstpixel=(DWORD*)dstrow;
374                     for (x=0; x<prc->Width; x++) {
375                         WORD srcval;
376                         srcval=*srcpixel++;
377                         *dstpixel++=0xff000000 | /* constant 255 alpha */
378                                     ((srcval << 8) & 0xf80000) | /* r */
379                                     ((srcval << 3) & 0x070000) | /* r - 3 bits */
380                                     ((srcval << 5) & 0x00fc00) | /* g */
381                                     ((srcval >> 1) & 0x000300) | /* g - 2 bits */
382                                     ((srcval << 3) & 0x0000f8) | /* b */
383                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
384                     }
385                     srcrow += srcstride;
386                     dstrow += cbStride;
387                 }
388             }
389
390             HeapFree(GetProcessHeap(), 0, srcdata);
391
392             return res;
393         }
394         return S_OK;
395     case format_24bppBGR:
396         if (prc)
397         {
398             HRESULT res;
399             UINT x, y;
400             BYTE *srcdata;
401             UINT srcstride, srcdatasize;
402             const BYTE *srcrow;
403             const BYTE *srcpixel;
404             BYTE *dstrow;
405             BYTE *dstpixel;
406
407             srcstride = 3 * prc->Width;
408             srcdatasize = srcstride * prc->Height;
409
410             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
411             if (!srcdata) return E_OUTOFMEMORY;
412
413             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
414
415             if (SUCCEEDED(res))
416             {
417                 srcrow = srcdata;
418                 dstrow = pbBuffer;
419                 for (y=0; y<prc->Height; y++) {
420                     srcpixel=srcrow;
421                     dstpixel=dstrow;
422                     for (x=0; x<prc->Width; x++) {
423                         *dstpixel++=*srcpixel++; /* blue */
424                         *dstpixel++=*srcpixel++; /* green */
425                         *dstpixel++=*srcpixel++; /* red */
426                         *dstpixel++=255; /* alpha */
427                     }
428                     srcrow += srcstride;
429                     dstrow += cbStride;
430                 }
431             }
432
433             HeapFree(GetProcessHeap(), 0, srcdata);
434
435             return res;
436         }
437         return S_OK;
438     case format_32bppBGR:
439         if (prc)
440         {
441             HRESULT res;
442             UINT x, y;
443
444             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
445             if (FAILED(res)) return res;
446
447             /* set all alpha values to 255 */
448             for (y=0; y<prc->Height; y++)
449                 for (x=0; x<prc->Width; x++)
450                     pbBuffer[cbStride*y+4*x+3] = 0xff;
451         }
452         return S_OK;
453     case format_32bppBGRA:
454         if (prc)
455             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
456         return S_OK;
457     default:
458         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
459     }
460 }
461
462 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
463     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
464 {
465     switch (source_format)
466     {
467     case format_32bppBGR:
468     case format_32bppBGRA:
469         if (prc)
470             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
471         return S_OK;
472     default:
473         return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
474     }
475 }
476
477 static const struct pixelformatinfo supported_formats[] = {
478     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
479     {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
480     {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
481     {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
482     {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
483     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
484     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
485     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
486     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
487     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
488     {0}
489 };
490
491 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
492 {
493     UINT i;
494
495     for (i=0; supported_formats[i].guid; i++)
496         if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
497
498     return NULL;
499 }
500
501 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
502     void **ppv)
503 {
504     FormatConverter *This = (FormatConverter*)iface;
505     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
506
507     if (!ppv) return E_INVALIDARG;
508
509     if (IsEqualIID(&IID_IUnknown, iid) ||
510         IsEqualIID(&IID_IWICBitmapSource, iid) ||
511         IsEqualIID(&IID_IWICFormatConverter, iid))
512     {
513         *ppv = This;
514     }
515     else
516     {
517         *ppv = NULL;
518         return E_NOINTERFACE;
519     }
520
521     IUnknown_AddRef((IUnknown*)*ppv);
522     return S_OK;
523 }
524
525 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
526 {
527     FormatConverter *This = (FormatConverter*)iface;
528     ULONG ref = InterlockedIncrement(&This->ref);
529
530     TRACE("(%p) refcount=%u\n", iface, ref);
531
532     return ref;
533 }
534
535 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
536 {
537     FormatConverter *This = (FormatConverter*)iface;
538     ULONG ref = InterlockedDecrement(&This->ref);
539
540     TRACE("(%p) refcount=%u\n", iface, ref);
541
542     if (ref == 0)
543     {
544         if (This->source) IWICBitmapSource_Release(This->source);
545         HeapFree(GetProcessHeap(), 0, This);
546     }
547
548     return ref;
549 }
550
551 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
552     UINT *puiWidth, UINT *puiHeight)
553 {
554     FormatConverter *This = (FormatConverter*)iface;
555
556     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
557
558     if (This->source)
559         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
560     else
561         return WINCODEC_ERR_NOTINITIALIZED;
562 }
563
564 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
565     WICPixelFormatGUID *pPixelFormat)
566 {
567     FormatConverter *This = (FormatConverter*)iface;
568
569     TRACE("(%p,%p): stub\n", iface, pPixelFormat);
570
571     if (This->source)
572         memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
573     else
574         return WINCODEC_ERR_NOTINITIALIZED;
575
576     return S_OK;
577 }
578
579 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
580     double *pDpiX, double *pDpiY)
581 {
582     FormatConverter *This = (FormatConverter*)iface;
583
584     TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
585
586     if (This->source)
587         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
588     else
589         return WINCODEC_ERR_NOTINITIALIZED;
590 }
591
592 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
593     IWICPalette *pIPalette)
594 {
595     FIXME("(%p,%p): stub\n", iface, pIPalette);
596     return E_NOTIMPL;
597 }
598
599 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
600     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
601 {
602     FormatConverter *This = (FormatConverter*)iface;
603     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
604
605     if (This->source)
606         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
607             pbBuffer, This->src_format->format);
608     else
609         return WINCODEC_ERR_NOTINITIALIZED;
610 }
611
612 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
613     IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
614     IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
615 {
616     FormatConverter *This = (FormatConverter*)iface;
617     const struct pixelformatinfo *srcinfo, *dstinfo;
618     static INT fixme=0;
619     GUID srcFormat;
620     HRESULT res;
621
622     TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
623         dither, pIPalette, alphaThresholdPercent, paletteTranslate);
624
625     if (pIPalette && !fixme++) FIXME("ignoring palette\n");
626
627     if (This->source) return WINCODEC_ERR_WRONGSTATE;
628
629     res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
630     if (FAILED(res)) return res;
631
632     srcinfo = get_formatinfo(&srcFormat);
633     if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
634
635     dstinfo = get_formatinfo(dstFormat);
636     if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
637
638     if (dstinfo->copy_function)
639     {
640         IWICBitmapSource_AddRef(pISource);
641         This->source = pISource;
642         This->src_format = srcinfo;
643         This->dst_format = dstinfo;
644         This->dither = dither;
645         This->alpha_threshold = alphaThresholdPercent;
646         This->palette_type = paletteTranslate;
647     }
648     else
649         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
650
651     return S_OK;
652 }
653
654 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
655     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
656     BOOL *pfCanConvert)
657 {
658     FormatConverter *This = (FormatConverter*)iface;
659     const struct pixelformatinfo *srcinfo, *dstinfo;
660
661     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
662         debugstr_guid(dstPixelFormat), pfCanConvert);
663
664     srcinfo = get_formatinfo(srcPixelFormat);
665     if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
666
667     dstinfo = get_formatinfo(dstPixelFormat);
668     if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
669
670     if (dstinfo->copy_function &&
671         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
672         *pfCanConvert = TRUE;
673     else
674         *pfCanConvert = FALSE;
675
676     return S_OK;
677 }
678
679 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
680     FormatConverter_QueryInterface,
681     FormatConverter_AddRef,
682     FormatConverter_Release,
683     FormatConverter_GetSize,
684     FormatConverter_GetPixelFormat,
685     FormatConverter_GetResolution,
686     FormatConverter_CopyPalette,
687     FormatConverter_CopyPixels,
688     FormatConverter_Initialize,
689     FormatConverter_CanConvert
690 };
691
692 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
693 {
694     FormatConverter *This;
695     HRESULT ret;
696
697     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
698
699     *ppv = NULL;
700
701     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
702
703     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
704     if (!This) return E_OUTOFMEMORY;
705
706     This->lpVtbl = &FormatConverter_Vtbl;
707     This->ref = 1;
708     This->source = NULL;
709
710     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
711     IUnknown_Release((IUnknown*)This);
712
713     return ret;
714 }