windowscodecs: Support conversions of the 24bpp PixelFormats.
[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_24bppRGB,
53     format_32bppBGR,
54     format_32bppBGRA,
55     format_32bppPBGRA,
56     format_48bppRGB,
57     format_64bppRGBA,
58     format_32bppCMYK,
59 };
60
61 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
62     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
63
64 struct pixelformatinfo {
65     enum pixelformat format;
66     const WICPixelFormatGUID *guid;
67     copyfunc copy_function;
68 };
69
70 typedef struct FormatConverter {
71     IWICFormatConverter IWICFormatConverter_iface;
72     LONG ref;
73     IWICBitmapSource *source;
74     const struct pixelformatinfo *dst_format, *src_format;
75     WICBitmapDitherType dither;
76     double alpha_threshold;
77     WICBitmapPaletteType palette_type;
78     CRITICAL_SECTION lock; /* must be held when initialized */
79 } FormatConverter;
80
81 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
82 {
83     return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
84 }
85
86 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
87     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
88 {
89     switch (source_format)
90     {
91     case format_1bppIndexed:
92     case format_BlackWhite:
93         if (prc)
94         {
95             HRESULT res;
96             UINT x, y;
97             BYTE *srcdata;
98             UINT srcstride, srcdatasize;
99             const BYTE *srcrow;
100             const BYTE *srcbyte;
101             BYTE *dstrow;
102             DWORD *dstpixel;
103             WICColor colors[2];
104             IWICPalette *palette;
105             UINT actualcolors;
106
107             res = PaletteImpl_Create(&palette);
108             if (FAILED(res)) return res;
109
110             if (source_format == format_1bppIndexed)
111                 res = IWICBitmapSource_CopyPalette(This->source, palette);
112             else
113                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
114
115             if (SUCCEEDED(res))
116                 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
117
118             IWICPalette_Release(palette);
119             if (FAILED(res)) return res;
120
121             srcstride = (prc->Width+7)/8;
122             srcdatasize = srcstride * prc->Height;
123
124             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
125             if (!srcdata) return E_OUTOFMEMORY;
126
127             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
128
129             if (SUCCEEDED(res))
130             {
131                 srcrow = srcdata;
132                 dstrow = pbBuffer;
133                 for (y=0; y<prc->Height; y++) {
134                     srcbyte = srcrow;
135                     dstpixel=(DWORD*)dstrow;
136                     for (x=0; x<prc->Width; x+=8) {
137                         BYTE srcval;
138                         srcval=*srcbyte++;
139                         *dstpixel++ = colors[srcval>>7&1];
140                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
141                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
142                         if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
143                         if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
144                         if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
145                         if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
146                         if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
147                     }
148                     srcrow += srcstride;
149                     dstrow += cbStride;
150                 }
151             }
152
153             HeapFree(GetProcessHeap(), 0, srcdata);
154
155             return res;
156         }
157         return S_OK;
158     case format_2bppIndexed:
159     case format_2bppGray:
160         if (prc)
161         {
162             HRESULT res;
163             UINT x, y;
164             BYTE *srcdata;
165             UINT srcstride, srcdatasize;
166             const BYTE *srcrow;
167             const BYTE *srcbyte;
168             BYTE *dstrow;
169             DWORD *dstpixel;
170             WICColor colors[4];
171             IWICPalette *palette;
172             UINT actualcolors;
173
174             res = PaletteImpl_Create(&palette);
175             if (FAILED(res)) return res;
176
177             if (source_format == format_2bppIndexed)
178                 res = IWICBitmapSource_CopyPalette(This->source, palette);
179             else
180                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
181
182             if (SUCCEEDED(res))
183                 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
184
185             IWICPalette_Release(palette);
186             if (FAILED(res)) return res;
187
188             srcstride = (prc->Width+3)/4;
189             srcdatasize = srcstride * prc->Height;
190
191             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
192             if (!srcdata) return E_OUTOFMEMORY;
193
194             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
195
196             if (SUCCEEDED(res))
197             {
198                 srcrow = srcdata;
199                 dstrow = pbBuffer;
200                 for (y=0; y<prc->Height; y++) {
201                     srcbyte = srcrow;
202                     dstpixel=(DWORD*)dstrow;
203                     for (x=0; x<prc->Width; x+=4) {
204                         BYTE srcval;
205                         srcval=*srcbyte++;
206                         *dstpixel++ = colors[srcval>>6];
207                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
208                         if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
209                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
210                     }
211                     srcrow += srcstride;
212                     dstrow += cbStride;
213                 }
214             }
215
216             HeapFree(GetProcessHeap(), 0, srcdata);
217
218             return res;
219         }
220         return S_OK;
221     case format_4bppIndexed:
222     case format_4bppGray:
223         if (prc)
224         {
225             HRESULT res;
226             UINT x, y;
227             BYTE *srcdata;
228             UINT srcstride, srcdatasize;
229             const BYTE *srcrow;
230             const BYTE *srcbyte;
231             BYTE *dstrow;
232             DWORD *dstpixel;
233             WICColor colors[16];
234             IWICPalette *palette;
235             UINT actualcolors;
236
237             res = PaletteImpl_Create(&palette);
238             if (FAILED(res)) return res;
239
240             if (source_format == format_4bppIndexed)
241                 res = IWICBitmapSource_CopyPalette(This->source, palette);
242             else
243                 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
244
245             if (SUCCEEDED(res))
246                 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
247
248             IWICPalette_Release(palette);
249             if (FAILED(res)) return res;
250
251             srcstride = (prc->Width+1)/2;
252             srcdatasize = srcstride * prc->Height;
253
254             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
255             if (!srcdata) return E_OUTOFMEMORY;
256
257             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
258
259             if (SUCCEEDED(res))
260             {
261                 srcrow = srcdata;
262                 dstrow = pbBuffer;
263                 for (y=0; y<prc->Height; y++) {
264                     srcbyte = srcrow;
265                     dstpixel=(DWORD*)dstrow;
266                     for (x=0; x<prc->Width; x+=2) {
267                         BYTE srcval;
268                         srcval=*srcbyte++;
269                         *dstpixel++ = colors[srcval>>4];
270                         if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
271                     }
272                     srcrow += srcstride;
273                     dstrow += cbStride;
274                 }
275             }
276
277             HeapFree(GetProcessHeap(), 0, srcdata);
278
279             return res;
280         }
281         return S_OK;
282     case format_8bppGray:
283         if (prc)
284         {
285             HRESULT res;
286             UINT x, y;
287             BYTE *srcdata;
288             UINT srcstride, srcdatasize;
289             const BYTE *srcrow;
290             const BYTE *srcbyte;
291             BYTE *dstrow;
292             DWORD *dstpixel;
293
294             srcstride = prc->Width;
295             srcdatasize = srcstride * prc->Height;
296
297             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
298             if (!srcdata) return E_OUTOFMEMORY;
299
300             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
301
302             if (SUCCEEDED(res))
303             {
304                 srcrow = srcdata;
305                 dstrow = pbBuffer;
306                 for (y=0; y<prc->Height; y++) {
307                     srcbyte = srcrow;
308                     dstpixel=(DWORD*)dstrow;
309                     for (x=0; x<prc->Width; x++)
310                     {
311                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
312                         srcbyte++;
313                     }
314                     srcrow += srcstride;
315                     dstrow += cbStride;
316                 }
317             }
318
319             HeapFree(GetProcessHeap(), 0, srcdata);
320
321             return res;
322         }
323         return S_OK;
324     case format_8bppIndexed:
325         if (prc)
326         {
327             HRESULT res;
328             UINT x, y;
329             BYTE *srcdata;
330             UINT srcstride, srcdatasize;
331             const BYTE *srcrow;
332             const BYTE *srcbyte;
333             BYTE *dstrow;
334             DWORD *dstpixel;
335             WICColor colors[256];
336             IWICPalette *palette;
337             UINT actualcolors;
338
339             res = PaletteImpl_Create(&palette);
340             if (FAILED(res)) return res;
341
342             res = IWICBitmapSource_CopyPalette(This->source, palette);
343             if (SUCCEEDED(res))
344                 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
345
346             IWICPalette_Release(palette);
347
348             if (FAILED(res)) return res;
349
350             srcstride = prc->Width;
351             srcdatasize = srcstride * prc->Height;
352
353             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
354             if (!srcdata) return E_OUTOFMEMORY;
355
356             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
357
358             if (SUCCEEDED(res))
359             {
360                 srcrow = srcdata;
361                 dstrow = pbBuffer;
362                 for (y=0; y<prc->Height; y++) {
363                     srcbyte = srcrow;
364                     dstpixel=(DWORD*)dstrow;
365                     for (x=0; x<prc->Width; x++)
366                         *dstpixel++ = colors[*srcbyte++];
367                     srcrow += srcstride;
368                     dstrow += cbStride;
369                 }
370             }
371
372             HeapFree(GetProcessHeap(), 0, srcdata);
373
374             return res;
375         }
376         return S_OK;
377     case format_16bppGray:
378         if (prc)
379         {
380             HRESULT res;
381             UINT x, y;
382             BYTE *srcdata;
383             UINT srcstride, srcdatasize;
384             const BYTE *srcrow;
385             const BYTE *srcbyte;
386             BYTE *dstrow;
387             DWORD *dstpixel;
388
389             srcstride = prc->Width * 2;
390             srcdatasize = srcstride * prc->Height;
391
392             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
393             if (!srcdata) return E_OUTOFMEMORY;
394
395             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
396
397             if (SUCCEEDED(res))
398             {
399                 srcrow = srcdata;
400                 dstrow = pbBuffer;
401                 for (y=0; y<prc->Height; y++) {
402                     srcbyte = srcrow;
403                     dstpixel=(DWORD*)dstrow;
404                     for (x=0; x<prc->Width; x++)
405                     {
406                         *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
407                         srcbyte+=2;
408                     }
409                     srcrow += srcstride;
410                     dstrow += cbStride;
411                 }
412             }
413
414             HeapFree(GetProcessHeap(), 0, srcdata);
415
416             return res;
417         }
418         return S_OK;
419     case format_16bppBGR555:
420         if (prc)
421         {
422             HRESULT res;
423             UINT x, y;
424             BYTE *srcdata;
425             UINT srcstride, srcdatasize;
426             const BYTE *srcrow;
427             const WORD *srcpixel;
428             BYTE *dstrow;
429             DWORD *dstpixel;
430
431             srcstride = 2 * prc->Width;
432             srcdatasize = srcstride * prc->Height;
433
434             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
435             if (!srcdata) return E_OUTOFMEMORY;
436
437             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
438
439             if (SUCCEEDED(res))
440             {
441                 srcrow = srcdata;
442                 dstrow = pbBuffer;
443                 for (y=0; y<prc->Height; y++) {
444                     srcpixel=(const WORD*)srcrow;
445                     dstpixel=(DWORD*)dstrow;
446                     for (x=0; x<prc->Width; x++) {
447                         WORD srcval;
448                         srcval=*srcpixel++;
449                         *dstpixel++=0xff000000 | /* constant 255 alpha */
450                                     ((srcval << 9) & 0xf80000) | /* r */
451                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
452                                     ((srcval << 6) & 0x00f800) | /* g */
453                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
454                                     ((srcval << 3) & 0x0000f8) | /* b */
455                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
456                     }
457                     srcrow += srcstride;
458                     dstrow += cbStride;
459                 }
460             }
461
462             HeapFree(GetProcessHeap(), 0, srcdata);
463
464             return res;
465         }
466         return S_OK;
467     case format_16bppBGR565:
468         if (prc)
469         {
470             HRESULT res;
471             UINT x, y;
472             BYTE *srcdata;
473             UINT srcstride, srcdatasize;
474             const BYTE *srcrow;
475             const WORD *srcpixel;
476             BYTE *dstrow;
477             DWORD *dstpixel;
478
479             srcstride = 2 * prc->Width;
480             srcdatasize = srcstride * prc->Height;
481
482             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
483             if (!srcdata) return E_OUTOFMEMORY;
484
485             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
486
487             if (SUCCEEDED(res))
488             {
489                 srcrow = srcdata;
490                 dstrow = pbBuffer;
491                 for (y=0; y<prc->Height; y++) {
492                     srcpixel=(const WORD*)srcrow;
493                     dstpixel=(DWORD*)dstrow;
494                     for (x=0; x<prc->Width; x++) {
495                         WORD srcval;
496                         srcval=*srcpixel++;
497                         *dstpixel++=0xff000000 | /* constant 255 alpha */
498                                     ((srcval << 8) & 0xf80000) | /* r */
499                                     ((srcval << 3) & 0x070000) | /* r - 3 bits */
500                                     ((srcval << 5) & 0x00fc00) | /* g */
501                                     ((srcval >> 1) & 0x000300) | /* g - 2 bits */
502                                     ((srcval << 3) & 0x0000f8) | /* b */
503                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
504                     }
505                     srcrow += srcstride;
506                     dstrow += cbStride;
507                 }
508             }
509
510             HeapFree(GetProcessHeap(), 0, srcdata);
511
512             return res;
513         }
514         return S_OK;
515     case format_16bppBGRA5551:
516         if (prc)
517         {
518             HRESULT res;
519             UINT x, y;
520             BYTE *srcdata;
521             UINT srcstride, srcdatasize;
522             const BYTE *srcrow;
523             const WORD *srcpixel;
524             BYTE *dstrow;
525             DWORD *dstpixel;
526
527             srcstride = 2 * prc->Width;
528             srcdatasize = srcstride * prc->Height;
529
530             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
531             if (!srcdata) return E_OUTOFMEMORY;
532
533             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
534
535             if (SUCCEEDED(res))
536             {
537                 srcrow = srcdata;
538                 dstrow = pbBuffer;
539                 for (y=0; y<prc->Height; y++) {
540                     srcpixel=(const WORD*)srcrow;
541                     dstpixel=(DWORD*)dstrow;
542                     for (x=0; x<prc->Width; x++) {
543                         WORD srcval;
544                         srcval=*srcpixel++;
545                         *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
546                                     ((srcval << 9) & 0xf80000) | /* r */
547                                     ((srcval << 4) & 0x070000) | /* r - 3 bits */
548                                     ((srcval << 6) & 0x00f800) | /* g */
549                                     ((srcval << 1) & 0x000700) | /* g - 3 bits */
550                                     ((srcval << 3) & 0x0000f8) | /* b */
551                                     ((srcval >> 2) & 0x000007);  /* b - 3 bits */
552                     }
553                     srcrow += srcstride;
554                     dstrow += cbStride;
555                 }
556             }
557
558             HeapFree(GetProcessHeap(), 0, srcdata);
559
560             return res;
561         }
562         return S_OK;
563     case format_24bppBGR:
564         if (prc)
565         {
566             HRESULT res;
567             UINT x, y;
568             BYTE *srcdata;
569             UINT srcstride, srcdatasize;
570             const BYTE *srcrow;
571             const BYTE *srcpixel;
572             BYTE *dstrow;
573             BYTE *dstpixel;
574
575             srcstride = 3 * prc->Width;
576             srcdatasize = srcstride * prc->Height;
577
578             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
579             if (!srcdata) return E_OUTOFMEMORY;
580
581             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
582
583             if (SUCCEEDED(res))
584             {
585                 srcrow = srcdata;
586                 dstrow = pbBuffer;
587                 for (y=0; y<prc->Height; y++) {
588                     srcpixel=srcrow;
589                     dstpixel=dstrow;
590                     for (x=0; x<prc->Width; x++) {
591                         *dstpixel++=*srcpixel++; /* blue */
592                         *dstpixel++=*srcpixel++; /* green */
593                         *dstpixel++=*srcpixel++; /* red */
594                         *dstpixel++=255; /* alpha */
595                     }
596                     srcrow += srcstride;
597                     dstrow += cbStride;
598                 }
599             }
600
601             HeapFree(GetProcessHeap(), 0, srcdata);
602
603             return res;
604         }
605         return S_OK;
606     case format_24bppRGB:
607         if (prc)
608         {
609             HRESULT res;
610             UINT x, y;
611             BYTE *srcdata;
612             UINT srcstride, srcdatasize;
613             const BYTE *srcrow;
614             const BYTE *srcpixel;
615             BYTE *dstrow;
616             BYTE *dstpixel;
617             BYTE tmppixel[3];
618
619             srcstride = 3 * prc->Width;
620             srcdatasize = srcstride * prc->Height;
621
622             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
623             if (!srcdata) return E_OUTOFMEMORY;
624
625             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
626
627             if (SUCCEEDED(res))
628             {
629                 srcrow = srcdata;
630                 dstrow = pbBuffer;
631                 for (y=0; y<prc->Height; y++) {
632                     srcpixel=srcrow;
633                     dstpixel=dstrow;
634                     for (x=0; x<prc->Width; x++) {
635                         tmppixel[0]=*srcpixel++; /* red */
636                         tmppixel[1]=*srcpixel++; /* green */
637                         tmppixel[2]=*srcpixel++; /* blue */
638
639                         *dstpixel++=tmppixel[2]; /* blue */
640                         *dstpixel++=tmppixel[1]; /* green */
641                         *dstpixel++=tmppixel[0]; /* red */
642                         *dstpixel++=255; /* alpha */
643                     }
644                     srcrow += srcstride;
645                     dstrow += cbStride;
646                 }
647             }
648
649             HeapFree(GetProcessHeap(), 0, srcdata);
650
651             return res;
652         }
653         return S_OK;
654     case format_32bppBGR:
655         if (prc)
656         {
657             HRESULT res;
658             UINT x, y;
659
660             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
661             if (FAILED(res)) return res;
662
663             /* set all alpha values to 255 */
664             for (y=0; y<prc->Height; y++)
665                 for (x=0; x<prc->Width; x++)
666                     pbBuffer[cbStride*y+4*x+3] = 0xff;
667         }
668         return S_OK;
669     case format_32bppBGRA:
670         if (prc)
671             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
672         return S_OK;
673     case format_32bppPBGRA:
674         if (prc)
675         {
676             HRESULT res;
677             UINT x, y;
678
679             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
680             if (FAILED(res)) return res;
681
682             for (y=0; y<prc->Height; y++)
683                 for (x=0; x<prc->Width; x++)
684                 {
685                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
686                     if (alpha != 0 && alpha != 255)
687                     {
688                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
689                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
690                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
691                     }
692                 }
693         }
694         return S_OK;
695     case format_48bppRGB:
696         if (prc)
697         {
698             HRESULT res;
699             UINT x, y;
700             BYTE *srcdata;
701             UINT srcstride, srcdatasize;
702             const BYTE *srcrow;
703             const BYTE *srcpixel;
704             BYTE *dstrow;
705             DWORD *dstpixel;
706
707             srcstride = 6 * prc->Width;
708             srcdatasize = srcstride * prc->Height;
709
710             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
711             if (!srcdata) return E_OUTOFMEMORY;
712
713             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
714
715             if (SUCCEEDED(res))
716             {
717                 srcrow = srcdata;
718                 dstrow = pbBuffer;
719                 for (y=0; y<prc->Height; y++) {
720                     srcpixel=srcrow;
721                     dstpixel=(DWORD*)dstrow;
722                     for (x=0; x<prc->Width; x++) {
723                         BYTE red, green, blue;
724                         red = *srcpixel++; srcpixel++;
725                         green = *srcpixel++; srcpixel++;
726                         blue = *srcpixel++; srcpixel++;
727                         *dstpixel++=0xff000000|red<<16|green<<8|blue;
728                     }
729                     srcrow += srcstride;
730                     dstrow += cbStride;
731                 }
732             }
733
734             HeapFree(GetProcessHeap(), 0, srcdata);
735
736             return res;
737         }
738         return S_OK;
739     case format_64bppRGBA:
740         if (prc)
741         {
742             HRESULT res;
743             UINT x, y;
744             BYTE *srcdata;
745             UINT srcstride, srcdatasize;
746             const BYTE *srcrow;
747             const BYTE *srcpixel;
748             BYTE *dstrow;
749             DWORD *dstpixel;
750
751             srcstride = 8 * prc->Width;
752             srcdatasize = srcstride * prc->Height;
753
754             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
755             if (!srcdata) return E_OUTOFMEMORY;
756
757             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
758
759             if (SUCCEEDED(res))
760             {
761                 srcrow = srcdata;
762                 dstrow = pbBuffer;
763                 for (y=0; y<prc->Height; y++) {
764                     srcpixel=srcrow;
765                     dstpixel=(DWORD*)dstrow;
766                     for (x=0; x<prc->Width; x++) {
767                         BYTE red, green, blue, alpha;
768                         red = *srcpixel++; srcpixel++;
769                         green = *srcpixel++; srcpixel++;
770                         blue = *srcpixel++; srcpixel++;
771                         alpha = *srcpixel++; srcpixel++;
772                         *dstpixel++=alpha<<24|red<<16|green<<8|blue;
773                     }
774                     srcrow += srcstride;
775                     dstrow += cbStride;
776                 }
777             }
778
779             HeapFree(GetProcessHeap(), 0, srcdata);
780
781             return res;
782         }
783         return S_OK;
784     case format_32bppCMYK:
785         if (prc)
786         {
787             HRESULT res;
788             UINT x, y;
789
790             res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
791             if (FAILED(res)) return res;
792
793             for (y=0; y<prc->Height; y++)
794                 for (x=0; x<prc->Width; x++)
795                 {
796                     BYTE *pixel = pbBuffer+cbStride*y+4*x;
797                     BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
798                     pixel[0] = (255-y)*(255-k)/255; /* blue */
799                     pixel[1] = (255-m)*(255-k)/255; /* green */
800                     pixel[2] = (255-c)*(255-k)/255; /* red */
801                     pixel[3] = 255; /* alpha */
802                 }
803         }
804         return S_OK;
805     default:
806         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
807     }
808 }
809
810 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
811     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
812 {
813     switch (source_format)
814     {
815     case format_32bppBGR:
816     case format_32bppBGRA:
817     case format_32bppPBGRA:
818         if (prc)
819             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
820         return S_OK;
821     default:
822         return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
823     }
824 }
825
826 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
827     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
828 {
829     HRESULT hr;
830
831     switch (source_format)
832     {
833     case format_32bppPBGRA:
834         if (prc)
835             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
836         return S_OK;
837     default:
838         hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
839         if (SUCCEEDED(hr) && prc)
840         {
841             UINT x, y;
842
843             for (y=0; y<prc->Height; y++)
844                 for (x=0; x<prc->Width; x++)
845                 {
846                     BYTE alpha = pbBuffer[cbStride*y+4*x+3];
847                     if (alpha != 255)
848                     {
849                         pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
850                         pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
851                         pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
852                     }
853                 }
854         }
855         return hr;
856     }
857 }
858
859 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
860     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
861 {
862     HRESULT hr;
863
864     switch (source_format)
865     {
866     case format_24bppBGR:
867     case format_24bppRGB:
868         if (prc)
869         {
870             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
871             if (SUCCEEDED(hr) && source_format == format_24bppRGB)
872               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
873             return hr;
874         }
875         return S_OK;
876     case format_32bppBGR:
877     case format_32bppBGRA:
878     case format_32bppPBGRA:
879         if (prc)
880         {
881             HRESULT res;
882             UINT x, y;
883             BYTE *srcdata;
884             UINT srcstride, srcdatasize;
885             const BYTE *srcrow;
886             const BYTE *srcpixel;
887             BYTE *dstrow;
888             BYTE *dstpixel;
889
890             srcstride = 4 * prc->Width;
891             srcdatasize = srcstride * prc->Height;
892
893             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
894             if (!srcdata) return E_OUTOFMEMORY;
895
896             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
897
898             if (SUCCEEDED(res))
899             {
900                 srcrow = srcdata;
901                 dstrow = pbBuffer;
902                 for (y=0; y<prc->Height; y++) {
903                     srcpixel=srcrow;
904                     dstpixel=dstrow;
905                     for (x=0; x<prc->Width; x++) {
906                         *dstpixel++=*srcpixel++; /* blue */
907                         *dstpixel++=*srcpixel++; /* green */
908                         *dstpixel++=*srcpixel++; /* red */
909                         srcpixel++; /* alpha */
910                     }
911                     srcrow += srcstride;
912                     dstrow += cbStride;
913                 }
914             }
915
916             HeapFree(GetProcessHeap(), 0, srcdata);
917
918             return res;
919         }
920         return S_OK;
921     default:
922         FIXME("Unimplemented conversion path!\n");
923         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
924     }
925 }
926
927 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
928     UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
929 {
930     HRESULT hr;
931
932     switch (source_format)
933     {
934     case format_24bppBGR:
935     case format_24bppRGB:
936         if (prc)
937         {
938             hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
939             if (SUCCEEDED(hr) && source_format == format_24bppBGR)
940               reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
941             return hr;
942         }
943         return S_OK;
944     case format_32bppBGR:
945     case format_32bppBGRA:
946     case format_32bppPBGRA:
947         if (prc)
948         {
949             HRESULT res;
950             UINT x, y;
951             BYTE *srcdata;
952             UINT srcstride, srcdatasize;
953             const BYTE *srcrow;
954             const BYTE *srcpixel;
955             BYTE *dstrow;
956             BYTE *dstpixel;
957
958             srcstride = 4 * prc->Width;
959             srcdatasize = srcstride * prc->Height;
960
961             srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
962             if (!srcdata) return E_OUTOFMEMORY;
963
964             res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
965
966             if (SUCCEEDED(res))
967             {
968                 srcrow = srcdata;
969                 dstrow = pbBuffer;
970                 for (y=0; y<prc->Height; y++) {
971                     srcpixel=srcrow;
972                     dstpixel=dstrow;
973                     for (x=0; x<prc->Width; x++) {
974                         *dstpixel++=*srcpixel++; /* blue */
975                         *dstpixel++=*srcpixel++; /* green */
976                         *dstpixel++=*srcpixel++; /* red */
977                         srcpixel++; /* alpha */
978                     }
979                     srcrow += srcstride;
980                     dstrow += cbStride;
981                 }
982
983                 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
984             }
985
986             HeapFree(GetProcessHeap(), 0, srcdata);
987
988             return res;
989         }
990         return S_OK;
991     default:
992         FIXME("Unimplemented conversion path!\n");
993         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
994     }
995 }
996
997 static const struct pixelformatinfo supported_formats[] = {
998     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
999     {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1000     {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1001     {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
1002     {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1003     {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1004     {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1005     {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
1006     {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1007     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1008     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1009     {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1010     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1011     {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1012     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1013     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1014     {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1015     {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1016     {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1017     {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1018     {0}
1019 };
1020
1021 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1022 {
1023     UINT i;
1024
1025     for (i=0; supported_formats[i].guid; i++)
1026         if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1027
1028     return NULL;
1029 }
1030
1031 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1032     void **ppv)
1033 {
1034     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1035     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1036
1037     if (!ppv) return E_INVALIDARG;
1038
1039     if (IsEqualIID(&IID_IUnknown, iid) ||
1040         IsEqualIID(&IID_IWICBitmapSource, iid) ||
1041         IsEqualIID(&IID_IWICFormatConverter, iid))
1042     {
1043         *ppv = &This->IWICFormatConverter_iface;
1044     }
1045     else
1046     {
1047         *ppv = NULL;
1048         return E_NOINTERFACE;
1049     }
1050
1051     IUnknown_AddRef((IUnknown*)*ppv);
1052     return S_OK;
1053 }
1054
1055 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1056 {
1057     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1058     ULONG ref = InterlockedIncrement(&This->ref);
1059
1060     TRACE("(%p) refcount=%u\n", iface, ref);
1061
1062     return ref;
1063 }
1064
1065 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1066 {
1067     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1068     ULONG ref = InterlockedDecrement(&This->ref);
1069
1070     TRACE("(%p) refcount=%u\n", iface, ref);
1071
1072     if (ref == 0)
1073     {
1074         This->lock.DebugInfo->Spare[0] = 0;
1075         DeleteCriticalSection(&This->lock);
1076         if (This->source) IWICBitmapSource_Release(This->source);
1077         HeapFree(GetProcessHeap(), 0, This);
1078     }
1079
1080     return ref;
1081 }
1082
1083 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1084     UINT *puiWidth, UINT *puiHeight)
1085 {
1086     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1087
1088     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1089
1090     if (This->source)
1091         return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1092     else
1093         return WINCODEC_ERR_NOTINITIALIZED;
1094 }
1095
1096 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1097     WICPixelFormatGUID *pPixelFormat)
1098 {
1099     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1100
1101     TRACE("(%p,%p): stub\n", iface, pPixelFormat);
1102
1103     if (This->source)
1104         memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1105     else
1106         return WINCODEC_ERR_NOTINITIALIZED;
1107
1108     return S_OK;
1109 }
1110
1111 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1112     double *pDpiX, double *pDpiY)
1113 {
1114     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1115
1116     TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
1117
1118     if (This->source)
1119         return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1120     else
1121         return WINCODEC_ERR_NOTINITIALIZED;
1122 }
1123
1124 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1125     IWICPalette *pIPalette)
1126 {
1127     FIXME("(%p,%p): stub\n", iface, pIPalette);
1128     return E_NOTIMPL;
1129 }
1130
1131 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1132     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1133 {
1134     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1135     WICRect rc;
1136     HRESULT hr;
1137     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1138
1139     if (This->source)
1140     {
1141         if (!prc)
1142         {
1143             UINT width, height;
1144             hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1145             if (FAILED(hr)) return hr;
1146             rc.X = 0;
1147             rc.Y = 0;
1148             rc.Width = width;
1149             rc.Height = height;
1150             prc = &rc;
1151         }
1152
1153         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1154             pbBuffer, This->src_format->format);
1155     }
1156     else
1157         return WINCODEC_ERR_NOTINITIALIZED;
1158 }
1159
1160 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1161     IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1162     IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
1163 {
1164     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1165     const struct pixelformatinfo *srcinfo, *dstinfo;
1166     static INT fixme=0;
1167     GUID srcFormat;
1168     HRESULT res=S_OK;
1169
1170     TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1171         dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1172
1173     if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1174
1175     EnterCriticalSection(&This->lock);
1176
1177     if (This->source)
1178     {
1179         res = WINCODEC_ERR_WRONGSTATE;
1180         goto end;
1181     }
1182
1183     res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1184     if (FAILED(res)) goto end;
1185
1186     srcinfo = get_formatinfo(&srcFormat);
1187     if (!srcinfo)
1188     {
1189         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1190         FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1191         goto end;
1192     }
1193
1194     dstinfo = get_formatinfo(dstFormat);
1195     if (!dstinfo)
1196     {
1197         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1198         FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1199         goto end;
1200     }
1201
1202     if (dstinfo->copy_function)
1203     {
1204         IWICBitmapSource_AddRef(pISource);
1205         This->src_format = srcinfo;
1206         This->dst_format = dstinfo;
1207         This->dither = dither;
1208         This->alpha_threshold = alphaThresholdPercent;
1209         This->palette_type = paletteTranslate;
1210         This->source = pISource;
1211     }
1212     else
1213     {
1214         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1215         res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1216     }
1217
1218 end:
1219
1220     LeaveCriticalSection(&This->lock);
1221
1222     return res;
1223 }
1224
1225 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1226     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1227     BOOL *pfCanConvert)
1228 {
1229     FormatConverter *This = impl_from_IWICFormatConverter(iface);
1230     const struct pixelformatinfo *srcinfo, *dstinfo;
1231
1232     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1233         debugstr_guid(dstPixelFormat), pfCanConvert);
1234
1235     srcinfo = get_formatinfo(srcPixelFormat);
1236     if (!srcinfo)
1237     {
1238         FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1239         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1240     }
1241
1242     dstinfo = get_formatinfo(dstPixelFormat);
1243     if (!dstinfo)
1244     {
1245         FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1246         return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1247     }
1248
1249     if (dstinfo->copy_function &&
1250         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1251         *pfCanConvert = TRUE;
1252     else
1253     {
1254         FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1255         *pfCanConvert = FALSE;
1256     }
1257
1258     return S_OK;
1259 }
1260
1261 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1262     FormatConverter_QueryInterface,
1263     FormatConverter_AddRef,
1264     FormatConverter_Release,
1265     FormatConverter_GetSize,
1266     FormatConverter_GetPixelFormat,
1267     FormatConverter_GetResolution,
1268     FormatConverter_CopyPalette,
1269     FormatConverter_CopyPixels,
1270     FormatConverter_Initialize,
1271     FormatConverter_CanConvert
1272 };
1273
1274 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1275 {
1276     FormatConverter *This;
1277     HRESULT ret;
1278
1279     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1280
1281     *ppv = NULL;
1282
1283     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1284
1285     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1286     if (!This) return E_OUTOFMEMORY;
1287
1288     This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1289     This->ref = 1;
1290     This->source = NULL;
1291     InitializeCriticalSection(&This->lock);
1292     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1293
1294     ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1295     IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1296
1297     return ret;
1298 }