wgl: Add initial WGL_ARB_create_context support.
[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_2bppIndexed,
41     format_4bppIndexed,
42     format_8bppIndexed,
43     format_BlackWhite,
44     format_2bppGray,
45     format_4bppGray,
46     format_8bppGray,
47     format_16bppGray,
48     format_16bppBGR555,
49     format_16bppBGR565,
50     format_24bppBGR,
51     format_32bppBGR,
52     format_32bppBGRA,
53     format_48bppRGB,
54     format_64bppRGBA,
55 };
56
57 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
58     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
59
60 struct pixelformatinfo {
61     enum pixelformat format;
62     const WICPixelFormatGUID *guid;
63     copyfunc copy_function;
64 };
65
66 typedef struct FormatConverter {
67     const IWICFormatConverterVtbl *lpVtbl;
68     LONG ref;
69     IWICBitmapSource *source;
70     const struct pixelformatinfo *dst_format, *src_format;
71     WICBitmapDitherType dither;
72     double alpha_threshold;
73     WICBitmapPaletteType palette_type;
74 } FormatConverter;
75
76 static void make_grayscale_palette(WICColor *colors, UINT num_colors)
77 {
78     int i, v;
79     for (i=0; i<num_colors; i++)
80     {
81         v = i * 255 / (num_colors-1);
82         colors[i] = 0xff000000 | v<<16 | v<<8 | v;
83     }
84 }
85
86 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
87     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
88 {
89     switch (source_format)
90     {
91     case format_1bppIndexed:
92     case format_BlackWhite:
93         if (prc)
94         {
95             HRESULT res;
96             UINT x, y;
97             BYTE *srcdata;
98             UINT srcstride, srcdatasize;
99             const BYTE *srcrow;
100             const BYTE *srcbyte;
101             BYTE *dstrow;
102             DWORD *dstpixel;
103             WICColor colors[2];
104             IWICPalette *palette;
105             UINT actualcolors;
106
107             if (source_format == format_1bppIndexed)
108             {
109                 res = PaletteImpl_Create(&palette);
110                 if (FAILED(res)) return res;
111
112                 res = IWICBitmapSource_CopyPalette(This->source, palette);
113                 if (SUCCEEDED(res))
114                     res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
115
116                 IWICPalette_Release(palette);
117
118                 if (FAILED(res)) return res;
119             }
120             else
121             {
122                 colors[0] = 0xff000000;
123                 colors[1] = 0xffffffff;
124             }
125
126             srcstride = (prc->Width+7)/8;
127             srcdatasize = srcstride * prc->Height;
128
129             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
130             if (!srcdata) return E_OUTOFMEMORY;
131
132             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
133
134             if (SUCCEEDED(res))
135             {
136                 srcrow = srcdata;
137                 dstrow = pbBuffer;
138                 for (y=0; y<prc->Height; y++) {
139                     srcbyte=(const BYTE*)srcrow;
140                     dstpixel=(DWORD*)dstrow;
141                     for (x=0; x<prc->Width; x+=8) {
142                         BYTE srcval;
143                         srcval=*srcbyte++;
144                         *dstpixel++ = colors[srcval>>7&1];
145                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
146                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
147                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
148                         if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
149                         if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
150                         if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
151                         if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
152                     }
153                     srcrow += srcstride;
154                     dstrow += cbStride;
155                 }
156             }
157
158             HeapFree(GetProcessHeap(), 0, srcdata);
159
160             return res;
161         }
162         return S_OK;
163     case format_2bppIndexed:
164     case format_2bppGray:
165         if (prc)
166         {
167             HRESULT res;
168             UINT x, y;
169             BYTE *srcdata;
170             UINT srcstride, srcdatasize;
171             const BYTE *srcrow;
172             const BYTE *srcbyte;
173             BYTE *dstrow;
174             DWORD *dstpixel;
175             WICColor colors[4];
176             IWICPalette *palette;
177             UINT actualcolors;
178
179             if (source_format == format_2bppIndexed)
180             {
181                 res = PaletteImpl_Create(&palette);
182                 if (FAILED(res)) return res;
183
184                 res = IWICBitmapSource_CopyPalette(This->source, palette);
185                 if (SUCCEEDED(res))
186                     res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
187
188                 IWICPalette_Release(palette);
189
190                 if (FAILED(res)) return res;
191             }
192             else
193                 make_grayscale_palette(colors, 4);
194
195             srcstride = (prc->Width+3)/4;
196             srcdatasize = srcstride * prc->Height;
197
198             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
199             if (!srcdata) return E_OUTOFMEMORY;
200
201             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
202
203             if (SUCCEEDED(res))
204             {
205                 srcrow = srcdata;
206                 dstrow = pbBuffer;
207                 for (y=0; y<prc->Height; y++) {
208                     srcbyte=(const BYTE*)srcrow;
209                     dstpixel=(DWORD*)dstrow;
210                     for (x=0; x<prc->Width; x+=4) {
211                         BYTE srcval;
212                         srcval=*srcbyte++;
213                         *dstpixel++ = colors[srcval>>6];
214                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
215                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
216                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
217                     }
218                     srcrow += srcstride;
219                     dstrow += cbStride;
220                 }
221             }
222
223             HeapFree(GetProcessHeap(), 0, srcdata);
224
225             return res;
226         }
227         return S_OK;
228     case format_4bppIndexed:
229     case format_4bppGray:
230         if (prc)
231         {
232             HRESULT res;
233             UINT x, y;
234             BYTE *srcdata;
235             UINT srcstride, srcdatasize;
236             const BYTE *srcrow;
237             const BYTE *srcbyte;
238             BYTE *dstrow;
239             DWORD *dstpixel;
240             WICColor colors[16];
241             IWICPalette *palette;
242             UINT actualcolors;
243
244             if (source_format == format_4bppIndexed)
245             {
246                 res = PaletteImpl_Create(&palette);
247                 if (FAILED(res)) return res;
248
249                 res = IWICBitmapSource_CopyPalette(This->source, palette);
250                 if (SUCCEEDED(res))
251                     res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
252
253                 IWICPalette_Release(palette);
254
255                 if (FAILED(res)) return res;
256             }
257             else
258                 make_grayscale_palette(colors, 16);
259
260             srcstride = (prc->Width+1)/2;
261             srcdatasize = srcstride * prc->Height;
262
263             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
264             if (!srcdata) return E_OUTOFMEMORY;
265
266             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
267
268             if (SUCCEEDED(res))
269             {
270                 srcrow = srcdata;
271                 dstrow = pbBuffer;
272                 for (y=0; y<prc->Height; y++) {
273                     srcbyte=(const BYTE*)srcrow;
274                     dstpixel=(DWORD*)dstrow;
275                     for (x=0; x<prc->Width; x+=2) {
276                         BYTE srcval;
277                         srcval=*srcbyte++;
278                         *dstpixel++ = colors[srcval>>4];
279                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
280                     }
281                     srcrow += srcstride;
282                     dstrow += cbStride;
283                 }
284             }
285
286             HeapFree(GetProcessHeap(), 0, srcdata);
287
288             return res;
289         }
290         return S_OK;
291     case format_8bppGray:
292         if (prc)
293         {
294             HRESULT res;
295             UINT x, y;
296             BYTE *srcdata;
297             UINT srcstride, srcdatasize;
298             const BYTE *srcrow;
299             const BYTE *srcbyte;
300             BYTE *dstrow;
301             DWORD *dstpixel;
302
303             srcstride = prc->Width;
304             srcdatasize = srcstride * prc->Height;
305
306             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
307             if (!srcdata) return E_OUTOFMEMORY;
308
309             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
310
311             if (SUCCEEDED(res))
312             {
313                 srcrow = srcdata;
314                 dstrow = pbBuffer;
315                 for (y=0; y<prc->Height; y++) {
316                     srcbyte=(const BYTE*)srcrow;
317                     dstpixel=(DWORD*)dstrow;
318                     for (x=0; x<prc->Width; x++)
319                     {
320                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
321                         srcbyte++;
322                     }
323                     srcrow += srcstride;
324                     dstrow += cbStride;
325                 }
326             }
327
328             HeapFree(GetProcessHeap(), 0, srcdata);
329
330             return res;
331         }
332         return S_OK;
333     case format_8bppIndexed:
334         if (prc)
335         {
336             HRESULT res;
337             UINT x, y;
338             BYTE *srcdata;
339             UINT srcstride, srcdatasize;
340             const BYTE *srcrow;
341             const BYTE *srcbyte;
342             BYTE *dstrow;
343             DWORD *dstpixel;
344             WICColor colors[256];
345             IWICPalette *palette;
346             UINT actualcolors;
347
348             res = PaletteImpl_Create(&palette);
349             if (FAILED(res)) return res;
350
351             res = IWICBitmapSource_CopyPalette(This->source, palette);
352             if (SUCCEEDED(res))
353                 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
354
355             IWICPalette_Release(palette);
356
357             if (FAILED(res)) return res;
358
359             srcstride = 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                     srcbyte=(const BYTE*)srcrow;
373                     dstpixel=(DWORD*)dstrow;
374                     for (x=0; x<prc->Width; x++)
375                         *dstpixel++ = colors[*srcbyte++];
376                     srcrow += srcstride;
377                     dstrow += cbStride;
378                 }
379             }
380
381             HeapFree(GetProcessHeap(), 0, srcdata);
382
383             return res;
384         }
385         return S_OK;
386     case format_16bppGray:
387         if (prc)
388         {
389             HRESULT res;
390             UINT x, y;
391             BYTE *srcdata;
392             UINT srcstride, srcdatasize;
393             const BYTE *srcrow;
394             const BYTE *srcbyte;
395             BYTE *dstrow;
396             DWORD *dstpixel;
397
398             srcstride = prc->Width * 2;
399             srcdatasize = srcstride * prc->Height;
400
401             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
402             if (!srcdata) return E_OUTOFMEMORY;
403
404             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
405
406             if (SUCCEEDED(res))
407             {
408                 srcrow = srcdata;
409                 dstrow = pbBuffer;
410                 for (y=0; y<prc->Height; y++) {
411                     srcbyte=(const BYTE*)srcrow;
412                     dstpixel=(DWORD*)dstrow;
413                     for (x=0; x<prc->Width; x++)
414                     {
415                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
416                         srcbyte+=2;
417                     }
418                     srcrow += srcstride;
419                     dstrow += cbStride;
420                 }
421             }
422
423             HeapFree(GetProcessHeap(), 0, srcdata);
424
425             return res;
426         }
427         return S_OK;
428     case format_16bppBGR555:
429         if (prc)
430         {
431             HRESULT res;
432             UINT x, y;
433             BYTE *srcdata;
434             UINT srcstride, srcdatasize;
435             const BYTE *srcrow;
436             const WORD *srcpixel;
437             BYTE *dstrow;
438             DWORD *dstpixel;
439
440             srcstride = 2 * prc->Width;
441             srcdatasize = srcstride * prc->Height;
442
443             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
444             if (!srcdata) return E_OUTOFMEMORY;
445
446             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
447
448             if (SUCCEEDED(res))
449             {
450                 srcrow = srcdata;
451                 dstrow = pbBuffer;
452                 for (y=0; y<prc->Height; y++) {
453                     srcpixel=(const WORD*)srcrow;
454                     dstpixel=(DWORD*)dstrow;
455                     for (x=0; x<prc->Width; x++) {
456                         WORD srcval;
457                         srcval=*srcpixel++;
458                         *dstpixel++=0xff000000 | /* constant 255 alpha */
459                                     ((srcval << 9) & 0xf80000) | /* r */
460                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
461                                     ((srcval << 6) & 0x00f800) | /* g */
462                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
463                                     ((srcval << 3) & 0x0000f8) | /* b */
464                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
465                     }
466                     srcrow += srcstride;
467                     dstrow += cbStride;
468                 }
469             }
470
471             HeapFree(GetProcessHeap(), 0, srcdata);
472
473             return res;
474         }
475         return S_OK;
476     case format_16bppBGR565:
477         if (prc)
478         {
479             HRESULT res;
480             UINT x, y;
481             BYTE *srcdata;
482             UINT srcstride, srcdatasize;
483             const BYTE *srcrow;
484             const WORD *srcpixel;
485             BYTE *dstrow;
486             DWORD *dstpixel;
487
488             srcstride = 2 * prc->Width;
489             srcdatasize = srcstride * prc->Height;
490
491             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
492             if (!srcdata) return E_OUTOFMEMORY;
493
494             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
495
496             if (SUCCEEDED(res))
497             {
498                 srcrow = srcdata;
499                 dstrow = pbBuffer;
500                 for (y=0; y<prc->Height; y++) {
501                     srcpixel=(const WORD*)srcrow;
502                     dstpixel=(DWORD*)dstrow;
503                     for (x=0; x<prc->Width; x++) {
504                         WORD srcval;
505                         srcval=*srcpixel++;
506                         *dstpixel++=0xff000000 | /* constant 255 alpha */
507                                     ((srcval << 8) & 0xf80000) | /* r */
508                                     ((srcval << 3) & 0x070000) | /* r - 3 bits */
509                                     ((srcval << 5) & 0x00fc00) | /* g */
510                                     ((srcval >> 1) & 0x000300) | /* g - 2 bits */
511                                     ((srcval << 3) & 0x0000f8) | /* b */
512                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
513                     }
514                     srcrow += srcstride;
515                     dstrow += cbStride;
516                 }
517             }
518
519             HeapFree(GetProcessHeap(), 0, srcdata);
520
521             return res;
522         }
523         return S_OK;
524     case format_24bppBGR:
525         if (prc)
526         {
527             HRESULT res;
528             UINT x, y;
529             BYTE *srcdata;
530             UINT srcstride, srcdatasize;
531             const BYTE *srcrow;
532             const BYTE *srcpixel;
533             BYTE *dstrow;
534             BYTE *dstpixel;
535
536             srcstride = 3 * prc->Width;
537             srcdatasize = srcstride * prc->Height;
538
539             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
540             if (!srcdata) return E_OUTOFMEMORY;
541
542             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
543
544             if (SUCCEEDED(res))
545             {
546                 srcrow = srcdata;
547                 dstrow = pbBuffer;
548                 for (y=0; y<prc->Height; y++) {
549                     srcpixel=srcrow;
550                     dstpixel=dstrow;
551                     for (x=0; x<prc->Width; x++) {
552                         *dstpixel++=*srcpixel++; /* blue */
553                         *dstpixel++=*srcpixel++; /* green */
554                         *dstpixel++=*srcpixel++; /* red */
555                         *dstpixel++=255; /* alpha */
556                     }
557                     srcrow += srcstride;
558                     dstrow += cbStride;
559                 }
560             }
561
562             HeapFree(GetProcessHeap(), 0, srcdata);
563
564             return res;
565         }
566         return S_OK;
567     case format_32bppBGR:
568         if (prc)
569         {
570             HRESULT res;
571             UINT x, y;
572
573             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
574             if (FAILED(res)) return res;
575
576             /* set all alpha values to 255 */
577             for (y=0; y<prc->Height; y++)
578                 for (x=0; x<prc->Width; x++)
579                     pbBuffer[cbStride*y+4*x+3] = 0xff;
580         }
581         return S_OK;
582     case format_32bppBGRA:
583         if (prc)
584             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
585         return S_OK;
586     case format_48bppRGB:
587         if (prc)
588         {
589             HRESULT res;
590             UINT x, y;
591             BYTE *srcdata;
592             UINT srcstride, srcdatasize;
593             const BYTE *srcrow;
594             const BYTE *srcpixel;
595             BYTE *dstrow;
596             DWORD *dstpixel;
597
598             srcstride = 6 * prc->Width;
599             srcdatasize = srcstride * prc->Height;
600
601             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
602             if (!srcdata) return E_OUTOFMEMORY;
603
604             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
605
606             if (SUCCEEDED(res))
607             {
608                 srcrow = srcdata;
609                 dstrow = pbBuffer;
610                 for (y=0; y<prc->Height; y++) {
611                     srcpixel=srcrow;
612                     dstpixel=(DWORD*)dstrow;
613                     for (x=0; x<prc->Width; x++) {
614                         BYTE red, green, blue;
615                         red = *srcpixel++; srcpixel++;
616                         green = *srcpixel++; srcpixel++;
617                         blue = *srcpixel++; srcpixel++;
618                         *dstpixel++=0xff000000|red<<16|green<<8|blue;
619                     }
620                     srcrow += srcstride;
621                     dstrow += cbStride;
622                 }
623             }
624
625             HeapFree(GetProcessHeap(), 0, srcdata);
626
627             return res;
628         }
629         return S_OK;
630     case format_64bppRGBA:
631         if (prc)
632         {
633             HRESULT res;
634             UINT x, y;
635             BYTE *srcdata;
636             UINT srcstride, srcdatasize;
637             const BYTE *srcrow;
638             const BYTE *srcpixel;
639             BYTE *dstrow;
640             DWORD *dstpixel;
641
642             srcstride = 8 * prc->Width;
643             srcdatasize = srcstride * prc->Height;
644
645             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
646             if (!srcdata) return E_OUTOFMEMORY;
647
648             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
649
650             if (SUCCEEDED(res))
651             {
652                 srcrow = srcdata;
653                 dstrow = pbBuffer;
654                 for (y=0; y<prc->Height; y++) {
655                     srcpixel=srcrow;
656                     dstpixel=(DWORD*)dstrow;
657                     for (x=0; x<prc->Width; x++) {
658                         BYTE red, green, blue, alpha;
659                         red = *srcpixel++; srcpixel++;
660                         green = *srcpixel++; srcpixel++;
661                         blue = *srcpixel++; srcpixel++;
662                         alpha = *srcpixel++; srcpixel++;
663                         *dstpixel++=alpha<<24|red<<16|green<<8|blue;
664                     }
665                     srcrow += srcstride;
666                     dstrow += cbStride;
667                 }
668             }
669
670             HeapFree(GetProcessHeap(), 0, srcdata);
671
672             return res;
673         }
674         return S_OK;
675     default:
676         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
677     }
678 }
679
680 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
681     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
682 {
683     switch (source_format)
684     {
685     case format_32bppBGR:
686     case format_32bppBGRA:
687         if (prc)
688             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
689         return S_OK;
690     default:
691         return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
692     }
693 }
694
695 static const struct pixelformatinfo supported_formats[] = {
696     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
697     {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
698     {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
699     {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
700     {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
701     {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
702     {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
703     {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
704     {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
705     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
706     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
707     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
708     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
709     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
710     {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
711     {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
712     {0}
713 };
714
715 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
716 {
717     UINT i;
718
719     for (i=0; supported_formats[i].guid; i++)
720         if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
721
722     return NULL;
723 }
724
725 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
726     void **ppv)
727 {
728     FormatConverter *This = (FormatConverter*)iface;
729     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
730
731     if (!ppv) return E_INVALIDARG;
732
733     if (IsEqualIID(&IID_IUnknown, iid) ||
734         IsEqualIID(&IID_IWICBitmapSource, iid) ||
735         IsEqualIID(&IID_IWICFormatConverter, iid))
736     {
737         *ppv = This;
738     }
739     else
740     {
741         *ppv = NULL;
742         return E_NOINTERFACE;
743     }
744
745     IUnknown_AddRef((IUnknown*)*ppv);
746     return S_OK;
747 }
748
749 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
750 {
751     FormatConverter *This = (FormatConverter*)iface;
752     ULONG ref = InterlockedIncrement(&This->ref);
753
754     TRACE("(%p) refcount=%u\n", iface, ref);
755
756     return ref;
757 }
758
759 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
760 {
761     FormatConverter *This = (FormatConverter*)iface;
762     ULONG ref = InterlockedDecrement(&This->ref);
763
764     TRACE("(%p) refcount=%u\n", iface, ref);
765
766     if (ref == 0)
767     {
768         if (This->source) IWICBitmapSource_Release(This->source);
769         HeapFree(GetProcessHeap(), 0, This);
770     }
771
772     return ref;
773 }
774
775 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
776     UINT *puiWidth, UINT *puiHeight)
777 {
778     FormatConverter *This = (FormatConverter*)iface;
779
780     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
781
782     if (This->source)
783         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
784     else
785         return WINCODEC_ERR_NOTINITIALIZED;
786 }
787
788 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
789     WICPixelFormatGUID *pPixelFormat)
790 {
791     FormatConverter *This = (FormatConverter*)iface;
792
793     TRACE("(%p,%p): stub\n", iface, pPixelFormat);
794
795     if (This->source)
796         memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
797     else
798         return WINCODEC_ERR_NOTINITIALIZED;
799
800     return S_OK;
801 }
802
803 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
804     double *pDpiX, double *pDpiY)
805 {
806     FormatConverter *This = (FormatConverter*)iface;
807
808     TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
809
810     if (This->source)
811         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
812     else
813         return WINCODEC_ERR_NOTINITIALIZED;
814 }
815
816 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
817     IWICPalette *pIPalette)
818 {
819     FIXME("(%p,%p): stub\n", iface, pIPalette);
820     return E_NOTIMPL;
821 }
822
823 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
824     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
825 {
826     FormatConverter *This = (FormatConverter*)iface;
827     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
828
829     if (This->source)
830         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
831             pbBuffer, This->src_format->format);
832     else
833         return WINCODEC_ERR_NOTINITIALIZED;
834 }
835
836 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
837     IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
838     IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
839 {
840     FormatConverter *This = (FormatConverter*)iface;
841     const struct pixelformatinfo *srcinfo, *dstinfo;
842     static INT fixme=0;
843     GUID srcFormat;
844     HRESULT res;
845
846     TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
847         dither, pIPalette, alphaThresholdPercent, paletteTranslate);
848
849     if (pIPalette && !fixme++) FIXME("ignoring palette\n");
850
851     if (This->source) return WINCODEC_ERR_WRONGSTATE;
852
853     res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
854     if (FAILED(res)) return res;
855
856     srcinfo = get_formatinfo(&srcFormat);
857     if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
858
859     dstinfo = get_formatinfo(dstFormat);
860     if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
861
862     if (dstinfo->copy_function)
863     {
864         IWICBitmapSource_AddRef(pISource);
865         This->source = pISource;
866         This->src_format = srcinfo;
867         This->dst_format = dstinfo;
868         This->dither = dither;
869         This->alpha_threshold = alphaThresholdPercent;
870         This->palette_type = paletteTranslate;
871     }
872     else
873         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
874
875     return S_OK;
876 }
877
878 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
879     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
880     BOOL *pfCanConvert)
881 {
882     FormatConverter *This = (FormatConverter*)iface;
883     const struct pixelformatinfo *srcinfo, *dstinfo;
884
885     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
886         debugstr_guid(dstPixelFormat), pfCanConvert);
887
888     srcinfo = get_formatinfo(srcPixelFormat);
889     if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
890
891     dstinfo = get_formatinfo(dstPixelFormat);
892     if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
893
894     if (dstinfo->copy_function &&
895         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
896         *pfCanConvert = TRUE;
897     else
898         *pfCanConvert = FALSE;
899
900     return S_OK;
901 }
902
903 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
904     FormatConverter_QueryInterface,
905     FormatConverter_AddRef,
906     FormatConverter_Release,
907     FormatConverter_GetSize,
908     FormatConverter_GetPixelFormat,
909     FormatConverter_GetResolution,
910     FormatConverter_CopyPalette,
911     FormatConverter_CopyPixels,
912     FormatConverter_Initialize,
913     FormatConverter_CanConvert
914 };
915
916 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
917 {
918     FormatConverter *This;
919     HRESULT ret;
920
921     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
922
923     *ppv = NULL;
924
925     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
926
927     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
928     if (!This) return E_OUTOFMEMORY;
929
930     This->lpVtbl = &FormatConverter_Vtbl;
931     This->ref = 1;
932     This->source = NULL;
933
934     ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
935     IUnknown_Release((IUnknown*)This);
936
937     return ret;
938 }