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