mfplat: Remove duplicated GUID entry from attribute tracing.
[wine/zf.git] / dlls / windowscodecs / converter.c
blobc321627885bc98b1be4fbaea3317f160efeff2c2
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/heap.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 struct FormatConverter;
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_32bppGrayFloat,
54 format_32bppBGR,
55 format_32bppRGB,
56 format_32bppBGRA,
57 format_32bppRGBA,
58 format_32bppPBGRA,
59 format_32bppPRGBA,
60 format_48bppRGB,
61 format_64bppRGBA,
62 format_32bppCMYK,
65 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
66 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
68 struct pixelformatinfo {
69 enum pixelformat format;
70 const WICPixelFormatGUID *guid;
71 copyfunc copy_function;
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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 / 255;
987 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
988 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 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 / 255;
1020 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1021 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = heap_alloc(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 heap_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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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 HeapFree(GetProcessHeap(), 0, srcdata);
1492 return hr;
1495 static const struct pixelformatinfo supported_formats[] = {
1496 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1497 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1498 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1499 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1500 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1501 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1502 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1503 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1504 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1505 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1506 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1507 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1508 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1509 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1510 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1511 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1512 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1513 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1514 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1515 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1516 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1517 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1518 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1519 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1523 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1525 UINT i;
1527 for (i=0; supported_formats[i].guid; i++)
1528 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1530 return NULL;
1533 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1534 void **ppv)
1536 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1537 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1539 if (!ppv) return E_INVALIDARG;
1541 if (IsEqualIID(&IID_IUnknown, iid) ||
1542 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1543 IsEqualIID(&IID_IWICFormatConverter, iid))
1545 *ppv = &This->IWICFormatConverter_iface;
1547 else
1549 *ppv = NULL;
1550 return E_NOINTERFACE;
1553 IUnknown_AddRef((IUnknown*)*ppv);
1554 return S_OK;
1557 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1559 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1560 ULONG ref = InterlockedIncrement(&This->ref);
1562 TRACE("(%p) refcount=%u\n", iface, ref);
1564 return ref;
1567 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1569 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1570 ULONG ref = InterlockedDecrement(&This->ref);
1572 TRACE("(%p) refcount=%u\n", iface, ref);
1574 if (ref == 0)
1576 This->lock.DebugInfo->Spare[0] = 0;
1577 DeleteCriticalSection(&This->lock);
1578 if (This->source) IWICBitmapSource_Release(This->source);
1579 if (This->palette) IWICPalette_Release(This->palette);
1580 HeapFree(GetProcessHeap(), 0, This);
1583 return ref;
1586 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1587 UINT *puiWidth, UINT *puiHeight)
1589 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1591 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1593 if (This->source)
1594 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1595 else
1596 return WINCODEC_ERR_NOTINITIALIZED;
1599 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1600 WICPixelFormatGUID *pPixelFormat)
1602 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1604 TRACE("(%p,%p)\n", iface, pPixelFormat);
1606 if (This->source)
1607 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1608 else
1609 return WINCODEC_ERR_NOTINITIALIZED;
1611 return S_OK;
1614 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1615 double *pDpiX, double *pDpiY)
1617 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1619 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1621 if (This->source)
1622 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1623 else
1624 return WINCODEC_ERR_NOTINITIALIZED;
1627 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1628 IWICPalette *palette)
1630 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1632 TRACE("(%p,%p)\n", iface, palette);
1634 if (!palette) return E_INVALIDARG;
1635 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1637 if (!This->palette)
1639 HRESULT hr;
1640 UINT bpp;
1642 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1643 if (hr != S_OK) return hr;
1644 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1645 return IWICBitmapSource_CopyPalette(This->source, palette);
1648 return IWICPalette_InitializeFromPalette(palette, This->palette);
1651 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1652 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1654 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1655 WICRect rc;
1656 HRESULT hr;
1657 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1659 if (This->source)
1661 if (!prc)
1663 UINT width, height;
1664 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1665 if (FAILED(hr)) return hr;
1666 rc.X = 0;
1667 rc.Y = 0;
1668 rc.Width = width;
1669 rc.Height = height;
1670 prc = &rc;
1673 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1674 pbBuffer, This->src_format->format);
1676 else
1677 return WINCODEC_ERR_WRONGSTATE;
1680 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1681 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1682 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1684 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1685 const struct pixelformatinfo *srcinfo, *dstinfo;
1686 GUID srcFormat;
1687 HRESULT res;
1689 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1690 dither, palette, alpha_threshold, palette_type);
1692 if (!palette)
1694 UINT bpp;
1695 res = get_pixelformat_bpp(dstFormat, &bpp);
1696 if (res != S_OK) return res;
1698 res = PaletteImpl_Create(&palette);
1699 if (res != S_OK) return res;
1701 switch (palette_type)
1703 case WICBitmapPaletteTypeCustom:
1704 IWICPalette_Release(palette);
1705 palette = NULL;
1706 if (bpp <= 8) return E_INVALIDARG;
1707 break;
1709 case WICBitmapPaletteTypeMedianCut:
1711 if (bpp <= 8)
1712 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1713 break;
1716 default:
1717 if (bpp <= 8)
1718 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1719 break;
1722 if (res != S_OK)
1724 IWICPalette_Release(palette);
1725 return res;
1728 else
1729 IWICPalette_AddRef(palette);
1731 EnterCriticalSection(&This->lock);
1733 if (This->source)
1735 res = WINCODEC_ERR_WRONGSTATE;
1736 goto end;
1739 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1740 if (FAILED(res)) goto end;
1742 srcinfo = get_formatinfo(&srcFormat);
1743 if (!srcinfo)
1745 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1746 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1747 goto end;
1750 dstinfo = get_formatinfo(dstFormat);
1751 if (!dstinfo)
1753 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1754 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1755 goto end;
1758 if (dstinfo->copy_function)
1760 IWICBitmapSource_AddRef(source);
1761 This->src_format = srcinfo;
1762 This->dst_format = dstinfo;
1763 This->dither = dither;
1764 This->alpha_threshold = alpha_threshold;
1765 This->palette = palette;
1766 This->source = source;
1768 else
1770 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1771 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1774 end:
1776 LeaveCriticalSection(&This->lock);
1778 if (res != S_OK && palette)
1779 IWICPalette_Release(palette);
1781 return res;
1784 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1785 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1786 BOOL *pfCanConvert)
1788 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1789 const struct pixelformatinfo *srcinfo, *dstinfo;
1791 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1792 debugstr_guid(dstPixelFormat), pfCanConvert);
1794 srcinfo = get_formatinfo(srcPixelFormat);
1795 if (!srcinfo)
1797 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1798 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1801 dstinfo = get_formatinfo(dstPixelFormat);
1802 if (!dstinfo)
1804 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1805 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1808 if (dstinfo->copy_function &&
1809 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1810 *pfCanConvert = TRUE;
1811 else
1813 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1814 *pfCanConvert = FALSE;
1817 return S_OK;
1820 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1821 FormatConverter_QueryInterface,
1822 FormatConverter_AddRef,
1823 FormatConverter_Release,
1824 FormatConverter_GetSize,
1825 FormatConverter_GetPixelFormat,
1826 FormatConverter_GetResolution,
1827 FormatConverter_CopyPalette,
1828 FormatConverter_CopyPixels,
1829 FormatConverter_Initialize,
1830 FormatConverter_CanConvert
1833 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1835 FormatConverter *This;
1836 HRESULT ret;
1838 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1840 *ppv = NULL;
1842 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1843 if (!This) return E_OUTOFMEMORY;
1845 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1846 This->ref = 1;
1847 This->source = NULL;
1848 This->palette = NULL;
1849 InitializeCriticalSection(&This->lock);
1850 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1852 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1853 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1855 return ret;