xref: /reactos/dll/win32/windowscodecs/converter.c (revision 48cc7814)
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/debug.h"
34 
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 
37 struct FormatConverter;
38 
39 enum pixelformat {
40     format_1bppIndexed,
41     format_2bppIndexed,
42     format_4bppIndexed,
43     format_8bppIndexed,
44     format_BlackWhite,
45     format_2bppGray,
46     format_4bppGray,
47     format_8bppGray,
48     format_16bppGray,
49     format_16bppBGR555,
50     format_16bppBGR565,
51     format_16bppBGRA5551,
52     format_24bppBGR,
53     format_24bppRGB,
54     format_32bppGrayFloat,
55     format_32bppBGR,
56     format_32bppRGB,
57     format_32bppBGRA,
58     format_32bppRGBA,
59     format_32bppPBGRA,
60     format_32bppPRGBA,
61     format_48bppRGB,
62     format_64bppRGBA,
63     format_32bppCMYK,
64 };
65 
66 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
67     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
68 
69 struct pixelformatinfo {
70     enum pixelformat format;
71     const WICPixelFormatGUID *guid;
72     copyfunc copy_function;
73 };
74 
75 typedef struct FormatConverter {
76     IWICFormatConverter IWICFormatConverter_iface;
77     LONG ref;
78     IWICBitmapSource *source;
79     const struct pixelformatinfo *dst_format, *src_format;
80     WICBitmapDitherType dither;
81     double alpha_threshold;
82     IWICPalette *palette;
83     CRITICAL_SECTION lock; /* must be held when initialized */
84 } FormatConverter;
85 
86 /* https://www.w3.org/Graphics/Color/srgb */
87 #ifndef __REACTOS__
88 static inline float from_sRGB_component(float f)
89 {
90     if (f <= 0.04045f) return f / 12.92f;
91     return powf((f + 0.055f) / 1.055f, 2.4f);
92 }
93 #endif
94 
95 static inline float to_sRGB_component(float f)
96 {
97     if (f <= 0.0031308f) return 12.92f * f;
98     return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
99 }
100 
101 #if 0 /* FIXME: enable once needed */
102 static void from_sRGB(BYTE *bgr)
103 {
104     float r, g, b;
105 
106     r = bgr[2] / 255.0f;
107     g = bgr[1] / 255.0f;
108     b = bgr[0] / 255.0f;
109 
110     r = from_sRGB_component(r);
111     g = from_sRGB_component(g);
112     b = from_sRGB_component(b);
113 
114     bgr[2] = (BYTE)(r * 255.0f);
115     bgr[1] = (BYTE)(g * 255.0f);
116     bgr[0] = (BYTE)(b * 255.0f);
117 }
118 
119 static void to_sRGB(BYTE *bgr)
120 {
121     float r, g, b;
122 
123     r = bgr[2] / 255.0f;
124     g = bgr[1] / 255.0f;
125     b = bgr[0] / 255.0f;
126 
127     r = to_sRGB_component(r);
128     g = to_sRGB_component(g);
129     b = to_sRGB_component(b);
130 
131     bgr[2] = (BYTE)(r * 255.0f);
132     bgr[1] = (BYTE)(g * 255.0f);
133     bgr[0] = (BYTE)(b * 255.0f);
134 }
135 #endif
136 
137 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
138 {
139     return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
140 }
141 
142 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
143     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
144 {
145     switch (source_format)
146     {
147     case format_1bppIndexed:
148     case format_BlackWhite:
149         if (prc)
150         {
151             HRESULT res;
152             INT x, y;
153             BYTE *srcdata;
154             UINT srcstride, srcdatasize;
155             const BYTE *srcrow;
156             const BYTE *srcbyte;
157             BYTE *dstrow;
158             DWORD *dstpixel;
159             WICColor colors[2];
160             IWICPalette *palette;
161             UINT actualcolors;
162 
163             res = PaletteImpl_Create(&palette);
164             if (FAILED(res)) return res;
165 
166             if (source_format == format_1bppIndexed)
167                 res = IWICBitmapSource_CopyPalette(This->source, palette);
168             else
169                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
170 
171             if (SUCCEEDED(res))
172                 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
173 
174             IWICPalette_Release(palette);
175             if (FAILED(res)) return res;
176 
177             srcstride = (prc->Width+7)/8;
178             srcdatasize = srcstride * prc->Height;
179 
180             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
181             if (!srcdata) return E_OUTOFMEMORY;
182 
183             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
184 
185             if (SUCCEEDED(res))
186             {
187                 srcrow = srcdata;
188                 dstrow = pbBuffer;
189                 for (y=0; y<prc->Height; y++) {
190                     srcbyte = srcrow;
191                     dstpixel=(DWORD*)dstrow;
192                     for (x=0; x<prc->Width; x+=8) {
193                         BYTE srcval;
194                         srcval=*srcbyte++;
195                         *dstpixel++ = colors[srcval>>7&1];
196                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
197                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
198                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
199                         if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
200                         if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
201                         if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
202                         if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
203                     }
204                     srcrow += srcstride;
205                     dstrow += cbStride;
206                 }
207             }
208 
209             HeapFree(GetProcessHeap(), 0, srcdata);
210 
211             return res;
212         }
213         return S_OK;
214     case format_2bppIndexed:
215     case format_2bppGray:
216         if (prc)
217         {
218             HRESULT res;
219             INT x, y;
220             BYTE *srcdata;
221             UINT srcstride, srcdatasize;
222             const BYTE *srcrow;
223             const BYTE *srcbyte;
224             BYTE *dstrow;
225             DWORD *dstpixel;
226             WICColor colors[4];
227             IWICPalette *palette;
228             UINT actualcolors;
229 
230             res = PaletteImpl_Create(&palette);
231             if (FAILED(res)) return res;
232 
233             if (source_format == format_2bppIndexed)
234                 res = IWICBitmapSource_CopyPalette(This->source, palette);
235             else
236                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
237 
238             if (SUCCEEDED(res))
239                 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
240 
241             IWICPalette_Release(palette);
242             if (FAILED(res)) return res;
243 
244             srcstride = (prc->Width+3)/4;
245             srcdatasize = srcstride * prc->Height;
246 
247             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
248             if (!srcdata) return E_OUTOFMEMORY;
249 
250             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
251 
252             if (SUCCEEDED(res))
253             {
254                 srcrow = srcdata;
255                 dstrow = pbBuffer;
256                 for (y=0; y<prc->Height; y++) {
257                     srcbyte = srcrow;
258                     dstpixel=(DWORD*)dstrow;
259                     for (x=0; x<prc->Width; x+=4) {
260                         BYTE srcval;
261                         srcval=*srcbyte++;
262                         *dstpixel++ = colors[srcval>>6];
263                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
264                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
265                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
266                     }
267                     srcrow += srcstride;
268                     dstrow += cbStride;
269                 }
270             }
271 
272             HeapFree(GetProcessHeap(), 0, srcdata);
273 
274             return res;
275         }
276         return S_OK;
277     case format_4bppIndexed:
278     case format_4bppGray:
279         if (prc)
280         {
281             HRESULT res;
282             INT x, y;
283             BYTE *srcdata;
284             UINT srcstride, srcdatasize;
285             const BYTE *srcrow;
286             const BYTE *srcbyte;
287             BYTE *dstrow;
288             DWORD *dstpixel;
289             WICColor colors[16];
290             IWICPalette *palette;
291             UINT actualcolors;
292 
293             res = PaletteImpl_Create(&palette);
294             if (FAILED(res)) return res;
295 
296             if (source_format == format_4bppIndexed)
297                 res = IWICBitmapSource_CopyPalette(This->source, palette);
298             else
299                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
300 
301             if (SUCCEEDED(res))
302                 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
303 
304             IWICPalette_Release(palette);
305             if (FAILED(res)) return res;
306 
307             srcstride = (prc->Width+1)/2;
308             srcdatasize = srcstride * prc->Height;
309 
310             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
311             if (!srcdata) return E_OUTOFMEMORY;
312 
313             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
314 
315             if (SUCCEEDED(res))
316             {
317                 srcrow = srcdata;
318                 dstrow = pbBuffer;
319                 for (y=0; y<prc->Height; y++) {
320                     srcbyte = srcrow;
321                     dstpixel=(DWORD*)dstrow;
322                     for (x=0; x<prc->Width; x+=2) {
323                         BYTE srcval;
324                         srcval=*srcbyte++;
325                         *dstpixel++ = colors[srcval>>4];
326                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
327                     }
328                     srcrow += srcstride;
329                     dstrow += cbStride;
330                 }
331             }
332 
333             HeapFree(GetProcessHeap(), 0, srcdata);
334 
335             return res;
336         }
337         return S_OK;
338     case format_8bppGray:
339         if (prc)
340         {
341             HRESULT res;
342             INT x, y;
343             BYTE *srcdata;
344             UINT srcstride, srcdatasize;
345             const BYTE *srcrow;
346             const BYTE *srcbyte;
347             BYTE *dstrow;
348             DWORD *dstpixel;
349 
350             srcstride = prc->Width;
351             srcdatasize = srcstride * prc->Height;
352 
353             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
354             if (!srcdata) return E_OUTOFMEMORY;
355 
356             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
357 
358             if (SUCCEEDED(res))
359             {
360                 srcrow = srcdata;
361                 dstrow = pbBuffer;
362                 for (y=0; y<prc->Height; y++) {
363                     srcbyte = srcrow;
364                     dstpixel=(DWORD*)dstrow;
365                     for (x=0; x<prc->Width; x++)
366                     {
367                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
368                         srcbyte++;
369                     }
370                     srcrow += srcstride;
371                     dstrow += cbStride;
372                 }
373             }
374 
375             HeapFree(GetProcessHeap(), 0, srcdata);
376 
377             return res;
378         }
379         return S_OK;
380     case format_8bppIndexed:
381         if (prc)
382         {
383             HRESULT res;
384             INT x, y;
385             BYTE *srcdata;
386             UINT srcstride, srcdatasize;
387             const BYTE *srcrow;
388             const BYTE *srcbyte;
389             BYTE *dstrow;
390             DWORD *dstpixel;
391             WICColor colors[256];
392             IWICPalette *palette;
393             UINT actualcolors;
394 
395             res = PaletteImpl_Create(&palette);
396             if (FAILED(res)) return res;
397 
398             res = IWICBitmapSource_CopyPalette(This->source, palette);
399             if (SUCCEEDED(res))
400                 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
401 
402             IWICPalette_Release(palette);
403 
404             if (FAILED(res)) return res;
405 
406             srcstride = prc->Width;
407             srcdatasize = srcstride * prc->Height;
408 
409             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
410             if (!srcdata) return E_OUTOFMEMORY;
411 
412             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
413 
414             if (SUCCEEDED(res))
415             {
416                 srcrow = srcdata;
417                 dstrow = pbBuffer;
418                 for (y=0; y<prc->Height; y++) {
419                     srcbyte = srcrow;
420                     dstpixel=(DWORD*)dstrow;
421                     for (x=0; x<prc->Width; x++)
422                         *dstpixel++ = colors[*srcbyte++];
423                     srcrow += srcstride;
424                     dstrow += cbStride;
425                 }
426             }
427 
428             HeapFree(GetProcessHeap(), 0, srcdata);
429 
430             return res;
431         }
432         return S_OK;
433     case format_16bppGray:
434         if (prc)
435         {
436             HRESULT res;
437             INT x, y;
438             BYTE *srcdata;
439             UINT srcstride, srcdatasize;
440             const BYTE *srcrow;
441             const BYTE *srcbyte;
442             BYTE *dstrow;
443             DWORD *dstpixel;
444 
445             srcstride = prc->Width * 2;
446             srcdatasize = srcstride * prc->Height;
447 
448             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
449             if (!srcdata) return E_OUTOFMEMORY;
450 
451             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
452 
453             if (SUCCEEDED(res))
454             {
455                 srcrow = srcdata;
456                 dstrow = pbBuffer;
457                 for (y=0; y<prc->Height; y++) {
458                     srcbyte = srcrow;
459                     dstpixel=(DWORD*)dstrow;
460                     for (x=0; x<prc->Width; x++)
461                     {
462                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
463                         srcbyte+=2;
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                         red = *srcpixel++; srcpixel++;
781                         green = *srcpixel++; srcpixel++;
782                         blue = *srcpixel++; 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                         red = *srcpixel++; srcpixel++;
825                         green = *srcpixel++; srcpixel++;
826                         blue = *srcpixel++; srcpixel++;
827                         alpha = *srcpixel++; 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     case format_32bppRGBA:
875     case format_32bppPRGBA:
876         if (prc)
877             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
878         return S_OK;
879     default:
880         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
881         if (SUCCEEDED(hr) && prc)
882               reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
883         return hr;
884     }
885 }
886 
887 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
888     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
889 {
890     switch (source_format)
891     {
892     case format_32bppBGR:
893     case format_32bppBGRA:
894     case format_32bppPBGRA:
895         if (prc)
896             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
897         return S_OK;
898     default:
899         return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
900     }
901 }
902 
903 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
904     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
905 {
906     switch (source_format)
907     {
908     case format_32bppRGB:
909     case format_32bppRGBA:
910     case format_32bppPRGBA:
911         if (prc)
912             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
913         return S_OK;
914     default:
915         return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
916     }
917 }
918 
919 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
920     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
921 {
922     HRESULT hr;
923 
924     switch (source_format)
925     {
926     case format_32bppPBGRA:
927         if (prc)
928             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
929         return S_OK;
930     default:
931         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
932         if (SUCCEEDED(hr) && prc)
933         {
934             INT x, y;
935 
936             for (y=0; y<prc->Height; y++)
937                 for (x=0; x<prc->Width; x++)
938                 {
939                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
940                     if (alpha != 255)
941                     {
942                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
943                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
944                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
945                     }
946                 }
947         }
948         return hr;
949     }
950 }
951 
952 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
953     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
954 {
955     HRESULT hr;
956 
957     switch (source_format)
958     {
959     case format_32bppPRGBA:
960         if (prc)
961             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
962         return S_OK;
963     default:
964         hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
965         if (SUCCEEDED(hr) && prc)
966         {
967             INT x, y;
968 
969             for (y=0; y<prc->Height; y++)
970                 for (x=0; x<prc->Width; x++)
971                 {
972                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
973                     if (alpha != 255)
974                     {
975                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
976                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
977                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
978                     }
979                 }
980         }
981         return hr;
982     }
983 }
984 
985 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
986     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
987 {
988     HRESULT hr;
989 
990     switch (source_format)
991     {
992     case format_24bppBGR:
993     case format_24bppRGB:
994         if (prc)
995         {
996             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
997             if (SUCCEEDED(hr) && source_format == format_24bppRGB)
998               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
999             return hr;
1000         }
1001         return S_OK;
1002     case format_32bppBGR:
1003     case format_32bppBGRA:
1004     case format_32bppPBGRA:
1005         if (prc)
1006         {
1007             HRESULT res;
1008             INT x, y;
1009             BYTE *srcdata;
1010             UINT srcstride, srcdatasize;
1011             const BYTE *srcrow;
1012             const BYTE *srcpixel;
1013             BYTE *dstrow;
1014             BYTE *dstpixel;
1015 
1016             srcstride = 4 * prc->Width;
1017             srcdatasize = srcstride * prc->Height;
1018 
1019             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1020             if (!srcdata) return E_OUTOFMEMORY;
1021 
1022             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1023 
1024             if (SUCCEEDED(res))
1025             {
1026                 srcrow = srcdata;
1027                 dstrow = pbBuffer;
1028                 for (y=0; y<prc->Height; y++) {
1029                     srcpixel=srcrow;
1030                     dstpixel=dstrow;
1031                     for (x=0; x<prc->Width; x++) {
1032                         *dstpixel++=*srcpixel++; /* blue */
1033                         *dstpixel++=*srcpixel++; /* green */
1034                         *dstpixel++=*srcpixel++; /* red */
1035                         srcpixel++; /* alpha */
1036                     }
1037                     srcrow += srcstride;
1038                     dstrow += cbStride;
1039                 }
1040             }
1041 
1042             HeapFree(GetProcessHeap(), 0, srcdata);
1043 
1044             return res;
1045         }
1046         return S_OK;
1047 
1048     case format_32bppGrayFloat:
1049         if (prc)
1050         {
1051             BYTE *srcdata;
1052             UINT srcstride, srcdatasize;
1053 
1054             srcstride = 4 * prc->Width;
1055             srcdatasize = srcstride * prc->Height;
1056 
1057             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1058             if (!srcdata) return E_OUTOFMEMORY;
1059 
1060             hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1061 
1062             if (SUCCEEDED(hr))
1063             {
1064                 INT x, y;
1065                 BYTE *src = srcdata, *dst = pbBuffer;
1066 
1067                 for (y = 0; y < prc->Height; y++)
1068                 {
1069                     float *gray_float = (float *)src;
1070                     BYTE *bgr = dst;
1071 
1072                     for (x = 0; x < prc->Width; x++)
1073                     {
1074                         BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1075                         *bgr++ = gray;
1076                         *bgr++ = gray;
1077                         *bgr++ = gray;
1078                     }
1079                     src += srcstride;
1080                     dst += cbStride;
1081                 }
1082             }
1083 
1084             HeapFree(GetProcessHeap(), 0, srcdata);
1085 
1086             return hr;
1087         }
1088         return S_OK;
1089 
1090     default:
1091         FIXME("Unimplemented conversion path!\n");
1092         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1093     }
1094 }
1095 
1096 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1097     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1098 {
1099     HRESULT hr;
1100 
1101     switch (source_format)
1102     {
1103     case format_24bppBGR:
1104     case format_24bppRGB:
1105         if (prc)
1106         {
1107             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1108             if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1109               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1110             return hr;
1111         }
1112         return S_OK;
1113     case format_32bppBGR:
1114     case format_32bppBGRA:
1115     case format_32bppPBGRA:
1116         if (prc)
1117         {
1118             HRESULT res;
1119             INT x, y;
1120             BYTE *srcdata;
1121             UINT srcstride, srcdatasize;
1122             const BYTE *srcrow;
1123             const BYTE *srcpixel;
1124             BYTE *dstrow;
1125             BYTE *dstpixel;
1126             BYTE tmppixel[3];
1127 
1128             srcstride = 4 * prc->Width;
1129             srcdatasize = srcstride * prc->Height;
1130 
1131             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1132             if (!srcdata) return E_OUTOFMEMORY;
1133 
1134             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1135 
1136             if (SUCCEEDED(res))
1137             {
1138                 srcrow = srcdata;
1139                 dstrow = pbBuffer;
1140                 for (y=0; y<prc->Height; y++) {
1141                     srcpixel=srcrow;
1142                     dstpixel=dstrow;
1143                     for (x=0; x<prc->Width; x++) {
1144                         tmppixel[0]=*srcpixel++; /* blue */
1145                         tmppixel[1]=*srcpixel++; /* green */
1146                         tmppixel[2]=*srcpixel++; /* red */
1147                         srcpixel++; /* alpha */
1148 
1149                         *dstpixel++=tmppixel[2]; /* red */
1150                         *dstpixel++=tmppixel[1]; /* green */
1151                         *dstpixel++=tmppixel[0]; /* blue */
1152                     }
1153                     srcrow += srcstride;
1154                     dstrow += cbStride;
1155                 }
1156             }
1157 
1158             HeapFree(GetProcessHeap(), 0, srcdata);
1159 
1160             return res;
1161         }
1162         return S_OK;
1163     default:
1164         FIXME("Unimplemented conversion path!\n");
1165         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1166     }
1167 }
1168 
1169 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1170     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1171 {
1172     HRESULT hr;
1173 
1174     switch (source_format)
1175     {
1176     case format_32bppBGR:
1177     case format_32bppBGRA:
1178     case format_32bppPBGRA:
1179     case format_32bppGrayFloat:
1180         if (prc)
1181         {
1182             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1183             break;
1184         }
1185         return S_OK;
1186 
1187     default:
1188         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1189         break;
1190     }
1191 
1192     if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1193     {
1194         INT x, y;
1195         BYTE *p = pbBuffer;
1196 
1197         for (y = 0; y < prc->Height; y++)
1198         {
1199             BYTE *bgr = p;
1200             for (x = 0; x < prc->Width; x++)
1201             {
1202                 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1203                 *(float *)bgr = gray;
1204                 bgr += 4;
1205             }
1206             p += cbStride;
1207         }
1208     }
1209     return hr;
1210 }
1211 
1212 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1213     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1214 {
1215     HRESULT hr;
1216     BYTE *srcdata;
1217     UINT srcstride, srcdatasize;
1218 
1219     if (source_format == format_8bppGray)
1220     {
1221         if (prc)
1222             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1223 
1224         return S_OK;
1225     }
1226 
1227     if (source_format == format_32bppGrayFloat)
1228     {
1229         hr = S_OK;
1230 
1231         if (prc)
1232         {
1233             srcstride = 4 * prc->Width;
1234             srcdatasize = srcstride * prc->Height;
1235 
1236             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1237             if (!srcdata) return E_OUTOFMEMORY;
1238 
1239             hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1240             if (SUCCEEDED(hr))
1241             {
1242                 INT x, y;
1243                 BYTE *src = srcdata, *dst = pbBuffer;
1244 
1245                 for (y=0; y < prc->Height; y++)
1246                 {
1247                     float *srcpixel = (float*)src;
1248                     BYTE *dstpixel = dst;
1249 
1250                     for (x=0; x < prc->Width; x++)
1251                         *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1252 
1253                     src += srcstride;
1254                     dst += cbStride;
1255                 }
1256             }
1257 
1258             HeapFree(GetProcessHeap(), 0, srcdata);
1259         }
1260 
1261         return hr;
1262     }
1263 
1264     srcstride = 3 * prc->Width;
1265     srcdatasize = srcstride * prc->Height;
1266 
1267     srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1268     if (!srcdata) return E_OUTOFMEMORY;
1269 
1270     hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1271     if (SUCCEEDED(hr) && prc)
1272     {
1273         INT x, y;
1274         BYTE *src = srcdata, *dst = pbBuffer;
1275 
1276         for (y = 0; y < prc->Height; y++)
1277         {
1278             BYTE *bgr = src;
1279 
1280             for (x = 0; x < prc->Width; x++)
1281             {
1282                 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1283 
1284                 gray = to_sRGB_component(gray) * 255.0f;
1285                 dst[x] = (BYTE)floorf(gray + 0.51f);
1286                 bgr += 3;
1287             }
1288             src += srcstride;
1289             dst += cbStride;
1290         }
1291     }
1292 
1293     HeapFree(GetProcessHeap(), 0, srcdata);
1294     return hr;
1295 }
1296 
1297 static UINT rgb_to_palette_index(BYTE r, BYTE g, BYTE b, WICColor *colors, UINT count)
1298 {
1299     UINT best_diff, best_index, i;
1300 
1301     best_diff = ~0;
1302     best_index = 0;
1303 
1304     for (i = 0; i < count; i++)
1305     {
1306         BYTE pal_r, pal_g, pal_b;
1307         DWORD diff_r, diff_g, diff_b, diff;
1308 
1309         pal_r = colors[i] >> 16;
1310         pal_g = colors[i] >> 8;
1311         pal_b = colors[i];
1312 
1313         diff_r = r - pal_r;
1314         diff_g = g - pal_g;
1315         diff_b = b - pal_b;
1316 
1317         diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1318         if (diff == 0) return i;
1319 
1320         if (diff < best_diff)
1321         {
1322             best_diff = diff;
1323             best_index = i;
1324         }
1325     }
1326 
1327     return best_index;
1328 }
1329 
1330 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1331     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1332 {
1333     HRESULT hr;
1334     BYTE *srcdata;
1335     WICColor colors[256];
1336     UINT srcstride, srcdatasize, count;
1337 
1338     if (source_format == format_8bppIndexed)
1339     {
1340         if (prc)
1341             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1342 
1343         return S_OK;
1344     }
1345 
1346     if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1347 
1348     hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1349     if (hr != S_OK) return hr;
1350 
1351     srcstride = 3 * prc->Width;
1352     srcdatasize = srcstride * prc->Height;
1353 
1354     srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1355     if (!srcdata) return E_OUTOFMEMORY;
1356 
1357     hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1358     if (SUCCEEDED(hr) && prc)
1359     {
1360         INT x, y;
1361         BYTE *src = srcdata, *dst = pbBuffer;
1362 
1363         for (y = 0; y < prc->Height; y++)
1364         {
1365             BYTE *bgr = src;
1366 
1367             for (x = 0; x < prc->Width; x++)
1368             {
1369                 dst[x] = rgb_to_palette_index(bgr[2], bgr[1], bgr[0], colors, count);
1370                 bgr += 3;
1371             }
1372             src += srcstride;
1373             dst += cbStride;
1374         }
1375     }
1376 
1377     HeapFree(GetProcessHeap(), 0, srcdata);
1378     return hr;
1379 }
1380 
1381 static const struct pixelformatinfo supported_formats[] = {
1382     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1383     {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1384     {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1385     {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1386     {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1387     {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1388     {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1389     {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1390     {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1391     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1392     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1393     {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1394     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1395     {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1396     {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1397     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1398     {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1399     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1400     {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1401     {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1402     {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1403     {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1404     {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1405     {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1406     {0}
1407 };
1408 
1409 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1410 {
1411     UINT i;
1412 
1413     for (i=0; supported_formats[i].guid; i++)
1414         if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1415 
1416     return NULL;
1417 }
1418 
1419 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1420     void **ppv)
1421 {
1422     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1423     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1424 
1425     if (!ppv) return E_INVALIDARG;
1426 
1427     if (IsEqualIID(&IID_IUnknown, iid) ||
1428         IsEqualIID(&IID_IWICBitmapSource, iid) ||
1429         IsEqualIID(&IID_IWICFormatConverter, iid))
1430     {
1431         *ppv = &This->IWICFormatConverter_iface;
1432     }
1433     else
1434     {
1435         *ppv = NULL;
1436         return E_NOINTERFACE;
1437     }
1438 
1439     IUnknown_AddRef((IUnknown*)*ppv);
1440     return S_OK;
1441 }
1442 
1443 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1444 {
1445     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1446     ULONG ref = InterlockedIncrement(&This->ref);
1447 
1448     TRACE("(%p) refcount=%u\n", iface, ref);
1449 
1450     return ref;
1451 }
1452 
1453 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1454 {
1455     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1456     ULONG ref = InterlockedDecrement(&This->ref);
1457 
1458     TRACE("(%p) refcount=%u\n", iface, ref);
1459 
1460     if (ref == 0)
1461     {
1462         This->lock.DebugInfo->Spare[0] = 0;
1463         DeleteCriticalSection(&This->lock);
1464         if (This->source) IWICBitmapSource_Release(This->source);
1465         if (This->palette) IWICPalette_Release(This->palette);
1466         HeapFree(GetProcessHeap(), 0, This);
1467     }
1468 
1469     return ref;
1470 }
1471 
1472 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1473     UINT *puiWidth, UINT *puiHeight)
1474 {
1475     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1476 
1477     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1478 
1479     if (This->source)
1480         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1481     else
1482         return WINCODEC_ERR_NOTINITIALIZED;
1483 }
1484 
1485 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1486     WICPixelFormatGUID *pPixelFormat)
1487 {
1488     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1489 
1490     TRACE("(%p,%p)\n", iface, pPixelFormat);
1491 
1492     if (This->source)
1493         memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1494     else
1495         return WINCODEC_ERR_NOTINITIALIZED;
1496 
1497     return S_OK;
1498 }
1499 
1500 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1501     double *pDpiX, double *pDpiY)
1502 {
1503     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1504 
1505     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1506 
1507     if (This->source)
1508         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1509     else
1510         return WINCODEC_ERR_NOTINITIALIZED;
1511 }
1512 
1513 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1514     IWICPalette *palette)
1515 {
1516     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1517 
1518     TRACE("(%p,%p)\n", iface, palette);
1519 
1520     if (!palette) return E_INVALIDARG;
1521     if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1522 
1523     if (!This->palette)
1524     {
1525         HRESULT hr;
1526         UINT bpp;
1527 
1528         hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1529         if (hr != S_OK) return hr;
1530         if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1531         return IWICBitmapSource_CopyPalette(This->source, palette);
1532     }
1533 
1534     return IWICPalette_InitializeFromPalette(palette, This->palette);
1535 }
1536 
1537 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1538     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1539 {
1540     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1541     WICRect rc;
1542     HRESULT hr;
1543     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1544 
1545     if (This->source)
1546     {
1547         if (!prc)
1548         {
1549             UINT width, height;
1550             hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1551             if (FAILED(hr)) return hr;
1552             rc.X = 0;
1553             rc.Y = 0;
1554             rc.Width = width;
1555             rc.Height = height;
1556             prc = &rc;
1557         }
1558 
1559         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1560             pbBuffer, This->src_format->format);
1561     }
1562     else
1563         return WINCODEC_ERR_WRONGSTATE;
1564 }
1565 
1566 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1567     IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1568     IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1569 {
1570     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1571     const struct pixelformatinfo *srcinfo, *dstinfo;
1572     GUID srcFormat;
1573     HRESULT res;
1574 
1575     TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1576         dither, palette, alpha_threshold, palette_type);
1577 
1578     if (!palette)
1579     {
1580         UINT bpp;
1581         res = get_pixelformat_bpp(dstFormat, &bpp);
1582         if (res != S_OK) return res;
1583 
1584         res = PaletteImpl_Create(&palette);
1585         if (res != S_OK) return res;
1586 
1587         switch (palette_type)
1588         {
1589         case WICBitmapPaletteTypeCustom:
1590             IWICPalette_Release(palette);
1591             palette = NULL;
1592             if (bpp <= 8) return E_INVALIDARG;
1593             break;
1594 
1595         case WICBitmapPaletteTypeMedianCut:
1596         {
1597             if (bpp <= 8)
1598                 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1599             break;
1600         }
1601 
1602         default:
1603             if (bpp <= 8)
1604                 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1605             break;
1606         }
1607 
1608         if (res != S_OK)
1609         {
1610             IWICPalette_Release(palette);
1611             return res;
1612         }
1613     }
1614     else
1615         IWICPalette_AddRef(palette);
1616 
1617     EnterCriticalSection(&This->lock);
1618 
1619     if (This->source)
1620     {
1621         res = WINCODEC_ERR_WRONGSTATE;
1622         goto end;
1623     }
1624 
1625     res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1626     if (FAILED(res)) goto end;
1627 
1628     srcinfo = get_formatinfo(&srcFormat);
1629     if (!srcinfo)
1630     {
1631         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1632         FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1633         goto end;
1634     }
1635 
1636     dstinfo = get_formatinfo(dstFormat);
1637     if (!dstinfo)
1638     {
1639         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1640         FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1641         goto end;
1642     }
1643 
1644     if (dstinfo->copy_function)
1645     {
1646         IWICBitmapSource_AddRef(source);
1647         This->src_format = srcinfo;
1648         This->dst_format = dstinfo;
1649         This->dither = dither;
1650         This->alpha_threshold = alpha_threshold;
1651         This->palette = palette;
1652         This->source = source;
1653     }
1654     else
1655     {
1656         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1657         res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1658     }
1659 
1660 end:
1661 
1662     LeaveCriticalSection(&This->lock);
1663 
1664     if (res != S_OK && palette)
1665         IWICPalette_Release(palette);
1666 
1667     return res;
1668 }
1669 
1670 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1671     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1672     BOOL *pfCanConvert)
1673 {
1674     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1675     const struct pixelformatinfo *srcinfo, *dstinfo;
1676 
1677     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1678         debugstr_guid(dstPixelFormat), pfCanConvert);
1679 
1680     srcinfo = get_formatinfo(srcPixelFormat);
1681     if (!srcinfo)
1682     {
1683         FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1684         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1685     }
1686 
1687     dstinfo = get_formatinfo(dstPixelFormat);
1688     if (!dstinfo)
1689     {
1690         FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1691         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1692     }
1693 
1694     if (dstinfo->copy_function &&
1695         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1696         *pfCanConvert = TRUE;
1697     else
1698     {
1699         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1700         *pfCanConvert = FALSE;
1701     }
1702 
1703     return S_OK;
1704 }
1705 
1706 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1707     FormatConverter_QueryInterface,
1708     FormatConverter_AddRef,
1709     FormatConverter_Release,
1710     FormatConverter_GetSize,
1711     FormatConverter_GetPixelFormat,
1712     FormatConverter_GetResolution,
1713     FormatConverter_CopyPalette,
1714     FormatConverter_CopyPixels,
1715     FormatConverter_Initialize,
1716     FormatConverter_CanConvert
1717 };
1718 
1719 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1720 {
1721     FormatConverter *This;
1722     HRESULT ret;
1723 
1724     TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1725 
1726     *ppv = NULL;
1727 
1728     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1729     if (!This) return E_OUTOFMEMORY;
1730 
1731     This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1732     This->ref = 1;
1733     This->source = NULL;
1734     This->palette = NULL;
1735     InitializeCriticalSection(&This->lock);
1736     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1737 
1738     ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1739     IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1740 
1741     return ret;
1742 }
1743