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