include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / windowscodecs / converter.c
blobc2657dc0d336270cf349fd4ff60d7fac2315f82a
1 /*
2 * Copyright 2009 Vincent Povirk
3 * Copyright 2016 Dmitry Timoshkov
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.
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.
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
20 #include <stdarg.h>
21 #include <math.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
29 #include "wincodecs_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
35 struct FormatConverter;
37 enum pixelformat {
38 format_1bppIndexed,
39 format_2bppIndexed,
40 format_4bppIndexed,
41 format_8bppIndexed,
42 format_BlackWhite,
43 format_2bppGray,
44 format_4bppGray,
45 format_8bppGray,
46 format_16bppGray,
47 format_16bppBGR555,
48 format_16bppBGR565,
49 format_16bppBGRA5551,
50 format_24bppBGR,
51 format_24bppRGB,
52 format_32bppGrayFloat,
53 format_32bppBGR,
54 format_32bppRGB,
55 format_32bppBGRA,
56 format_32bppRGBA,
57 format_32bppPBGRA,
58 format_32bppPRGBA,
59 format_48bppRGB,
60 format_64bppRGBA,
61 format_32bppCMYK,
64 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
65 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
67 struct pixelformatinfo {
68 enum pixelformat format;
69 const WICPixelFormatGUID *guid;
70 copyfunc copy_function;
71 BOOL is_indexed_format;
74 typedef struct FormatConverter {
75 IWICFormatConverter IWICFormatConverter_iface;
76 LONG ref;
77 IWICBitmapSource *source;
78 const struct pixelformatinfo *dst_format, *src_format;
79 WICBitmapDitherType dither;
80 double alpha_threshold;
81 IWICPalette *palette;
82 CRITICAL_SECTION lock; /* must be held when initialized */
83 } FormatConverter;
85 /* https://www.w3.org/Graphics/Color/srgb */
86 static inline float to_sRGB_component(float f)
88 if (f <= 0.0031308f) return 12.92f * f;
89 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
92 #if 0 /* FIXME: enable once needed */
93 static inline float from_sRGB_component(float f)
95 if (f <= 0.04045f) return f / 12.92f;
96 return powf((f + 0.055f) / 1.055f, 2.4f);
99 static void from_sRGB(BYTE *bgr)
101 float r, g, b;
103 r = bgr[2] / 255.0f;
104 g = bgr[1] / 255.0f;
105 b = bgr[0] / 255.0f;
107 r = from_sRGB_component(r);
108 g = from_sRGB_component(g);
109 b = from_sRGB_component(b);
111 bgr[2] = (BYTE)(r * 255.0f);
112 bgr[1] = (BYTE)(g * 255.0f);
113 bgr[0] = (BYTE)(b * 255.0f);
116 static void to_sRGB(BYTE *bgr)
118 float r, g, b;
120 r = bgr[2] / 255.0f;
121 g = bgr[1] / 255.0f;
122 b = bgr[0] / 255.0f;
124 r = to_sRGB_component(r);
125 g = to_sRGB_component(g);
126 b = to_sRGB_component(b);
128 bgr[2] = (BYTE)(r * 255.0f);
129 bgr[1] = (BYTE)(g * 255.0f);
130 bgr[0] = (BYTE)(b * 255.0f);
132 #endif
134 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
136 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
139 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
140 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
142 switch (source_format)
144 case format_1bppIndexed:
145 case format_BlackWhite:
146 if (prc)
148 HRESULT res;
149 INT x, y;
150 BYTE *srcdata;
151 UINT srcstride, srcdatasize;
152 const BYTE *srcrow;
153 const BYTE *srcbyte;
154 BYTE *dstrow;
155 DWORD *dstpixel;
156 WICColor colors[2];
157 IWICPalette *palette;
158 UINT actualcolors;
160 res = PaletteImpl_Create(&palette);
161 if (FAILED(res)) return res;
163 if (source_format == format_1bppIndexed)
164 res = IWICBitmapSource_CopyPalette(This->source, palette);
165 else
166 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
168 if (SUCCEEDED(res))
169 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
171 IWICPalette_Release(palette);
172 if (FAILED(res)) return res;
174 srcstride = (prc->Width+7)/8;
175 srcdatasize = srcstride * prc->Height;
177 srcdata = malloc(srcdatasize);
178 if (!srcdata) return E_OUTOFMEMORY;
180 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
182 if (SUCCEEDED(res))
184 srcrow = srcdata;
185 dstrow = pbBuffer;
186 for (y=0; y<prc->Height; y++) {
187 srcbyte = srcrow;
188 dstpixel=(DWORD*)dstrow;
189 for (x=0; x<prc->Width; x+=8) {
190 BYTE srcval;
191 srcval=*srcbyte++;
192 *dstpixel++ = colors[srcval>>7&1];
193 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
194 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
195 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
196 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
197 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
198 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
199 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
201 srcrow += srcstride;
202 dstrow += cbStride;
206 free(srcdata);
208 return res;
210 return S_OK;
211 case format_2bppIndexed:
212 case format_2bppGray:
213 if (prc)
215 HRESULT res;
216 INT x, y;
217 BYTE *srcdata;
218 UINT srcstride, srcdatasize;
219 const BYTE *srcrow;
220 const BYTE *srcbyte;
221 BYTE *dstrow;
222 DWORD *dstpixel;
223 WICColor colors[4];
224 IWICPalette *palette;
225 UINT actualcolors;
227 res = PaletteImpl_Create(&palette);
228 if (FAILED(res)) return res;
230 if (source_format == format_2bppIndexed)
231 res = IWICBitmapSource_CopyPalette(This->source, palette);
232 else
233 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
235 if (SUCCEEDED(res))
236 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
238 IWICPalette_Release(palette);
239 if (FAILED(res)) return res;
241 srcstride = (prc->Width+3)/4;
242 srcdatasize = srcstride * prc->Height;
244 srcdata = malloc(srcdatasize);
245 if (!srcdata) return E_OUTOFMEMORY;
247 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
249 if (SUCCEEDED(res))
251 srcrow = srcdata;
252 dstrow = pbBuffer;
253 for (y=0; y<prc->Height; y++) {
254 srcbyte = srcrow;
255 dstpixel=(DWORD*)dstrow;
256 for (x=0; x<prc->Width; x+=4) {
257 BYTE srcval;
258 srcval=*srcbyte++;
259 *dstpixel++ = colors[srcval>>6];
260 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
261 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
262 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
264 srcrow += srcstride;
265 dstrow += cbStride;
269 free(srcdata);
271 return res;
273 return S_OK;
274 case format_4bppIndexed:
275 case format_4bppGray:
276 if (prc)
278 HRESULT res;
279 INT x, y;
280 BYTE *srcdata;
281 UINT srcstride, srcdatasize;
282 const BYTE *srcrow;
283 const BYTE *srcbyte;
284 BYTE *dstrow;
285 DWORD *dstpixel;
286 WICColor colors[16];
287 IWICPalette *palette;
288 UINT actualcolors;
290 res = PaletteImpl_Create(&palette);
291 if (FAILED(res)) return res;
293 if (source_format == format_4bppIndexed)
294 res = IWICBitmapSource_CopyPalette(This->source, palette);
295 else
296 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
298 if (SUCCEEDED(res))
299 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
301 IWICPalette_Release(palette);
302 if (FAILED(res)) return res;
304 srcstride = (prc->Width+1)/2;
305 srcdatasize = srcstride * prc->Height;
307 srcdata = malloc(srcdatasize);
308 if (!srcdata) return E_OUTOFMEMORY;
310 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
312 if (SUCCEEDED(res))
314 srcrow = srcdata;
315 dstrow = pbBuffer;
316 for (y=0; y<prc->Height; y++) {
317 srcbyte = srcrow;
318 dstpixel=(DWORD*)dstrow;
319 for (x=0; x<prc->Width; x+=2) {
320 BYTE srcval;
321 srcval=*srcbyte++;
322 *dstpixel++ = colors[srcval>>4];
323 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
325 srcrow += srcstride;
326 dstrow += cbStride;
330 free(srcdata);
332 return res;
334 return S_OK;
335 case format_8bppGray:
336 if (prc)
338 HRESULT res;
339 INT x, y;
340 BYTE *srcdata;
341 UINT srcstride, srcdatasize;
342 const BYTE *srcrow;
343 const BYTE *srcbyte;
344 BYTE *dstrow;
345 DWORD *dstpixel;
347 srcstride = prc->Width;
348 srcdatasize = srcstride * prc->Height;
350 srcdata = malloc(srcdatasize);
351 if (!srcdata) return E_OUTOFMEMORY;
353 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
355 if (SUCCEEDED(res))
357 srcrow = srcdata;
358 dstrow = pbBuffer;
359 for (y=0; y<prc->Height; y++) {
360 srcbyte = srcrow;
361 dstpixel=(DWORD*)dstrow;
362 for (x=0; x<prc->Width; x++)
364 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
365 srcbyte++;
367 srcrow += srcstride;
368 dstrow += cbStride;
372 free(srcdata);
374 return res;
376 return S_OK;
377 case format_8bppIndexed:
378 if (prc)
380 HRESULT res;
381 INT x, y;
382 BYTE *srcdata;
383 UINT srcstride, srcdatasize;
384 const BYTE *srcrow;
385 const BYTE *srcbyte;
386 BYTE *dstrow;
387 DWORD *dstpixel;
388 WICColor colors[256];
389 IWICPalette *palette;
390 UINT actualcolors;
392 res = PaletteImpl_Create(&palette);
393 if (FAILED(res)) return res;
395 res = IWICBitmapSource_CopyPalette(This->source, palette);
396 if (SUCCEEDED(res))
397 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
399 IWICPalette_Release(palette);
401 if (FAILED(res)) return res;
403 srcstride = prc->Width;
404 srcdatasize = srcstride * prc->Height;
406 srcdata = malloc(srcdatasize);
407 if (!srcdata) return E_OUTOFMEMORY;
409 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
411 if (SUCCEEDED(res))
413 srcrow = srcdata;
414 dstrow = pbBuffer;
415 for (y=0; y<prc->Height; y++) {
416 srcbyte = srcrow;
417 dstpixel=(DWORD*)dstrow;
418 for (x=0; x<prc->Width; x++)
419 *dstpixel++ = colors[*srcbyte++];
420 srcrow += srcstride;
421 dstrow += cbStride;
425 free(srcdata);
427 return res;
429 return S_OK;
430 case format_16bppGray:
431 if (prc)
433 HRESULT res;
434 INT x, y;
435 BYTE *srcdata;
436 UINT srcstride, srcdatasize;
437 const BYTE *srcrow;
438 const BYTE *srcbyte;
439 BYTE *dstrow;
440 DWORD *dstpixel;
442 srcstride = prc->Width * 2;
443 srcdatasize = srcstride * prc->Height;
445 srcdata = malloc(srcdatasize);
446 if (!srcdata) return E_OUTOFMEMORY;
448 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
450 if (SUCCEEDED(res))
452 srcrow = srcdata;
453 dstrow = pbBuffer;
454 for (y=0; y<prc->Height; y++) {
455 srcbyte = srcrow;
456 dstpixel=(DWORD*)dstrow;
457 for (x=0; x<prc->Width; x++)
459 srcbyte++;
460 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
461 srcbyte++;
463 srcrow += srcstride;
464 dstrow += cbStride;
468 free(srcdata);
470 return res;
472 return S_OK;
473 case format_16bppBGR555:
474 if (prc)
476 HRESULT res;
477 INT x, y;
478 BYTE *srcdata;
479 UINT srcstride, srcdatasize;
480 const BYTE *srcrow;
481 const WORD *srcpixel;
482 BYTE *dstrow;
483 DWORD *dstpixel;
485 srcstride = 2 * prc->Width;
486 srcdatasize = srcstride * prc->Height;
488 srcdata = malloc(srcdatasize);
489 if (!srcdata) return E_OUTOFMEMORY;
491 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
493 if (SUCCEEDED(res))
495 srcrow = srcdata;
496 dstrow = pbBuffer;
497 for (y=0; y<prc->Height; y++) {
498 srcpixel=(const WORD*)srcrow;
499 dstpixel=(DWORD*)dstrow;
500 for (x=0; x<prc->Width; x++) {
501 WORD srcval;
502 srcval=*srcpixel++;
503 *dstpixel++=0xff000000 | /* constant 255 alpha */
504 ((srcval << 9) & 0xf80000) | /* r */
505 ((srcval << 4) & 0x070000) | /* r - 3 bits */
506 ((srcval << 6) & 0x00f800) | /* g */
507 ((srcval << 1) & 0x000700) | /* g - 3 bits */
508 ((srcval << 3) & 0x0000f8) | /* b */
509 ((srcval >> 2) & 0x000007); /* b - 3 bits */
511 srcrow += srcstride;
512 dstrow += cbStride;
516 free(srcdata);
518 return res;
520 return S_OK;
521 case format_16bppBGR565:
522 if (prc)
524 HRESULT res;
525 INT x, y;
526 BYTE *srcdata;
527 UINT srcstride, srcdatasize;
528 const BYTE *srcrow;
529 const WORD *srcpixel;
530 BYTE *dstrow;
531 DWORD *dstpixel;
533 srcstride = 2 * prc->Width;
534 srcdatasize = srcstride * prc->Height;
536 srcdata = malloc(srcdatasize);
537 if (!srcdata) return E_OUTOFMEMORY;
539 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
541 if (SUCCEEDED(res))
543 srcrow = srcdata;
544 dstrow = pbBuffer;
545 for (y=0; y<prc->Height; y++) {
546 srcpixel=(const WORD*)srcrow;
547 dstpixel=(DWORD*)dstrow;
548 for (x=0; x<prc->Width; x++) {
549 WORD srcval;
550 srcval=*srcpixel++;
551 *dstpixel++=0xff000000 | /* constant 255 alpha */
552 ((srcval << 8) & 0xf80000) | /* r */
553 ((srcval << 3) & 0x070000) | /* r - 3 bits */
554 ((srcval << 5) & 0x00fc00) | /* g */
555 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
556 ((srcval << 3) & 0x0000f8) | /* b */
557 ((srcval >> 2) & 0x000007); /* b - 3 bits */
559 srcrow += srcstride;
560 dstrow += cbStride;
564 free(srcdata);
566 return res;
568 return S_OK;
569 case format_16bppBGRA5551:
570 if (prc)
572 HRESULT res;
573 INT x, y;
574 BYTE *srcdata;
575 UINT srcstride, srcdatasize;
576 const BYTE *srcrow;
577 const WORD *srcpixel;
578 BYTE *dstrow;
579 DWORD *dstpixel;
581 srcstride = 2 * prc->Width;
582 srcdatasize = srcstride * prc->Height;
584 srcdata = malloc(srcdatasize);
585 if (!srcdata) return E_OUTOFMEMORY;
587 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
589 if (SUCCEEDED(res))
591 srcrow = srcdata;
592 dstrow = pbBuffer;
593 for (y=0; y<prc->Height; y++) {
594 srcpixel=(const WORD*)srcrow;
595 dstpixel=(DWORD*)dstrow;
596 for (x=0; x<prc->Width; x++) {
597 WORD srcval;
598 srcval=*srcpixel++;
599 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
600 ((srcval << 9) & 0xf80000) | /* r */
601 ((srcval << 4) & 0x070000) | /* r - 3 bits */
602 ((srcval << 6) & 0x00f800) | /* g */
603 ((srcval << 1) & 0x000700) | /* g - 3 bits */
604 ((srcval << 3) & 0x0000f8) | /* b */
605 ((srcval >> 2) & 0x000007); /* b - 3 bits */
607 srcrow += srcstride;
608 dstrow += cbStride;
612 free(srcdata);
614 return res;
616 return S_OK;
617 case format_24bppBGR:
618 if (prc)
620 HRESULT res;
621 INT x, y;
622 BYTE *srcdata;
623 UINT srcstride, srcdatasize;
624 const BYTE *srcrow;
625 const BYTE *srcpixel;
626 BYTE *dstrow;
627 BYTE *dstpixel;
629 srcstride = 3 * prc->Width;
630 srcdatasize = srcstride * prc->Height;
632 srcdata = malloc(srcdatasize);
633 if (!srcdata) return E_OUTOFMEMORY;
635 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
637 if (SUCCEEDED(res))
639 srcrow = srcdata;
640 dstrow = pbBuffer;
641 for (y=0; y<prc->Height; y++) {
642 srcpixel=srcrow;
643 dstpixel=dstrow;
644 for (x=0; x<prc->Width; x++) {
645 *dstpixel++=*srcpixel++; /* blue */
646 *dstpixel++=*srcpixel++; /* green */
647 *dstpixel++=*srcpixel++; /* red */
648 *dstpixel++=255; /* alpha */
650 srcrow += srcstride;
651 dstrow += cbStride;
655 free(srcdata);
657 return res;
659 return S_OK;
660 case format_24bppRGB:
661 if (prc)
663 HRESULT res;
664 INT x, y;
665 BYTE *srcdata;
666 UINT srcstride, srcdatasize;
667 const BYTE *srcrow;
668 const BYTE *srcpixel;
669 BYTE *dstrow;
670 BYTE *dstpixel;
671 BYTE tmppixel[3];
673 srcstride = 3 * prc->Width;
674 srcdatasize = srcstride * prc->Height;
676 srcdata = malloc(srcdatasize);
677 if (!srcdata) return E_OUTOFMEMORY;
679 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
681 if (SUCCEEDED(res))
683 srcrow = srcdata;
684 dstrow = pbBuffer;
685 for (y=0; y<prc->Height; y++) {
686 srcpixel=srcrow;
687 dstpixel=dstrow;
688 for (x=0; x<prc->Width; x++) {
689 tmppixel[0]=*srcpixel++; /* red */
690 tmppixel[1]=*srcpixel++; /* green */
691 tmppixel[2]=*srcpixel++; /* blue */
693 *dstpixel++=tmppixel[2]; /* blue */
694 *dstpixel++=tmppixel[1]; /* green */
695 *dstpixel++=tmppixel[0]; /* red */
696 *dstpixel++=255; /* alpha */
698 srcrow += srcstride;
699 dstrow += cbStride;
703 free(srcdata);
705 return res;
707 return S_OK;
708 case format_32bppBGR:
709 if (prc)
711 HRESULT res;
712 INT x, y;
714 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
715 if (FAILED(res)) return res;
717 /* set all alpha values to 255 */
718 for (y=0; y<prc->Height; y++)
719 for (x=0; x<prc->Width; x++)
720 pbBuffer[cbStride*y+4*x+3] = 0xff;
722 return S_OK;
723 case format_32bppRGBA:
724 if (prc)
726 HRESULT res;
727 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
728 if (FAILED(res)) return res;
729 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
731 return S_OK;
732 case format_32bppBGRA:
733 if (prc)
734 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
735 return S_OK;
736 case format_32bppPBGRA:
737 if (prc)
739 HRESULT res;
740 INT x, y;
742 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
743 if (FAILED(res)) return res;
745 for (y=0; y<prc->Height; y++)
746 for (x=0; x<prc->Width; x++)
748 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
749 if (alpha != 0 && alpha != 255)
751 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
752 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
753 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
757 return S_OK;
758 case format_48bppRGB:
759 if (prc)
761 HRESULT res;
762 INT x, y;
763 BYTE *srcdata;
764 UINT srcstride, srcdatasize;
765 const BYTE *srcrow;
766 const BYTE *srcpixel;
767 BYTE *dstrow;
768 DWORD *dstpixel;
770 srcstride = 6 * prc->Width;
771 srcdatasize = srcstride * prc->Height;
773 srcdata = malloc(srcdatasize);
774 if (!srcdata) return E_OUTOFMEMORY;
776 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
778 if (SUCCEEDED(res))
780 srcrow = srcdata;
781 dstrow = pbBuffer;
782 for (y=0; y<prc->Height; y++) {
783 srcpixel=srcrow;
784 dstpixel=(DWORD*)dstrow;
785 for (x=0; x<prc->Width; x++) {
786 BYTE red, green, blue;
787 srcpixel++; red = *srcpixel++;
788 srcpixel++; green = *srcpixel++;
789 srcpixel++; blue = *srcpixel++;
790 *dstpixel++=0xff000000|red<<16|green<<8|blue;
792 srcrow += srcstride;
793 dstrow += cbStride;
797 free(srcdata);
799 return res;
801 return S_OK;
802 case format_64bppRGBA:
803 if (prc)
805 HRESULT res;
806 INT x, y;
807 BYTE *srcdata;
808 UINT srcstride, srcdatasize;
809 const BYTE *srcrow;
810 const BYTE *srcpixel;
811 BYTE *dstrow;
812 DWORD *dstpixel;
814 srcstride = 8 * prc->Width;
815 srcdatasize = srcstride * prc->Height;
817 srcdata = malloc(srcdatasize);
818 if (!srcdata) return E_OUTOFMEMORY;
820 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
822 if (SUCCEEDED(res))
824 srcrow = srcdata;
825 dstrow = pbBuffer;
826 for (y=0; y<prc->Height; y++) {
827 srcpixel=srcrow;
828 dstpixel=(DWORD*)dstrow;
829 for (x=0; x<prc->Width; x++) {
830 BYTE red, green, blue, alpha;
831 srcpixel++; red = *srcpixel++;
832 srcpixel++; green = *srcpixel++;
833 srcpixel++; blue = *srcpixel++;
834 srcpixel++; alpha = *srcpixel++;
835 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
837 srcrow += srcstride;
838 dstrow += cbStride;
842 free(srcdata);
844 return res;
846 return S_OK;
847 case format_32bppCMYK:
848 if (prc)
850 HRESULT res;
851 UINT x, y;
853 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
854 if (FAILED(res)) return res;
856 for (y=0; y<prc->Height; y++)
857 for (x=0; x<prc->Width; x++)
859 BYTE *pixel = pbBuffer+cbStride*y+4*x;
860 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
861 pixel[0] = (255-y)*(255-k)/255; /* blue */
862 pixel[1] = (255-m)*(255-k)/255; /* green */
863 pixel[2] = (255-c)*(255-k)/255; /* red */
864 pixel[3] = 255; /* alpha */
867 return S_OK;
868 default:
869 FIXME("Unimplemented conversion path!\n");
870 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
874 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
875 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
877 HRESULT hr;
879 switch (source_format)
881 case format_32bppRGB:
882 if (prc)
884 INT x, y;
886 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
887 if (FAILED(hr)) return hr;
889 /* set all alpha values to 255 */
890 for (y=0; y<prc->Height; y++)
891 for (x=0; x<prc->Width; x++)
892 pbBuffer[cbStride*y+4*x+3] = 0xff;
894 return S_OK;
896 case format_32bppRGBA:
897 if (prc)
898 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
899 return S_OK;
901 case format_32bppPRGBA:
902 if (prc)
904 INT x, y;
906 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
907 if (FAILED(hr)) return hr;
909 for (y=0; y<prc->Height; y++)
910 for (x=0; x<prc->Width; x++)
912 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
913 if (alpha != 0 && alpha != 255)
915 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
916 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
917 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
921 return S_OK;
923 default:
924 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
925 if (SUCCEEDED(hr) && prc)
926 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
927 return hr;
931 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
932 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
934 switch (source_format)
936 case format_32bppBGR:
937 case format_32bppBGRA:
938 case format_32bppPBGRA:
939 if (prc)
940 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
941 return S_OK;
942 default:
943 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
947 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
948 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
950 switch (source_format)
952 case format_32bppRGB:
953 case format_32bppRGBA:
954 case format_32bppPRGBA:
955 if (prc)
956 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
957 return S_OK;
958 default:
959 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
963 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
964 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
966 HRESULT hr;
968 switch (source_format)
970 case format_32bppPBGRA:
971 if (prc)
972 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
973 return S_OK;
974 default:
975 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
976 if (SUCCEEDED(hr) && prc)
978 INT x, y;
980 for (y=0; y<prc->Height; y++)
981 for (x=0; x<prc->Width; x++)
983 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
984 if (alpha != 255)
986 pbBuffer[cbStride*y+4*x] = (pbBuffer[cbStride*y+4*x] * alpha + 127) / 255;
987 pbBuffer[cbStride*y+4*x+1] = (pbBuffer[cbStride*y+4*x+1] * alpha + 127) / 255;
988 pbBuffer[cbStride*y+4*x+2] = (pbBuffer[cbStride*y+4*x+2] * alpha + 127) / 255;
992 return hr;
996 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
997 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
999 HRESULT hr;
1001 switch (source_format)
1003 case format_32bppPRGBA:
1004 if (prc)
1005 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1006 return S_OK;
1007 default:
1008 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1009 if (SUCCEEDED(hr) && prc)
1011 INT x, y;
1013 for (y=0; y<prc->Height; y++)
1014 for (x=0; x<prc->Width; x++)
1016 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1017 if (alpha != 255)
1019 pbBuffer[cbStride*y+4*x] = (pbBuffer[cbStride*y+4*x] * alpha + 127) / 255;
1020 pbBuffer[cbStride*y+4*x+1] = (pbBuffer[cbStride*y+4*x+1] * alpha + 127) / 255;
1021 pbBuffer[cbStride*y+4*x+2] = (pbBuffer[cbStride*y+4*x+2] * alpha + 127) / 255;
1025 return hr;
1029 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1030 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1032 HRESULT hr;
1034 switch (source_format)
1036 case format_24bppBGR:
1037 case format_24bppRGB:
1038 if (prc)
1040 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1041 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1042 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1043 return hr;
1045 return S_OK;
1046 case format_32bppBGR:
1047 case format_32bppBGRA:
1048 case format_32bppPBGRA:
1049 case format_32bppRGBA:
1050 if (prc)
1052 HRESULT res;
1053 INT x, y;
1054 BYTE *srcdata;
1055 UINT srcstride, srcdatasize;
1056 const BYTE *srcrow;
1057 const BYTE *srcpixel;
1058 BYTE *dstrow;
1059 BYTE *dstpixel;
1061 srcstride = 4 * prc->Width;
1062 srcdatasize = srcstride * prc->Height;
1064 srcdata = malloc(srcdatasize);
1065 if (!srcdata) return E_OUTOFMEMORY;
1067 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1069 if (SUCCEEDED(res))
1071 srcrow = srcdata;
1072 dstrow = pbBuffer;
1074 if (source_format == format_32bppRGBA)
1076 for (y = 0; y < prc->Height; y++)
1078 srcpixel = srcrow;
1079 dstpixel = dstrow;
1080 for (x = 0; x < prc->Width; x++) {
1081 *dstpixel++ = srcpixel[2]; /* blue */
1082 *dstpixel++ = srcpixel[1]; /* green */
1083 *dstpixel++ = srcpixel[0]; /* red */
1084 srcpixel += 4;
1086 srcrow += srcstride;
1087 dstrow += cbStride;
1090 else
1092 for (y = 0; y < prc->Height; y++)
1094 srcpixel = srcrow;
1095 dstpixel = dstrow;
1096 for (x = 0; x < prc->Width; x++) {
1097 *dstpixel++ = *srcpixel++; /* blue */
1098 *dstpixel++ = *srcpixel++; /* green */
1099 *dstpixel++ = *srcpixel++; /* red */
1100 srcpixel++; /* alpha */
1102 srcrow += srcstride;
1103 dstrow += cbStride;
1108 free(srcdata);
1110 return res;
1112 return S_OK;
1114 case format_32bppGrayFloat:
1115 if (prc)
1117 BYTE *srcdata;
1118 UINT srcstride, srcdatasize;
1120 srcstride = 4 * prc->Width;
1121 srcdatasize = srcstride * prc->Height;
1123 srcdata = malloc(srcdatasize);
1124 if (!srcdata) return E_OUTOFMEMORY;
1126 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1128 if (SUCCEEDED(hr))
1130 INT x, y;
1131 BYTE *src = srcdata, *dst = pbBuffer;
1133 for (y = 0; y < prc->Height; y++)
1135 float *gray_float = (float *)src;
1136 BYTE *bgr = dst;
1138 for (x = 0; x < prc->Width; x++)
1140 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1141 *bgr++ = gray;
1142 *bgr++ = gray;
1143 *bgr++ = gray;
1145 src += srcstride;
1146 dst += cbStride;
1150 free(srcdata);
1152 return hr;
1154 return S_OK;
1156 case format_32bppCMYK:
1157 if (prc)
1159 BYTE *srcdata;
1160 UINT srcstride, srcdatasize;
1162 srcstride = 4 * prc->Width;
1163 srcdatasize = srcstride * prc->Height;
1165 srcdata = malloc(srcdatasize);
1166 if (!srcdata) return E_OUTOFMEMORY;
1168 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1169 if (SUCCEEDED(hr))
1171 INT x, y;
1172 BYTE *src = srcdata, *dst = pbBuffer;
1174 for (y = 0; y < prc->Height; y++)
1176 BYTE *cmyk = src;
1177 BYTE *bgr = dst;
1179 for (x = 0; x < prc->Width; x++)
1181 BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
1182 bgr[0] = (255 - y) * (255 - k) / 255; /* B */
1183 bgr[1] = (255 - m) * (255 - k) / 255; /* G */
1184 bgr[2] = (255 - c) * (255 - k) / 255; /* R */
1185 cmyk += 4;
1186 bgr += 3;
1188 src += srcstride;
1189 dst += cbStride;
1193 free(srcdata);
1194 return hr;
1196 return S_OK;
1198 default:
1199 FIXME("Unimplemented conversion path!\n");
1200 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1204 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1205 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1207 HRESULT hr;
1209 switch (source_format)
1211 case format_24bppBGR:
1212 case format_24bppRGB:
1213 if (prc)
1215 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1216 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1217 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1218 return hr;
1220 return S_OK;
1221 case format_32bppBGR:
1222 case format_32bppBGRA:
1223 case format_32bppPBGRA:
1224 if (prc)
1226 HRESULT res;
1227 INT x, y;
1228 BYTE *srcdata;
1229 UINT srcstride, srcdatasize;
1230 const BYTE *srcrow;
1231 const BYTE *srcpixel;
1232 BYTE *dstrow;
1233 BYTE *dstpixel;
1234 BYTE tmppixel[3];
1236 srcstride = 4 * prc->Width;
1237 srcdatasize = srcstride * prc->Height;
1239 srcdata = malloc(srcdatasize);
1240 if (!srcdata) return E_OUTOFMEMORY;
1242 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1244 if (SUCCEEDED(res))
1246 srcrow = srcdata;
1247 dstrow = pbBuffer;
1248 for (y=0; y<prc->Height; y++) {
1249 srcpixel=srcrow;
1250 dstpixel=dstrow;
1251 for (x=0; x<prc->Width; x++) {
1252 tmppixel[0]=*srcpixel++; /* blue */
1253 tmppixel[1]=*srcpixel++; /* green */
1254 tmppixel[2]=*srcpixel++; /* red */
1255 srcpixel++; /* alpha */
1257 *dstpixel++=tmppixel[2]; /* red */
1258 *dstpixel++=tmppixel[1]; /* green */
1259 *dstpixel++=tmppixel[0]; /* blue */
1261 srcrow += srcstride;
1262 dstrow += cbStride;
1266 free(srcdata);
1268 return res;
1270 return S_OK;
1271 default:
1272 FIXME("Unimplemented conversion path!\n");
1273 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1277 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1278 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1280 HRESULT hr;
1282 switch (source_format)
1284 case format_32bppBGR:
1285 case format_32bppBGRA:
1286 case format_32bppPBGRA:
1287 case format_32bppGrayFloat:
1288 if (prc)
1290 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1291 break;
1293 return S_OK;
1295 default:
1296 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1297 break;
1300 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1302 INT x, y;
1303 BYTE *p = pbBuffer;
1305 for (y = 0; y < prc->Height; y++)
1307 BYTE *bgr = p;
1308 for (x = 0; x < prc->Width; x++)
1310 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1311 *(float *)bgr = gray;
1312 bgr += 4;
1314 p += cbStride;
1317 return hr;
1320 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1321 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1323 HRESULT hr;
1324 BYTE *srcdata;
1325 UINT srcstride, srcdatasize;
1327 if (source_format == format_8bppGray)
1329 if (prc)
1330 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1332 return S_OK;
1335 if (source_format == format_32bppGrayFloat)
1337 hr = S_OK;
1339 if (prc)
1341 srcstride = 4 * prc->Width;
1342 srcdatasize = srcstride * prc->Height;
1344 srcdata = malloc(srcdatasize);
1345 if (!srcdata) return E_OUTOFMEMORY;
1347 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1348 if (SUCCEEDED(hr))
1350 INT x, y;
1351 BYTE *src = srcdata, *dst = pbBuffer;
1353 for (y=0; y < prc->Height; y++)
1355 float *srcpixel = (float*)src;
1356 BYTE *dstpixel = dst;
1358 for (x=0; x < prc->Width; x++)
1359 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1361 src += srcstride;
1362 dst += cbStride;
1366 free(srcdata);
1369 return hr;
1372 if (!prc)
1373 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1375 srcstride = 3 * prc->Width;
1376 srcdatasize = srcstride * prc->Height;
1378 srcdata = malloc(srcdatasize);
1379 if (!srcdata) return E_OUTOFMEMORY;
1381 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1382 if (SUCCEEDED(hr))
1384 INT x, y;
1385 BYTE *src = srcdata, *dst = pbBuffer;
1387 for (y = 0; y < prc->Height; y++)
1389 BYTE *bgr = src;
1391 for (x = 0; x < prc->Width; x++)
1393 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1395 gray = to_sRGB_component(gray) * 255.0f;
1396 dst[x] = (BYTE)floorf(gray + 0.51f);
1397 bgr += 3;
1399 src += srcstride;
1400 dst += cbStride;
1404 free(srcdata);
1405 return hr;
1408 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1410 UINT best_diff, best_index, i;
1412 best_diff = ~0;
1413 best_index = 0;
1415 for (i = 0; i < count; i++)
1417 BYTE pal_r, pal_g, pal_b;
1418 UINT diff_r, diff_g, diff_b, diff;
1420 pal_r = colors[i] >> 16;
1421 pal_g = colors[i] >> 8;
1422 pal_b = colors[i];
1424 diff_r = bgr[2] - pal_r;
1425 diff_g = bgr[1] - pal_g;
1426 diff_b = bgr[0] - pal_b;
1428 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1429 if (diff == 0) return i;
1431 if (diff < best_diff)
1433 best_diff = diff;
1434 best_index = i;
1438 return best_index;
1441 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1442 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1444 HRESULT hr;
1445 BYTE *srcdata;
1446 WICColor colors[256];
1447 UINT srcstride, srcdatasize, count;
1449 if (source_format == format_8bppIndexed)
1451 if (prc)
1452 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1454 return S_OK;
1457 if (!prc)
1458 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1460 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1462 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1463 if (hr != S_OK) return hr;
1465 srcstride = 3 * prc->Width;
1466 srcdatasize = srcstride * prc->Height;
1468 srcdata = malloc(srcdatasize);
1469 if (!srcdata) return E_OUTOFMEMORY;
1471 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1472 if (SUCCEEDED(hr))
1474 INT x, y;
1475 BYTE *src = srcdata, *dst = pbBuffer;
1477 for (y = 0; y < prc->Height; y++)
1479 BYTE *bgr = src;
1481 for (x = 0; x < prc->Width; x++)
1483 dst[x] = rgb_to_palette_index(bgr, colors, count);
1484 bgr += 3;
1486 src += srcstride;
1487 dst += cbStride;
1491 free(srcdata);
1492 return hr;
1495 static HRESULT copypixels_to_16bppBGRA5551(struct FormatConverter *This, const WICRect *prc,
1496 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1498 switch (source_format)
1500 case format_16bppBGRA5551:
1501 if (prc)
1502 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1503 return S_OK;
1504 case format_32bppBGRA:
1505 if(prc)
1507 HRESULT res;
1508 INT x, y;
1509 BYTE *srcdata;
1510 UINT srcstride, srcdatasize;
1511 const BYTE *srcrow;
1512 const DWORD *srcpixel;
1513 BYTE *dstrow;
1514 DWORD srcval = 0;
1515 WORD *dstpixel;
1517 int a, r, g, b;
1519 srcstride = 4 * prc->Width;
1520 srcdatasize = srcstride * prc->Height;
1522 srcdata = malloc(srcdatasize);
1523 if (!srcdata) return E_OUTOFMEMORY;
1525 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1526 if(SUCCEEDED(res))
1528 srcrow = srcdata;
1529 dstrow = pbBuffer;
1530 for(y=0; y< prc->Height; y++) {
1531 srcpixel = (const DWORD*)srcrow;
1532 dstpixel = (WORD *)dstrow;
1533 for(x=0; x<prc->Width; x++) {
1534 srcval=*srcpixel++;
1535 a = (srcval & 0xff000000) >> 24;
1536 r = (srcval & 0x00ff0000) >> 16;
1537 g = (srcval & 0x0000ff00) >> 8;
1538 b = (srcval & 0x000000ff);
1539 a = (a >> 7) << 15;
1540 r = (r >> 3) << 10;
1541 g = (g >> 3) << 5;
1542 b = (b >> 3);
1543 *dstpixel++ = (a|r|g|b);
1545 srcrow += srcstride;
1546 dstrow += cbStride;
1549 free(srcdata);
1551 return S_OK;
1552 default:
1553 FIXME("Unimplemented conversion path! %d\n", source_format);
1554 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1558 static const struct pixelformatinfo supported_formats[] = {
1559 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL, TRUE},
1560 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL, TRUE},
1561 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL, TRUE},
1562 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed, TRUE},
1563 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1564 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1565 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1566 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1567 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1568 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1569 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1570 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, copypixels_to_16bppBGRA5551},
1571 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1572 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1573 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1574 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1575 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1576 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1577 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1578 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1579 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1580 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1581 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1582 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1586 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1588 UINT i;
1590 for (i=0; supported_formats[i].guid; i++)
1591 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1593 return NULL;
1596 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1597 void **ppv)
1599 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1600 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1602 if (!ppv) return E_INVALIDARG;
1604 if (IsEqualIID(&IID_IUnknown, iid) ||
1605 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1606 IsEqualIID(&IID_IWICFormatConverter, iid))
1608 *ppv = &This->IWICFormatConverter_iface;
1610 else
1612 *ppv = NULL;
1613 return E_NOINTERFACE;
1616 IUnknown_AddRef((IUnknown*)*ppv);
1617 return S_OK;
1620 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1622 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1623 ULONG ref = InterlockedIncrement(&This->ref);
1625 TRACE("(%p) refcount=%lu\n", iface, ref);
1627 return ref;
1630 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1632 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1633 ULONG ref = InterlockedDecrement(&This->ref);
1635 TRACE("(%p) refcount=%lu\n", iface, ref);
1637 if (ref == 0)
1639 This->lock.DebugInfo->Spare[0] = 0;
1640 DeleteCriticalSection(&This->lock);
1641 if (This->source) IWICBitmapSource_Release(This->source);
1642 if (This->palette) IWICPalette_Release(This->palette);
1643 free(This);
1646 return ref;
1649 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1650 UINT *puiWidth, UINT *puiHeight)
1652 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1654 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1656 if (This->source)
1657 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1658 else
1659 return WINCODEC_ERR_NOTINITIALIZED;
1662 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1663 WICPixelFormatGUID *pPixelFormat)
1665 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1667 TRACE("(%p,%p)\n", iface, pPixelFormat);
1669 if (This->source)
1670 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1671 else
1672 return WINCODEC_ERR_NOTINITIALIZED;
1674 return S_OK;
1677 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1678 double *pDpiX, double *pDpiY)
1680 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1682 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1684 if (This->source)
1685 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1686 else
1687 return WINCODEC_ERR_NOTINITIALIZED;
1690 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1691 IWICPalette *palette)
1693 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1695 TRACE("(%p,%p)\n", iface, palette);
1697 if (!palette) return E_INVALIDARG;
1698 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1700 if (!This->palette)
1702 if (This->dst_format->is_indexed_format) return WINCODEC_ERR_WRONGSTATE;
1703 return IWICBitmapSource_CopyPalette(This->source, palette);
1706 return IWICPalette_InitializeFromPalette(palette, This->palette);
1709 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1710 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1712 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1713 WICRect rc;
1714 HRESULT hr;
1715 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1717 if (This->source)
1719 if (!prc)
1721 UINT width, height;
1722 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1723 if (FAILED(hr)) return hr;
1724 rc.X = 0;
1725 rc.Y = 0;
1726 rc.Width = width;
1727 rc.Height = height;
1728 prc = &rc;
1731 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1732 pbBuffer, This->src_format->format);
1734 else
1735 return WINCODEC_ERR_WRONGSTATE;
1738 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1739 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1740 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1742 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1743 const struct pixelformatinfo *srcinfo, *dstinfo;
1744 GUID srcFormat;
1745 HRESULT res;
1747 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1748 dither, palette, alpha_threshold, palette_type);
1750 dstinfo = get_formatinfo(dstFormat);
1751 if (!dstinfo)
1753 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1754 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1757 if (!palette)
1759 UINT bpp;
1760 res = get_pixelformat_bpp(dstFormat, &bpp);
1761 if (res != S_OK) return res;
1763 res = PaletteImpl_Create(&palette);
1764 if (res != S_OK) return res;
1766 switch (palette_type)
1768 case WICBitmapPaletteTypeCustom:
1769 IWICPalette_Release(palette);
1770 palette = NULL;
1772 /* Indexed types require a palette */
1773 if (dstinfo->is_indexed_format)
1774 return E_INVALIDARG;
1775 break;
1777 case WICBitmapPaletteTypeMedianCut:
1779 if (dstinfo->is_indexed_format)
1780 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1781 break;
1784 default:
1785 if (dstinfo->is_indexed_format)
1786 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1787 break;
1790 if (res != S_OK)
1792 IWICPalette_Release(palette);
1793 return res;
1796 else
1797 IWICPalette_AddRef(palette);
1799 EnterCriticalSection(&This->lock);
1801 if (This->source)
1803 res = WINCODEC_ERR_WRONGSTATE;
1804 goto end;
1807 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1808 if (FAILED(res)) goto end;
1810 srcinfo = get_formatinfo(&srcFormat);
1811 if (!srcinfo)
1813 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1814 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1815 goto end;
1818 if (dstinfo->copy_function)
1820 IWICBitmapSource_AddRef(source);
1821 This->src_format = srcinfo;
1822 This->dst_format = dstinfo;
1823 This->dither = dither;
1824 This->alpha_threshold = alpha_threshold;
1825 This->palette = palette;
1826 This->source = source;
1828 else
1830 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1831 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1834 end:
1836 LeaveCriticalSection(&This->lock);
1838 if (res != S_OK && palette)
1839 IWICPalette_Release(palette);
1841 return res;
1844 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1845 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1846 BOOL *pfCanConvert)
1848 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1849 const struct pixelformatinfo *srcinfo, *dstinfo;
1851 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1852 debugstr_guid(dstPixelFormat), pfCanConvert);
1854 srcinfo = get_formatinfo(srcPixelFormat);
1855 if (!srcinfo)
1857 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1858 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1861 dstinfo = get_formatinfo(dstPixelFormat);
1862 if (!dstinfo)
1864 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1865 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1868 if (dstinfo->copy_function &&
1869 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1870 *pfCanConvert = TRUE;
1871 else
1873 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1874 *pfCanConvert = FALSE;
1877 return S_OK;
1880 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1881 FormatConverter_QueryInterface,
1882 FormatConverter_AddRef,
1883 FormatConverter_Release,
1884 FormatConverter_GetSize,
1885 FormatConverter_GetPixelFormat,
1886 FormatConverter_GetResolution,
1887 FormatConverter_CopyPalette,
1888 FormatConverter_CopyPixels,
1889 FormatConverter_Initialize,
1890 FormatConverter_CanConvert
1893 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1895 FormatConverter *This;
1896 HRESULT ret;
1898 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1900 *ppv = NULL;
1902 This = malloc(sizeof(FormatConverter));
1903 if (!This) return E_OUTOFMEMORY;
1905 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1906 This->ref = 1;
1907 This->source = NULL;
1908 This->palette = NULL;
1909 InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO);
1910 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1912 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1913 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1915 return ret;