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