xref: /reactos/dll/win32/windowscodecs/converter.c (revision d8c6ef5e)
1 /*
2  * Copyright 2009 Vincent Povirk
3  * Copyright 2016 Dmitry Timoshkov
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "config.h"
21 
22 #include <stdarg.h>
23 #include <math.h>
24 
25 #define COBJMACROS
26 
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
30 
31 #include "wincodecs_private.h"
32 
33 #include "wine/heap.h"
34 #include "wine/debug.h"
35 
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37 
38 struct FormatConverter;
39 
40 enum pixelformat {
41     format_1bppIndexed,
42     format_2bppIndexed,
43     format_4bppIndexed,
44     format_8bppIndexed,
45     format_BlackWhite,
46     format_2bppGray,
47     format_4bppGray,
48     format_8bppGray,
49     format_16bppGray,
50     format_16bppBGR555,
51     format_16bppBGR565,
52     format_16bppBGRA5551,
53     format_24bppBGR,
54     format_24bppRGB,
55     format_32bppGrayFloat,
56     format_32bppBGR,
57     format_32bppRGB,
58     format_32bppBGRA,
59     format_32bppRGBA,
60     format_32bppPBGRA,
61     format_32bppPRGBA,
62     format_48bppRGB,
63     format_64bppRGBA,
64     format_32bppCMYK,
65 };
66 
67 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
68     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
69 
70 struct pixelformatinfo {
71     enum pixelformat format;
72     const WICPixelFormatGUID *guid;
73     copyfunc copy_function;
74 };
75 
76 typedef struct FormatConverter {
77     IWICFormatConverter IWICFormatConverter_iface;
78     LONG ref;
79     IWICBitmapSource *source;
80     const struct pixelformatinfo *dst_format, *src_format;
81     WICBitmapDitherType dither;
82     double alpha_threshold;
83     IWICPalette *palette;
84     CRITICAL_SECTION lock; /* must be held when initialized */
85 } FormatConverter;
86 
87 /* https://www.w3.org/Graphics/Color/srgb */
88 static inline float to_sRGB_component(float f)
89 {
90     if (f <= 0.0031308f) return 12.92f * f;
91     return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
92 }
93 
94 #if 0 /* FIXME: enable once needed */
95 static inline float from_sRGB_component(float f)
96 {
97     if (f <= 0.04045f) return f / 12.92f;
98     return powf((f + 0.055f) / 1.055f, 2.4f);
99 }
100 
101 static void from_sRGB(BYTE *bgr)
102 {
103     float r, g, b;
104 
105     r = bgr[2] / 255.0f;
106     g = bgr[1] / 255.0f;
107     b = bgr[0] / 255.0f;
108 
109     r = from_sRGB_component(r);
110     g = from_sRGB_component(g);
111     b = from_sRGB_component(b);
112 
113     bgr[2] = (BYTE)(r * 255.0f);
114     bgr[1] = (BYTE)(g * 255.0f);
115     bgr[0] = (BYTE)(b * 255.0f);
116 }
117 
118 static void to_sRGB(BYTE *bgr)
119 {
120     float r, g, b;
121 
122     r = bgr[2] / 255.0f;
123     g = bgr[1] / 255.0f;
124     b = bgr[0] / 255.0f;
125 
126     r = to_sRGB_component(r);
127     g = to_sRGB_component(g);
128     b = to_sRGB_component(b);
129 
130     bgr[2] = (BYTE)(r * 255.0f);
131     bgr[1] = (BYTE)(g * 255.0f);
132     bgr[0] = (BYTE)(b * 255.0f);
133 }
134 #endif
135 
136 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
137 {
138     return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
139 }
140 
141 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
142     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
143 {
144     switch (source_format)
145     {
146     case format_1bppIndexed:
147     case format_BlackWhite:
148         if (prc)
149         {
150             HRESULT res;
151             INT x, y;
152             BYTE *srcdata;
153             UINT srcstride, srcdatasize;
154             const BYTE *srcrow;
155             const BYTE *srcbyte;
156             BYTE *dstrow;
157             DWORD *dstpixel;
158             WICColor colors[2];
159             IWICPalette *palette;
160             UINT actualcolors;
161 
162             res = PaletteImpl_Create(&palette);
163             if (FAILED(res)) return res;
164 
165             if (source_format == format_1bppIndexed)
166                 res = IWICBitmapSource_CopyPalette(This->source, palette);
167             else
168                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
169 
170             if (SUCCEEDED(res))
171                 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
172 
173             IWICPalette_Release(palette);
174             if (FAILED(res)) return res;
175 
176             srcstride = (prc->Width+7)/8;
177             srcdatasize = srcstride * prc->Height;
178 
179             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
180             if (!srcdata) return E_OUTOFMEMORY;
181 
182             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
183 
184             if (SUCCEEDED(res))
185             {
186                 srcrow = srcdata;
187                 dstrow = pbBuffer;
188                 for (y=0; y<prc->Height; y++) {
189                     srcbyte = srcrow;
190                     dstpixel=(DWORD*)dstrow;
191                     for (x=0; x<prc->Width; x+=8) {
192                         BYTE srcval;
193                         srcval=*srcbyte++;
194                         *dstpixel++ = colors[srcval>>7&1];
195                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
196                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
197                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
198                         if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
199                         if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
200                         if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
201                         if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
202                     }
203                     srcrow += srcstride;
204                     dstrow += cbStride;
205                 }
206             }
207 
208             HeapFree(GetProcessHeap(), 0, srcdata);
209 
210             return res;
211         }
212         return S_OK;
213     case format_2bppIndexed:
214     case format_2bppGray:
215         if (prc)
216         {
217             HRESULT res;
218             INT x, y;
219             BYTE *srcdata;
220             UINT srcstride, srcdatasize;
221             const BYTE *srcrow;
222             const BYTE *srcbyte;
223             BYTE *dstrow;
224             DWORD *dstpixel;
225             WICColor colors[4];
226             IWICPalette *palette;
227             UINT actualcolors;
228 
229             res = PaletteImpl_Create(&palette);
230             if (FAILED(res)) return res;
231 
232             if (source_format == format_2bppIndexed)
233                 res = IWICBitmapSource_CopyPalette(This->source, palette);
234             else
235                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
236 
237             if (SUCCEEDED(res))
238                 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
239 
240             IWICPalette_Release(palette);
241             if (FAILED(res)) return res;
242 
243             srcstride = (prc->Width+3)/4;
244             srcdatasize = srcstride * prc->Height;
245 
246             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
247             if (!srcdata) return E_OUTOFMEMORY;
248 
249             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
250 
251             if (SUCCEEDED(res))
252             {
253                 srcrow = srcdata;
254                 dstrow = pbBuffer;
255                 for (y=0; y<prc->Height; y++) {
256                     srcbyte = srcrow;
257                     dstpixel=(DWORD*)dstrow;
258                     for (x=0; x<prc->Width; x+=4) {
259                         BYTE srcval;
260                         srcval=*srcbyte++;
261                         *dstpixel++ = colors[srcval>>6];
262                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
263                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
264                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
265                     }
266                     srcrow += srcstride;
267                     dstrow += cbStride;
268                 }
269             }
270 
271             HeapFree(GetProcessHeap(), 0, srcdata);
272 
273             return res;
274         }
275         return S_OK;
276     case format_4bppIndexed:
277     case format_4bppGray:
278         if (prc)
279         {
280             HRESULT res;
281             INT x, y;
282             BYTE *srcdata;
283             UINT srcstride, srcdatasize;
284             const BYTE *srcrow;
285             const BYTE *srcbyte;
286             BYTE *dstrow;
287             DWORD *dstpixel;
288             WICColor colors[16];
289             IWICPalette *palette;
290             UINT actualcolors;
291 
292             res = PaletteImpl_Create(&palette);
293             if (FAILED(res)) return res;
294 
295             if (source_format == format_4bppIndexed)
296                 res = IWICBitmapSource_CopyPalette(This->source, palette);
297             else
298                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
299 
300             if (SUCCEEDED(res))
301                 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
302 
303             IWICPalette_Release(palette);
304             if (FAILED(res)) return res;
305 
306             srcstride = (prc->Width+1)/2;
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 = srcrow;
320                     dstpixel=(DWORD*)dstrow;
321                     for (x=0; x<prc->Width; x+=2) {
322                         BYTE srcval;
323                         srcval=*srcbyte++;
324                         *dstpixel++ = colors[srcval>>4];
325                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
326                     }
327                     srcrow += srcstride;
328                     dstrow += cbStride;
329                 }
330             }
331 
332             HeapFree(GetProcessHeap(), 0, srcdata);
333 
334             return res;
335         }
336         return S_OK;
337     case format_8bppGray:
338         if (prc)
339         {
340             HRESULT res;
341             INT x, y;
342             BYTE *srcdata;
343             UINT srcstride, srcdatasize;
344             const BYTE *srcrow;
345             const BYTE *srcbyte;
346             BYTE *dstrow;
347             DWORD *dstpixel;
348 
349             srcstride = prc->Width;
350             srcdatasize = srcstride * prc->Height;
351 
352             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
353             if (!srcdata) return E_OUTOFMEMORY;
354 
355             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
356 
357             if (SUCCEEDED(res))
358             {
359                 srcrow = srcdata;
360                 dstrow = pbBuffer;
361                 for (y=0; y<prc->Height; y++) {
362                     srcbyte = srcrow;
363                     dstpixel=(DWORD*)dstrow;
364                     for (x=0; x<prc->Width; x++)
365                     {
366                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
367                         srcbyte++;
368                     }
369                     srcrow += srcstride;
370                     dstrow += cbStride;
371                 }
372             }
373 
374             HeapFree(GetProcessHeap(), 0, srcdata);
375 
376             return res;
377         }
378         return S_OK;
379     case format_8bppIndexed:
380         if (prc)
381         {
382             HRESULT res;
383             INT x, y;
384             BYTE *srcdata;
385             UINT srcstride, srcdatasize;
386             const BYTE *srcrow;
387             const BYTE *srcbyte;
388             BYTE *dstrow;
389             DWORD *dstpixel;
390             WICColor colors[256];
391             IWICPalette *palette;
392             UINT actualcolors;
393 
394             res = PaletteImpl_Create(&palette);
395             if (FAILED(res)) return res;
396 
397             res = IWICBitmapSource_CopyPalette(This->source, palette);
398             if (SUCCEEDED(res))
399                 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
400 
401             IWICPalette_Release(palette);
402 
403             if (FAILED(res)) return res;
404 
405             srcstride = prc->Width;
406             srcdatasize = srcstride * prc->Height;
407 
408             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
409             if (!srcdata) return E_OUTOFMEMORY;
410 
411             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
412 
413             if (SUCCEEDED(res))
414             {
415                 srcrow = srcdata;
416                 dstrow = pbBuffer;
417                 for (y=0; y<prc->Height; y++) {
418                     srcbyte = srcrow;
419                     dstpixel=(DWORD*)dstrow;
420                     for (x=0; x<prc->Width; x++)
421                         *dstpixel++ = colors[*srcbyte++];
422                     srcrow += srcstride;
423                     dstrow += cbStride;
424                 }
425             }
426 
427             HeapFree(GetProcessHeap(), 0, srcdata);
428 
429             return res;
430         }
431         return S_OK;
432     case format_16bppGray:
433         if (prc)
434         {
435             HRESULT res;
436             INT x, y;
437             BYTE *srcdata;
438             UINT srcstride, srcdatasize;
439             const BYTE *srcrow;
440             const BYTE *srcbyte;
441             BYTE *dstrow;
442             DWORD *dstpixel;
443 
444             srcstride = prc->Width * 2;
445             srcdatasize = srcstride * prc->Height;
446 
447             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
448             if (!srcdata) return E_OUTOFMEMORY;
449 
450             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
451 
452             if (SUCCEEDED(res))
453             {
454                 srcrow = srcdata;
455                 dstrow = pbBuffer;
456                 for (y=0; y<prc->Height; y++) {
457                     srcbyte = srcrow;
458                     dstpixel=(DWORD*)dstrow;
459                     for (x=0; x<prc->Width; x++)
460                     {
461                         srcbyte++;
462                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
463                         srcbyte++;
464                     }
465                     srcrow += srcstride;
466                     dstrow += cbStride;
467                 }
468             }
469 
470             HeapFree(GetProcessHeap(), 0, srcdata);
471 
472             return res;
473         }
474         return S_OK;
475     case format_16bppBGR555:
476         if (prc)
477         {
478             HRESULT res;
479             INT x, y;
480             BYTE *srcdata;
481             UINT srcstride, srcdatasize;
482             const BYTE *srcrow;
483             const WORD *srcpixel;
484             BYTE *dstrow;
485             DWORD *dstpixel;
486 
487             srcstride = 2 * prc->Width;
488             srcdatasize = srcstride * prc->Height;
489 
490             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
491             if (!srcdata) return E_OUTOFMEMORY;
492 
493             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
494 
495             if (SUCCEEDED(res))
496             {
497                 srcrow = srcdata;
498                 dstrow = pbBuffer;
499                 for (y=0; y<prc->Height; y++) {
500                     srcpixel=(const WORD*)srcrow;
501                     dstpixel=(DWORD*)dstrow;
502                     for (x=0; x<prc->Width; x++) {
503                         WORD srcval;
504                         srcval=*srcpixel++;
505                         *dstpixel++=0xff000000 | /* constant 255 alpha */
506                                     ((srcval << 9) & 0xf80000) | /* r */
507                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
508                                     ((srcval << 6) & 0x00f800) | /* g */
509                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
510                                     ((srcval << 3) & 0x0000f8) | /* b */
511                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
512                     }
513                     srcrow += srcstride;
514                     dstrow += cbStride;
515                 }
516             }
517 
518             HeapFree(GetProcessHeap(), 0, srcdata);
519 
520             return res;
521         }
522         return S_OK;
523     case format_16bppBGR565:
524         if (prc)
525         {
526             HRESULT res;
527             INT x, y;
528             BYTE *srcdata;
529             UINT srcstride, srcdatasize;
530             const BYTE *srcrow;
531             const WORD *srcpixel;
532             BYTE *dstrow;
533             DWORD *dstpixel;
534 
535             srcstride = 2 * prc->Width;
536             srcdatasize = srcstride * prc->Height;
537 
538             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
539             if (!srcdata) return E_OUTOFMEMORY;
540 
541             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
542 
543             if (SUCCEEDED(res))
544             {
545                 srcrow = srcdata;
546                 dstrow = pbBuffer;
547                 for (y=0; y<prc->Height; y++) {
548                     srcpixel=(const WORD*)srcrow;
549                     dstpixel=(DWORD*)dstrow;
550                     for (x=0; x<prc->Width; x++) {
551                         WORD srcval;
552                         srcval=*srcpixel++;
553                         *dstpixel++=0xff000000 | /* constant 255 alpha */
554                                     ((srcval << 8) & 0xf80000) | /* r */
555                                     ((srcval << 3) & 0x070000) | /* r - 3 bits */
556                                     ((srcval << 5) & 0x00fc00) | /* g */
557                                     ((srcval >> 1) & 0x000300) | /* g - 2 bits */
558                                     ((srcval << 3) & 0x0000f8) | /* b */
559                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
560                     }
561                     srcrow += srcstride;
562                     dstrow += cbStride;
563                 }
564             }
565 
566             HeapFree(GetProcessHeap(), 0, srcdata);
567 
568             return res;
569         }
570         return S_OK;
571     case format_16bppBGRA5551:
572         if (prc)
573         {
574             HRESULT res;
575             INT x, y;
576             BYTE *srcdata;
577             UINT srcstride, srcdatasize;
578             const BYTE *srcrow;
579             const WORD *srcpixel;
580             BYTE *dstrow;
581             DWORD *dstpixel;
582 
583             srcstride = 2 * prc->Width;
584             srcdatasize = srcstride * prc->Height;
585 
586             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
587             if (!srcdata) return E_OUTOFMEMORY;
588 
589             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
590 
591             if (SUCCEEDED(res))
592             {
593                 srcrow = srcdata;
594                 dstrow = pbBuffer;
595                 for (y=0; y<prc->Height; y++) {
596                     srcpixel=(const WORD*)srcrow;
597                     dstpixel=(DWORD*)dstrow;
598                     for (x=0; x<prc->Width; x++) {
599                         WORD srcval;
600                         srcval=*srcpixel++;
601                         *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
602                                     ((srcval << 9) & 0xf80000) | /* r */
603                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
604                                     ((srcval << 6) & 0x00f800) | /* g */
605                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
606                                     ((srcval << 3) & 0x0000f8) | /* b */
607                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
608                     }
609                     srcrow += srcstride;
610                     dstrow += cbStride;
611                 }
612             }
613 
614             HeapFree(GetProcessHeap(), 0, srcdata);
615 
616             return res;
617         }
618         return S_OK;
619     case format_24bppBGR:
620         if (prc)
621         {
622             HRESULT res;
623             INT x, y;
624             BYTE *srcdata;
625             UINT srcstride, srcdatasize;
626             const BYTE *srcrow;
627             const BYTE *srcpixel;
628             BYTE *dstrow;
629             BYTE *dstpixel;
630 
631             srcstride = 3 * prc->Width;
632             srcdatasize = srcstride * prc->Height;
633 
634             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
635             if (!srcdata) return E_OUTOFMEMORY;
636 
637             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
638 
639             if (SUCCEEDED(res))
640             {
641                 srcrow = srcdata;
642                 dstrow = pbBuffer;
643                 for (y=0; y<prc->Height; y++) {
644                     srcpixel=srcrow;
645                     dstpixel=dstrow;
646                     for (x=0; x<prc->Width; x++) {
647                         *dstpixel++=*srcpixel++; /* blue */
648                         *dstpixel++=*srcpixel++; /* green */
649                         *dstpixel++=*srcpixel++; /* red */
650                         *dstpixel++=255; /* alpha */
651                     }
652                     srcrow += srcstride;
653                     dstrow += cbStride;
654                 }
655             }
656 
657             HeapFree(GetProcessHeap(), 0, srcdata);
658 
659             return res;
660         }
661         return S_OK;
662     case format_24bppRGB:
663         if (prc)
664         {
665             HRESULT res;
666             INT x, y;
667             BYTE *srcdata;
668             UINT srcstride, srcdatasize;
669             const BYTE *srcrow;
670             const BYTE *srcpixel;
671             BYTE *dstrow;
672             BYTE *dstpixel;
673             BYTE tmppixel[3];
674 
675             srcstride = 3 * prc->Width;
676             srcdatasize = srcstride * prc->Height;
677 
678             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
679             if (!srcdata) return E_OUTOFMEMORY;
680 
681             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
682 
683             if (SUCCEEDED(res))
684             {
685                 srcrow = srcdata;
686                 dstrow = pbBuffer;
687                 for (y=0; y<prc->Height; y++) {
688                     srcpixel=srcrow;
689                     dstpixel=dstrow;
690                     for (x=0; x<prc->Width; x++) {
691                         tmppixel[0]=*srcpixel++; /* red */
692                         tmppixel[1]=*srcpixel++; /* green */
693                         tmppixel[2]=*srcpixel++; /* blue */
694 
695                         *dstpixel++=tmppixel[2]; /* blue */
696                         *dstpixel++=tmppixel[1]; /* green */
697                         *dstpixel++=tmppixel[0]; /* red */
698                         *dstpixel++=255; /* alpha */
699                     }
700                     srcrow += srcstride;
701                     dstrow += cbStride;
702                 }
703             }
704 
705             HeapFree(GetProcessHeap(), 0, srcdata);
706 
707             return res;
708         }
709         return S_OK;
710     case format_32bppBGR:
711         if (prc)
712         {
713             HRESULT res;
714             INT x, y;
715 
716             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
717             if (FAILED(res)) return res;
718 
719             /* set all alpha values to 255 */
720             for (y=0; y<prc->Height; y++)
721                 for (x=0; x<prc->Width; x++)
722                     pbBuffer[cbStride*y+4*x+3] = 0xff;
723         }
724         return S_OK;
725     case format_32bppBGRA:
726         if (prc)
727             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
728         return S_OK;
729     case format_32bppPBGRA:
730         if (prc)
731         {
732             HRESULT res;
733             INT x, y;
734 
735             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
736             if (FAILED(res)) return res;
737 
738             for (y=0; y<prc->Height; y++)
739                 for (x=0; x<prc->Width; x++)
740                 {
741                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
742                     if (alpha != 0 && alpha != 255)
743                     {
744                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
745                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
746                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
747                     }
748                 }
749         }
750         return S_OK;
751     case format_48bppRGB:
752         if (prc)
753         {
754             HRESULT res;
755             INT x, y;
756             BYTE *srcdata;
757             UINT srcstride, srcdatasize;
758             const BYTE *srcrow;
759             const BYTE *srcpixel;
760             BYTE *dstrow;
761             DWORD *dstpixel;
762 
763             srcstride = 6 * prc->Width;
764             srcdatasize = srcstride * prc->Height;
765 
766             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
767             if (!srcdata) return E_OUTOFMEMORY;
768 
769             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
770 
771             if (SUCCEEDED(res))
772             {
773                 srcrow = srcdata;
774                 dstrow = pbBuffer;
775                 for (y=0; y<prc->Height; y++) {
776                     srcpixel=srcrow;
777                     dstpixel=(DWORD*)dstrow;
778                     for (x=0; x<prc->Width; x++) {
779                         BYTE red, green, blue;
780                         srcpixel++; red = *srcpixel++;
781                         srcpixel++; green = *srcpixel++;
782                         srcpixel++; blue = *srcpixel++;
783                         *dstpixel++=0xff000000|red<<16|green<<8|blue;
784                     }
785                     srcrow += srcstride;
786                     dstrow += cbStride;
787                 }
788             }
789 
790             HeapFree(GetProcessHeap(), 0, srcdata);
791 
792             return res;
793         }
794         return S_OK;
795     case format_64bppRGBA:
796         if (prc)
797         {
798             HRESULT res;
799             INT x, y;
800             BYTE *srcdata;
801             UINT srcstride, srcdatasize;
802             const BYTE *srcrow;
803             const BYTE *srcpixel;
804             BYTE *dstrow;
805             DWORD *dstpixel;
806 
807             srcstride = 8 * prc->Width;
808             srcdatasize = srcstride * prc->Height;
809 
810             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
811             if (!srcdata) return E_OUTOFMEMORY;
812 
813             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
814 
815             if (SUCCEEDED(res))
816             {
817                 srcrow = srcdata;
818                 dstrow = pbBuffer;
819                 for (y=0; y<prc->Height; y++) {
820                     srcpixel=srcrow;
821                     dstpixel=(DWORD*)dstrow;
822                     for (x=0; x<prc->Width; x++) {
823                         BYTE red, green, blue, alpha;
824                         srcpixel++; red = *srcpixel++;
825                         srcpixel++; green = *srcpixel++;
826                         srcpixel++; blue = *srcpixel++;
827                         srcpixel++; alpha = *srcpixel++;
828                         *dstpixel++=alpha<<24|red<<16|green<<8|blue;
829                     }
830                     srcrow += srcstride;
831                     dstrow += cbStride;
832                 }
833             }
834 
835             HeapFree(GetProcessHeap(), 0, srcdata);
836 
837             return res;
838         }
839         return S_OK;
840     case format_32bppCMYK:
841         if (prc)
842         {
843             HRESULT res;
844             UINT x, y;
845 
846             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
847             if (FAILED(res)) return res;
848 
849             for (y=0; y<prc->Height; y++)
850                 for (x=0; x<prc->Width; x++)
851                 {
852                     BYTE *pixel = pbBuffer+cbStride*y+4*x;
853                     BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
854                     pixel[0] = (255-y)*(255-k)/255; /* blue */
855                     pixel[1] = (255-m)*(255-k)/255; /* green */
856                     pixel[2] = (255-c)*(255-k)/255; /* red */
857                     pixel[3] = 255; /* alpha */
858                 }
859         }
860         return S_OK;
861     default:
862         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
863     }
864 }
865 
866 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
867     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
868 {
869     HRESULT hr;
870 
871     switch (source_format)
872     {
873     case format_32bppRGB:
874         if (prc)
875         {
876             INT x, y;
877 
878             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
879             if (FAILED(hr)) return hr;
880 
881             /* set all alpha values to 255 */
882             for (y=0; y<prc->Height; y++)
883                 for (x=0; x<prc->Width; x++)
884                     pbBuffer[cbStride*y+4*x+3] = 0xff;
885         }
886         return S_OK;
887 
888     case format_32bppRGBA:
889         if (prc)
890             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
891         return S_OK;
892 
893     case format_32bppPRGBA:
894         if (prc)
895         {
896             INT x, y;
897 
898             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
899             if (FAILED(hr)) return hr;
900 
901             for (y=0; y<prc->Height; y++)
902                 for (x=0; x<prc->Width; x++)
903                 {
904                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
905                     if (alpha != 0 && alpha != 255)
906                     {
907                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
908                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
909                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
910                     }
911                 }
912         }
913         return S_OK;
914 
915     default:
916         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
917         if (SUCCEEDED(hr) && prc)
918               reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
919         return hr;
920     }
921 }
922 
923 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
924     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
925 {
926     switch (source_format)
927     {
928     case format_32bppBGR:
929     case format_32bppBGRA:
930     case format_32bppPBGRA:
931         if (prc)
932             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
933         return S_OK;
934     default:
935         return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
936     }
937 }
938 
939 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
940     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
941 {
942     switch (source_format)
943     {
944     case format_32bppRGB:
945     case format_32bppRGBA:
946     case format_32bppPRGBA:
947         if (prc)
948             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
949         return S_OK;
950     default:
951         return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
952     }
953 }
954 
955 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
956     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
957 {
958     HRESULT hr;
959 
960     switch (source_format)
961     {
962     case format_32bppPBGRA:
963         if (prc)
964             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
965         return S_OK;
966     default:
967         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
968         if (SUCCEEDED(hr) && prc)
969         {
970             INT x, y;
971 
972             for (y=0; y<prc->Height; y++)
973                 for (x=0; x<prc->Width; x++)
974                 {
975                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
976                     if (alpha != 255)
977                     {
978                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
979                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
980                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
981                     }
982                 }
983         }
984         return hr;
985     }
986 }
987 
988 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
989     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
990 {
991     HRESULT hr;
992 
993     switch (source_format)
994     {
995     case format_32bppPRGBA:
996         if (prc)
997             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
998         return S_OK;
999     default:
1000         hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1001         if (SUCCEEDED(hr) && prc)
1002         {
1003             INT x, y;
1004 
1005             for (y=0; y<prc->Height; y++)
1006                 for (x=0; x<prc->Width; x++)
1007                 {
1008                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1009                     if (alpha != 255)
1010                     {
1011                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
1012                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1013                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
1014                     }
1015                 }
1016         }
1017         return hr;
1018     }
1019 }
1020 
1021 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1022     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1023 {
1024     HRESULT hr;
1025 
1026     switch (source_format)
1027     {
1028     case format_24bppBGR:
1029     case format_24bppRGB:
1030         if (prc)
1031         {
1032             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1033             if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1034               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1035             return hr;
1036         }
1037         return S_OK;
1038     case format_32bppBGR:
1039     case format_32bppBGRA:
1040     case format_32bppPBGRA:
1041         if (prc)
1042         {
1043             HRESULT res;
1044             INT x, y;
1045             BYTE *srcdata;
1046             UINT srcstride, srcdatasize;
1047             const BYTE *srcrow;
1048             const BYTE *srcpixel;
1049             BYTE *dstrow;
1050             BYTE *dstpixel;
1051 
1052             srcstride = 4 * prc->Width;
1053             srcdatasize = srcstride * prc->Height;
1054 
1055             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1056             if (!srcdata) return E_OUTOFMEMORY;
1057 
1058             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1059 
1060             if (SUCCEEDED(res))
1061             {
1062                 srcrow = srcdata;
1063                 dstrow = pbBuffer;
1064                 for (y=0; y<prc->Height; y++) {
1065                     srcpixel=srcrow;
1066                     dstpixel=dstrow;
1067                     for (x=0; x<prc->Width; x++) {
1068                         *dstpixel++=*srcpixel++; /* blue */
1069                         *dstpixel++=*srcpixel++; /* green */
1070                         *dstpixel++=*srcpixel++; /* red */
1071                         srcpixel++; /* alpha */
1072                     }
1073                     srcrow += srcstride;
1074                     dstrow += cbStride;
1075                 }
1076             }
1077 
1078             HeapFree(GetProcessHeap(), 0, srcdata);
1079 
1080             return res;
1081         }
1082         return S_OK;
1083 
1084     case format_32bppGrayFloat:
1085         if (prc)
1086         {
1087             BYTE *srcdata;
1088             UINT srcstride, srcdatasize;
1089 
1090             srcstride = 4 * prc->Width;
1091             srcdatasize = srcstride * prc->Height;
1092 
1093             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1094             if (!srcdata) return E_OUTOFMEMORY;
1095 
1096             hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1097 
1098             if (SUCCEEDED(hr))
1099             {
1100                 INT x, y;
1101                 BYTE *src = srcdata, *dst = pbBuffer;
1102 
1103                 for (y = 0; y < prc->Height; y++)
1104                 {
1105                     float *gray_float = (float *)src;
1106                     BYTE *bgr = dst;
1107 
1108                     for (x = 0; x < prc->Width; x++)
1109                     {
1110                         BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1111                         *bgr++ = gray;
1112                         *bgr++ = gray;
1113                         *bgr++ = gray;
1114                     }
1115                     src += srcstride;
1116                     dst += cbStride;
1117                 }
1118             }
1119 
1120             HeapFree(GetProcessHeap(), 0, srcdata);
1121 
1122             return hr;
1123         }
1124         return S_OK;
1125 
1126     case format_32bppCMYK:
1127         if (prc)
1128         {
1129             BYTE *srcdata;
1130             UINT srcstride, srcdatasize;
1131 
1132             srcstride = 4 * prc->Width;
1133             srcdatasize = srcstride * prc->Height;
1134 
1135             srcdata = heap_alloc(srcdatasize);
1136             if (!srcdata) return E_OUTOFMEMORY;
1137 
1138             hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1139             if (SUCCEEDED(hr))
1140             {
1141                 INT x, y;
1142                 BYTE *src = srcdata, *dst = pbBuffer;
1143 
1144                 for (y = 0; y < prc->Height; y++)
1145                 {
1146                     BYTE *cmyk = src;
1147                     BYTE *bgr = dst;
1148 
1149                     for (x = 0; x < prc->Width; x++)
1150                     {
1151                         BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
1152                         bgr[0] = (255 - y) * (255 - k) / 255; /* B */
1153                         bgr[1] = (255 - m) * (255 - k) / 255; /* G */
1154                         bgr[2] = (255 - c) * (255 - k) / 255; /* R */
1155                         cmyk += 4;
1156                         bgr += 3;
1157                     }
1158                     src += srcstride;
1159                     dst += cbStride;
1160                 }
1161             }
1162 
1163             heap_free(srcdata);
1164             return hr;
1165         }
1166         return S_OK;
1167 
1168     default:
1169         FIXME("Unimplemented conversion path!\n");
1170         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1171     }
1172 }
1173 
1174 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1175     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1176 {
1177     HRESULT hr;
1178 
1179     switch (source_format)
1180     {
1181     case format_24bppBGR:
1182     case format_24bppRGB:
1183         if (prc)
1184         {
1185             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1186             if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1187               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1188             return hr;
1189         }
1190         return S_OK;
1191     case format_32bppBGR:
1192     case format_32bppBGRA:
1193     case format_32bppPBGRA:
1194         if (prc)
1195         {
1196             HRESULT res;
1197             INT x, y;
1198             BYTE *srcdata;
1199             UINT srcstride, srcdatasize;
1200             const BYTE *srcrow;
1201             const BYTE *srcpixel;
1202             BYTE *dstrow;
1203             BYTE *dstpixel;
1204             BYTE tmppixel[3];
1205 
1206             srcstride = 4 * prc->Width;
1207             srcdatasize = srcstride * prc->Height;
1208 
1209             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1210             if (!srcdata) return E_OUTOFMEMORY;
1211 
1212             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1213 
1214             if (SUCCEEDED(res))
1215             {
1216                 srcrow = srcdata;
1217                 dstrow = pbBuffer;
1218                 for (y=0; y<prc->Height; y++) {
1219                     srcpixel=srcrow;
1220                     dstpixel=dstrow;
1221                     for (x=0; x<prc->Width; x++) {
1222                         tmppixel[0]=*srcpixel++; /* blue */
1223                         tmppixel[1]=*srcpixel++; /* green */
1224                         tmppixel[2]=*srcpixel++; /* red */
1225                         srcpixel++; /* alpha */
1226 
1227                         *dstpixel++=tmppixel[2]; /* red */
1228                         *dstpixel++=tmppixel[1]; /* green */
1229                         *dstpixel++=tmppixel[0]; /* blue */
1230                     }
1231                     srcrow += srcstride;
1232                     dstrow += cbStride;
1233                 }
1234             }
1235 
1236             HeapFree(GetProcessHeap(), 0, srcdata);
1237 
1238             return res;
1239         }
1240         return S_OK;
1241     default:
1242         FIXME("Unimplemented conversion path!\n");
1243         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1244     }
1245 }
1246 
1247 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1248     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1249 {
1250     HRESULT hr;
1251 
1252     switch (source_format)
1253     {
1254     case format_32bppBGR:
1255     case format_32bppBGRA:
1256     case format_32bppPBGRA:
1257     case format_32bppGrayFloat:
1258         if (prc)
1259         {
1260             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1261             break;
1262         }
1263         return S_OK;
1264 
1265     default:
1266         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1267         break;
1268     }
1269 
1270     if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1271     {
1272         INT x, y;
1273         BYTE *p = pbBuffer;
1274 
1275         for (y = 0; y < prc->Height; y++)
1276         {
1277             BYTE *bgr = p;
1278             for (x = 0; x < prc->Width; x++)
1279             {
1280                 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1281                 *(float *)bgr = gray;
1282                 bgr += 4;
1283             }
1284             p += cbStride;
1285         }
1286     }
1287     return hr;
1288 }
1289 
1290 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1291     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1292 {
1293     HRESULT hr;
1294     BYTE *srcdata;
1295     UINT srcstride, srcdatasize;
1296 
1297     if (source_format == format_8bppGray)
1298     {
1299         if (prc)
1300             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1301 
1302         return S_OK;
1303     }
1304 
1305     if (source_format == format_32bppGrayFloat)
1306     {
1307         hr = S_OK;
1308 
1309         if (prc)
1310         {
1311             srcstride = 4 * prc->Width;
1312             srcdatasize = srcstride * prc->Height;
1313 
1314             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1315             if (!srcdata) return E_OUTOFMEMORY;
1316 
1317             hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1318             if (SUCCEEDED(hr))
1319             {
1320                 INT x, y;
1321                 BYTE *src = srcdata, *dst = pbBuffer;
1322 
1323                 for (y=0; y < prc->Height; y++)
1324                 {
1325                     float *srcpixel = (float*)src;
1326                     BYTE *dstpixel = dst;
1327 
1328                     for (x=0; x < prc->Width; x++)
1329                         *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1330 
1331                     src += srcstride;
1332                     dst += cbStride;
1333                 }
1334             }
1335 
1336             HeapFree(GetProcessHeap(), 0, srcdata);
1337         }
1338 
1339         return hr;
1340     }
1341 
1342     if (!prc)
1343         return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1344 
1345     srcstride = 3 * prc->Width;
1346     srcdatasize = srcstride * prc->Height;
1347 
1348     srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1349     if (!srcdata) return E_OUTOFMEMORY;
1350 
1351     hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1352     if (SUCCEEDED(hr))
1353     {
1354         INT x, y;
1355         BYTE *src = srcdata, *dst = pbBuffer;
1356 
1357         for (y = 0; y < prc->Height; y++)
1358         {
1359             BYTE *bgr = src;
1360 
1361             for (x = 0; x < prc->Width; x++)
1362             {
1363                 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1364 
1365                 gray = to_sRGB_component(gray) * 255.0f;
1366                 dst[x] = (BYTE)floorf(gray + 0.51f);
1367                 bgr += 3;
1368             }
1369             src += srcstride;
1370             dst += cbStride;
1371         }
1372     }
1373 
1374     HeapFree(GetProcessHeap(), 0, srcdata);
1375     return hr;
1376 }
1377 
1378 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1379 {
1380     UINT best_diff, best_index, i;
1381 
1382     best_diff = ~0;
1383     best_index = 0;
1384 
1385     for (i = 0; i < count; i++)
1386     {
1387         BYTE pal_r, pal_g, pal_b;
1388         UINT diff_r, diff_g, diff_b, diff;
1389 
1390         pal_r = colors[i] >> 16;
1391         pal_g = colors[i] >> 8;
1392         pal_b = colors[i];
1393 
1394         diff_r = bgr[2] - pal_r;
1395         diff_g = bgr[1] - pal_g;
1396         diff_b = bgr[0] - pal_b;
1397 
1398         diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1399         if (diff == 0) return i;
1400 
1401         if (diff < best_diff)
1402         {
1403             best_diff = diff;
1404             best_index = i;
1405         }
1406     }
1407 
1408     return best_index;
1409 }
1410 
1411 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1412     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1413 {
1414     HRESULT hr;
1415     BYTE *srcdata;
1416     WICColor colors[256];
1417     UINT srcstride, srcdatasize, count;
1418 
1419     if (source_format == format_8bppIndexed)
1420     {
1421         if (prc)
1422             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1423 
1424         return S_OK;
1425     }
1426 
1427     if (!prc)
1428         return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1429 
1430     if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1431 
1432     hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1433     if (hr != S_OK) return hr;
1434 
1435     srcstride = 3 * prc->Width;
1436     srcdatasize = srcstride * prc->Height;
1437 
1438     srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1439     if (!srcdata) return E_OUTOFMEMORY;
1440 
1441     hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1442     if (SUCCEEDED(hr))
1443     {
1444         INT x, y;
1445         BYTE *src = srcdata, *dst = pbBuffer;
1446 
1447         for (y = 0; y < prc->Height; y++)
1448         {
1449             BYTE *bgr = src;
1450 
1451             for (x = 0; x < prc->Width; x++)
1452             {
1453                 dst[x] = rgb_to_palette_index(bgr, colors, count);
1454                 bgr += 3;
1455             }
1456             src += srcstride;
1457             dst += cbStride;
1458         }
1459     }
1460 
1461     HeapFree(GetProcessHeap(), 0, srcdata);
1462     return hr;
1463 }
1464 
1465 static const struct pixelformatinfo supported_formats[] = {
1466     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1467     {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1468     {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1469     {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1470     {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1471     {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1472     {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1473     {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1474     {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1475     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1476     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1477     {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1478     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1479     {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1480     {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1481     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1482     {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1483     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1484     {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1485     {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1486     {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1487     {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1488     {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1489     {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1490     {0}
1491 };
1492 
1493 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1494 {
1495     UINT i;
1496 
1497     for (i=0; supported_formats[i].guid; i++)
1498         if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1499 
1500     return NULL;
1501 }
1502 
1503 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1504     void **ppv)
1505 {
1506     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1507     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1508 
1509     if (!ppv) return E_INVALIDARG;
1510 
1511     if (IsEqualIID(&IID_IUnknown, iid) ||
1512         IsEqualIID(&IID_IWICBitmapSource, iid) ||
1513         IsEqualIID(&IID_IWICFormatConverter, iid))
1514     {
1515         *ppv = &This->IWICFormatConverter_iface;
1516     }
1517     else
1518     {
1519         *ppv = NULL;
1520         return E_NOINTERFACE;
1521     }
1522 
1523     IUnknown_AddRef((IUnknown*)*ppv);
1524     return S_OK;
1525 }
1526 
1527 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1528 {
1529     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1530     ULONG ref = InterlockedIncrement(&This->ref);
1531 
1532     TRACE("(%p) refcount=%u\n", iface, ref);
1533 
1534     return ref;
1535 }
1536 
1537 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1538 {
1539     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1540     ULONG ref = InterlockedDecrement(&This->ref);
1541 
1542     TRACE("(%p) refcount=%u\n", iface, ref);
1543 
1544     if (ref == 0)
1545     {
1546         This->lock.DebugInfo->Spare[0] = 0;
1547         DeleteCriticalSection(&This->lock);
1548         if (This->source) IWICBitmapSource_Release(This->source);
1549         if (This->palette) IWICPalette_Release(This->palette);
1550         HeapFree(GetProcessHeap(), 0, This);
1551     }
1552 
1553     return ref;
1554 }
1555 
1556 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1557     UINT *puiWidth, UINT *puiHeight)
1558 {
1559     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1560 
1561     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1562 
1563     if (This->source)
1564         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1565     else
1566         return WINCODEC_ERR_NOTINITIALIZED;
1567 }
1568 
1569 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1570     WICPixelFormatGUID *pPixelFormat)
1571 {
1572     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1573 
1574     TRACE("(%p,%p)\n", iface, pPixelFormat);
1575 
1576     if (This->source)
1577         memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1578     else
1579         return WINCODEC_ERR_NOTINITIALIZED;
1580 
1581     return S_OK;
1582 }
1583 
1584 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1585     double *pDpiX, double *pDpiY)
1586 {
1587     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1588 
1589     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1590 
1591     if (This->source)
1592         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1593     else
1594         return WINCODEC_ERR_NOTINITIALIZED;
1595 }
1596 
1597 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1598     IWICPalette *palette)
1599 {
1600     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1601 
1602     TRACE("(%p,%p)\n", iface, palette);
1603 
1604     if (!palette) return E_INVALIDARG;
1605     if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1606 
1607     if (!This->palette)
1608     {
1609         HRESULT hr;
1610         UINT bpp;
1611 
1612         hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1613         if (hr != S_OK) return hr;
1614         if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1615         return IWICBitmapSource_CopyPalette(This->source, palette);
1616     }
1617 
1618     return IWICPalette_InitializeFromPalette(palette, This->palette);
1619 }
1620 
1621 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1622     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1623 {
1624     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1625     WICRect rc;
1626     HRESULT hr;
1627     TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1628 
1629     if (This->source)
1630     {
1631         if (!prc)
1632         {
1633             UINT width, height;
1634             hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1635             if (FAILED(hr)) return hr;
1636             rc.X = 0;
1637             rc.Y = 0;
1638             rc.Width = width;
1639             rc.Height = height;
1640             prc = &rc;
1641         }
1642 
1643         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1644             pbBuffer, This->src_format->format);
1645     }
1646     else
1647         return WINCODEC_ERR_WRONGSTATE;
1648 }
1649 
1650 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1651     IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1652     IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1653 {
1654     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1655     const struct pixelformatinfo *srcinfo, *dstinfo;
1656     GUID srcFormat;
1657     HRESULT res;
1658 
1659     TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1660         dither, palette, alpha_threshold, palette_type);
1661 
1662     if (!palette)
1663     {
1664         UINT bpp;
1665         res = get_pixelformat_bpp(dstFormat, &bpp);
1666         if (res != S_OK) return res;
1667 
1668         res = PaletteImpl_Create(&palette);
1669         if (res != S_OK) return res;
1670 
1671         switch (palette_type)
1672         {
1673         case WICBitmapPaletteTypeCustom:
1674             IWICPalette_Release(palette);
1675             palette = NULL;
1676             if (bpp <= 8) return E_INVALIDARG;
1677             break;
1678 
1679         case WICBitmapPaletteTypeMedianCut:
1680         {
1681             if (bpp <= 8)
1682                 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1683             break;
1684         }
1685 
1686         default:
1687             if (bpp <= 8)
1688                 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1689             break;
1690         }
1691 
1692         if (res != S_OK)
1693         {
1694             IWICPalette_Release(palette);
1695             return res;
1696         }
1697     }
1698     else
1699         IWICPalette_AddRef(palette);
1700 
1701     EnterCriticalSection(&This->lock);
1702 
1703     if (This->source)
1704     {
1705         res = WINCODEC_ERR_WRONGSTATE;
1706         goto end;
1707     }
1708 
1709     res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1710     if (FAILED(res)) goto end;
1711 
1712     srcinfo = get_formatinfo(&srcFormat);
1713     if (!srcinfo)
1714     {
1715         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1716         FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1717         goto end;
1718     }
1719 
1720     dstinfo = get_formatinfo(dstFormat);
1721     if (!dstinfo)
1722     {
1723         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1724         FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1725         goto end;
1726     }
1727 
1728     if (dstinfo->copy_function)
1729     {
1730         IWICBitmapSource_AddRef(source);
1731         This->src_format = srcinfo;
1732         This->dst_format = dstinfo;
1733         This->dither = dither;
1734         This->alpha_threshold = alpha_threshold;
1735         This->palette = palette;
1736         This->source = source;
1737     }
1738     else
1739     {
1740         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1741         res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1742     }
1743 
1744 end:
1745 
1746     LeaveCriticalSection(&This->lock);
1747 
1748     if (res != S_OK && palette)
1749         IWICPalette_Release(palette);
1750 
1751     return res;
1752 }
1753 
1754 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1755     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1756     BOOL *pfCanConvert)
1757 {
1758     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1759     const struct pixelformatinfo *srcinfo, *dstinfo;
1760 
1761     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1762         debugstr_guid(dstPixelFormat), pfCanConvert);
1763 
1764     srcinfo = get_formatinfo(srcPixelFormat);
1765     if (!srcinfo)
1766     {
1767         FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1768         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1769     }
1770 
1771     dstinfo = get_formatinfo(dstPixelFormat);
1772     if (!dstinfo)
1773     {
1774         FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1775         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1776     }
1777 
1778     if (dstinfo->copy_function &&
1779         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1780         *pfCanConvert = TRUE;
1781     else
1782     {
1783         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1784         *pfCanConvert = FALSE;
1785     }
1786 
1787     return S_OK;
1788 }
1789 
1790 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1791     FormatConverter_QueryInterface,
1792     FormatConverter_AddRef,
1793     FormatConverter_Release,
1794     FormatConverter_GetSize,
1795     FormatConverter_GetPixelFormat,
1796     FormatConverter_GetResolution,
1797     FormatConverter_CopyPalette,
1798     FormatConverter_CopyPixels,
1799     FormatConverter_Initialize,
1800     FormatConverter_CanConvert
1801 };
1802 
1803 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1804 {
1805     FormatConverter *This;
1806     HRESULT ret;
1807 
1808     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1809 
1810     *ppv = NULL;
1811 
1812     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1813     if (!This) return E_OUTOFMEMORY;
1814 
1815     This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1816     This->ref = 1;
1817     This->source = NULL;
1818     This->palette = NULL;
1819     InitializeCriticalSection(&This->lock);
1820     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1821 
1822     ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1823     IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1824 
1825     return ret;
1826 }
1827