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