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