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