kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / windowscodecs / converter.c
blob9083aa04f731ad18a55e7a94b5282b589e50885d
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 "config.h"
22 #include <stdarg.h>
23 #include <math.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37 struct FormatConverter;
39 enum pixelformat {
40 format_1bppIndexed,
41 format_2bppIndexed,
42 format_4bppIndexed,
43 format_8bppIndexed,
44 format_BlackWhite,
45 format_2bppGray,
46 format_4bppGray,
47 format_8bppGray,
48 format_16bppGray,
49 format_16bppBGR555,
50 format_16bppBGR565,
51 format_16bppBGRA5551,
52 format_24bppBGR,
53 format_24bppRGB,
54 format_32bppGrayFloat,
55 format_32bppBGR,
56 format_32bppRGB,
57 format_32bppBGRA,
58 format_32bppRGBA,
59 format_32bppPBGRA,
60 format_32bppPRGBA,
61 format_48bppRGB,
62 format_64bppRGBA,
63 format_32bppCMYK,
66 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
67 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
69 struct pixelformatinfo {
70 enum pixelformat format;
71 const WICPixelFormatGUID *guid;
72 copyfunc copy_function;
75 typedef struct FormatConverter {
76 IWICFormatConverter IWICFormatConverter_iface;
77 LONG ref;
78 IWICBitmapSource *source;
79 const struct pixelformatinfo *dst_format, *src_format;
80 WICBitmapDitherType dither;
81 double alpha_threshold;
82 IWICPalette *palette;
83 CRITICAL_SECTION lock; /* must be held when initialized */
84 } FormatConverter;
86 /* https://www.w3.org/Graphics/Color/srgb */
87 static inline float from_sRGB_component(float f)
89 if (f <= 0.04045f) return f / 12.92f;
90 return powf((f + 0.055f) / 1.055f, 2.4f);
93 static inline float to_sRGB_component(float f)
95 if (f <= 0.0031308f) return 12.92f * f;
96 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
99 #if 0 /* FIXME: enable once needed */
100 static void from_sRGB(BYTE *bgr)
102 float r, g, b;
104 r = bgr[2] / 255.0f;
105 g = bgr[1] / 255.0f;
106 b = bgr[0] / 255.0f;
108 r = from_sRGB_component(r);
109 g = from_sRGB_component(g);
110 b = from_sRGB_component(b);
112 bgr[2] = (BYTE)(r * 255.0f);
113 bgr[1] = (BYTE)(g * 255.0f);
114 bgr[0] = (BYTE)(b * 255.0f);
117 static void to_sRGB(BYTE *bgr)
119 float r, g, b;
121 r = bgr[2] / 255.0f;
122 g = bgr[1] / 255.0f;
123 b = bgr[0] / 255.0f;
125 r = to_sRGB_component(r);
126 g = to_sRGB_component(g);
127 b = to_sRGB_component(b);
129 bgr[2] = (BYTE)(r * 255.0f);
130 bgr[1] = (BYTE)(g * 255.0f);
131 bgr[0] = (BYTE)(b * 255.0f);
133 #endif
135 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
137 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
140 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
141 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
143 switch (source_format)
145 case format_1bppIndexed:
146 case format_BlackWhite:
147 if (prc)
149 HRESULT res;
150 INT x, y;
151 BYTE *srcdata;
152 UINT srcstride, srcdatasize;
153 const BYTE *srcrow;
154 const BYTE *srcbyte;
155 BYTE *dstrow;
156 DWORD *dstpixel;
157 WICColor colors[2];
158 IWICPalette *palette;
159 UINT actualcolors;
161 res = PaletteImpl_Create(&palette);
162 if (FAILED(res)) return res;
164 if (source_format == format_1bppIndexed)
165 res = IWICBitmapSource_CopyPalette(This->source, palette);
166 else
167 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
169 if (SUCCEEDED(res))
170 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
172 IWICPalette_Release(palette);
173 if (FAILED(res)) return res;
175 srcstride = (prc->Width+7)/8;
176 srcdatasize = srcstride * prc->Height;
178 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
179 if (!srcdata) return E_OUTOFMEMORY;
181 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
183 if (SUCCEEDED(res))
185 srcrow = srcdata;
186 dstrow = pbBuffer;
187 for (y=0; y<prc->Height; y++) {
188 srcbyte = srcrow;
189 dstpixel=(DWORD*)dstrow;
190 for (x=0; x<prc->Width; x+=8) {
191 BYTE srcval;
192 srcval=*srcbyte++;
193 *dstpixel++ = colors[srcval>>7&1];
194 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
195 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
196 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
197 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
198 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
199 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
200 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
202 srcrow += srcstride;
203 dstrow += cbStride;
207 HeapFree(GetProcessHeap(), 0, srcdata);
209 return res;
211 return S_OK;
212 case format_2bppIndexed:
213 case format_2bppGray:
214 if (prc)
216 HRESULT res;
217 INT x, y;
218 BYTE *srcdata;
219 UINT srcstride, srcdatasize;
220 const BYTE *srcrow;
221 const BYTE *srcbyte;
222 BYTE *dstrow;
223 DWORD *dstpixel;
224 WICColor colors[4];
225 IWICPalette *palette;
226 UINT actualcolors;
228 res = PaletteImpl_Create(&palette);
229 if (FAILED(res)) return res;
231 if (source_format == format_2bppIndexed)
232 res = IWICBitmapSource_CopyPalette(This->source, palette);
233 else
234 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
236 if (SUCCEEDED(res))
237 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
239 IWICPalette_Release(palette);
240 if (FAILED(res)) return res;
242 srcstride = (prc->Width+3)/4;
243 srcdatasize = srcstride * prc->Height;
245 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
246 if (!srcdata) return E_OUTOFMEMORY;
248 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
250 if (SUCCEEDED(res))
252 srcrow = srcdata;
253 dstrow = pbBuffer;
254 for (y=0; y<prc->Height; y++) {
255 srcbyte = srcrow;
256 dstpixel=(DWORD*)dstrow;
257 for (x=0; x<prc->Width; x+=4) {
258 BYTE srcval;
259 srcval=*srcbyte++;
260 *dstpixel++ = colors[srcval>>6];
261 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
262 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
263 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
265 srcrow += srcstride;
266 dstrow += cbStride;
270 HeapFree(GetProcessHeap(), 0, srcdata);
272 return res;
274 return S_OK;
275 case format_4bppIndexed:
276 case format_4bppGray:
277 if (prc)
279 HRESULT res;
280 INT x, y;
281 BYTE *srcdata;
282 UINT srcstride, srcdatasize;
283 const BYTE *srcrow;
284 const BYTE *srcbyte;
285 BYTE *dstrow;
286 DWORD *dstpixel;
287 WICColor colors[16];
288 IWICPalette *palette;
289 UINT actualcolors;
291 res = PaletteImpl_Create(&palette);
292 if (FAILED(res)) return res;
294 if (source_format == format_4bppIndexed)
295 res = IWICBitmapSource_CopyPalette(This->source, palette);
296 else
297 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
299 if (SUCCEEDED(res))
300 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
302 IWICPalette_Release(palette);
303 if (FAILED(res)) return res;
305 srcstride = (prc->Width+1)/2;
306 srcdatasize = srcstride * prc->Height;
308 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
309 if (!srcdata) return E_OUTOFMEMORY;
311 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
313 if (SUCCEEDED(res))
315 srcrow = srcdata;
316 dstrow = pbBuffer;
317 for (y=0; y<prc->Height; y++) {
318 srcbyte = srcrow;
319 dstpixel=(DWORD*)dstrow;
320 for (x=0; x<prc->Width; x+=2) {
321 BYTE srcval;
322 srcval=*srcbyte++;
323 *dstpixel++ = colors[srcval>>4];
324 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
326 srcrow += srcstride;
327 dstrow += cbStride;
331 HeapFree(GetProcessHeap(), 0, srcdata);
333 return res;
335 return S_OK;
336 case format_8bppGray:
337 if (prc)
339 HRESULT res;
340 INT x, y;
341 BYTE *srcdata;
342 UINT srcstride, srcdatasize;
343 const BYTE *srcrow;
344 const BYTE *srcbyte;
345 BYTE *dstrow;
346 DWORD *dstpixel;
348 srcstride = prc->Width;
349 srcdatasize = srcstride * prc->Height;
351 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
352 if (!srcdata) return E_OUTOFMEMORY;
354 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
356 if (SUCCEEDED(res))
358 srcrow = srcdata;
359 dstrow = pbBuffer;
360 for (y=0; y<prc->Height; y++) {
361 srcbyte = srcrow;
362 dstpixel=(DWORD*)dstrow;
363 for (x=0; x<prc->Width; x++)
365 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
366 srcbyte++;
368 srcrow += srcstride;
369 dstrow += cbStride;
373 HeapFree(GetProcessHeap(), 0, srcdata);
375 return res;
377 return S_OK;
378 case format_8bppIndexed:
379 if (prc)
381 HRESULT res;
382 INT x, y;
383 BYTE *srcdata;
384 UINT srcstride, srcdatasize;
385 const BYTE *srcrow;
386 const BYTE *srcbyte;
387 BYTE *dstrow;
388 DWORD *dstpixel;
389 WICColor colors[256];
390 IWICPalette *palette;
391 UINT actualcolors;
393 res = PaletteImpl_Create(&palette);
394 if (FAILED(res)) return res;
396 res = IWICBitmapSource_CopyPalette(This->source, palette);
397 if (SUCCEEDED(res))
398 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
400 IWICPalette_Release(palette);
402 if (FAILED(res)) return res;
404 srcstride = prc->Width;
405 srcdatasize = srcstride * prc->Height;
407 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
408 if (!srcdata) return E_OUTOFMEMORY;
410 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
412 if (SUCCEEDED(res))
414 srcrow = srcdata;
415 dstrow = pbBuffer;
416 for (y=0; y<prc->Height; y++) {
417 srcbyte = srcrow;
418 dstpixel=(DWORD*)dstrow;
419 for (x=0; x<prc->Width; x++)
420 *dstpixel++ = colors[*srcbyte++];
421 srcrow += srcstride;
422 dstrow += cbStride;
426 HeapFree(GetProcessHeap(), 0, srcdata);
428 return res;
430 return S_OK;
431 case format_16bppGray:
432 if (prc)
434 HRESULT res;
435 INT x, y;
436 BYTE *srcdata;
437 UINT srcstride, srcdatasize;
438 const BYTE *srcrow;
439 const BYTE *srcbyte;
440 BYTE *dstrow;
441 DWORD *dstpixel;
443 srcstride = prc->Width * 2;
444 srcdatasize = srcstride * prc->Height;
446 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
447 if (!srcdata) return E_OUTOFMEMORY;
449 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
451 if (SUCCEEDED(res))
453 srcrow = srcdata;
454 dstrow = pbBuffer;
455 for (y=0; y<prc->Height; y++) {
456 srcbyte = srcrow;
457 dstpixel=(DWORD*)dstrow;
458 for (x=0; x<prc->Width; x++)
460 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
461 srcbyte+=2;
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_32bppBGRA:
724 if (prc)
725 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
726 return S_OK;
727 case format_32bppPBGRA:
728 if (prc)
730 HRESULT res;
731 INT x, y;
733 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
734 if (FAILED(res)) return res;
736 for (y=0; y<prc->Height; y++)
737 for (x=0; x<prc->Width; x++)
739 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
740 if (alpha != 0 && alpha != 255)
742 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
743 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
744 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
748 return S_OK;
749 case format_48bppRGB:
750 if (prc)
752 HRESULT res;
753 INT x, y;
754 BYTE *srcdata;
755 UINT srcstride, srcdatasize;
756 const BYTE *srcrow;
757 const BYTE *srcpixel;
758 BYTE *dstrow;
759 DWORD *dstpixel;
761 srcstride = 6 * prc->Width;
762 srcdatasize = srcstride * prc->Height;
764 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
765 if (!srcdata) return E_OUTOFMEMORY;
767 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
769 if (SUCCEEDED(res))
771 srcrow = srcdata;
772 dstrow = pbBuffer;
773 for (y=0; y<prc->Height; y++) {
774 srcpixel=srcrow;
775 dstpixel=(DWORD*)dstrow;
776 for (x=0; x<prc->Width; x++) {
777 BYTE red, green, blue;
778 red = *srcpixel++; srcpixel++;
779 green = *srcpixel++; srcpixel++;
780 blue = *srcpixel++; srcpixel++;
781 *dstpixel++=0xff000000|red<<16|green<<8|blue;
783 srcrow += srcstride;
784 dstrow += cbStride;
788 HeapFree(GetProcessHeap(), 0, srcdata);
790 return res;
792 return S_OK;
793 case format_64bppRGBA:
794 if (prc)
796 HRESULT res;
797 INT x, y;
798 BYTE *srcdata;
799 UINT srcstride, srcdatasize;
800 const BYTE *srcrow;
801 const BYTE *srcpixel;
802 BYTE *dstrow;
803 DWORD *dstpixel;
805 srcstride = 8 * prc->Width;
806 srcdatasize = srcstride * prc->Height;
808 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
809 if (!srcdata) return E_OUTOFMEMORY;
811 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
813 if (SUCCEEDED(res))
815 srcrow = srcdata;
816 dstrow = pbBuffer;
817 for (y=0; y<prc->Height; y++) {
818 srcpixel=srcrow;
819 dstpixel=(DWORD*)dstrow;
820 for (x=0; x<prc->Width; x++) {
821 BYTE red, green, blue, alpha;
822 red = *srcpixel++; srcpixel++;
823 green = *srcpixel++; srcpixel++;
824 blue = *srcpixel++; srcpixel++;
825 alpha = *srcpixel++; srcpixel++;
826 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
828 srcrow += srcstride;
829 dstrow += cbStride;
833 HeapFree(GetProcessHeap(), 0, srcdata);
835 return res;
837 return S_OK;
838 case format_32bppCMYK:
839 if (prc)
841 HRESULT res;
842 UINT x, y;
844 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
845 if (FAILED(res)) return res;
847 for (y=0; y<prc->Height; y++)
848 for (x=0; x<prc->Width; x++)
850 BYTE *pixel = pbBuffer+cbStride*y+4*x;
851 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
852 pixel[0] = (255-y)*(255-k)/255; /* blue */
853 pixel[1] = (255-m)*(255-k)/255; /* green */
854 pixel[2] = (255-c)*(255-k)/255; /* red */
855 pixel[3] = 255; /* alpha */
858 return S_OK;
859 default:
860 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
864 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
865 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
867 HRESULT hr;
869 switch (source_format)
871 case format_32bppRGB:
872 if (prc)
874 INT x, y;
876 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
877 if (FAILED(hr)) return hr;
879 /* set all alpha values to 255 */
880 for (y=0; y<prc->Height; y++)
881 for (x=0; x<prc->Width; x++)
882 pbBuffer[cbStride*y+4*x+3] = 0xff;
884 return S_OK;
886 case format_32bppRGBA:
887 if (prc)
888 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
889 return S_OK;
891 case format_32bppPRGBA:
892 if (prc)
894 INT x, y;
896 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
897 if (FAILED(hr)) return hr;
899 for (y=0; y<prc->Height; y++)
900 for (x=0; x<prc->Width; x++)
902 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
903 if (alpha != 0 && alpha != 255)
905 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
906 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
907 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
911 return S_OK;
913 default:
914 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
915 if (SUCCEEDED(hr) && prc)
916 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
917 return hr;
921 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
922 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
924 switch (source_format)
926 case format_32bppBGR:
927 case format_32bppBGRA:
928 case format_32bppPBGRA:
929 if (prc)
930 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
931 return S_OK;
932 default:
933 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
937 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
938 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
940 switch (source_format)
942 case format_32bppRGB:
943 case format_32bppRGBA:
944 case format_32bppPRGBA:
945 if (prc)
946 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
947 return S_OK;
948 default:
949 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
953 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
954 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
956 HRESULT hr;
958 switch (source_format)
960 case format_32bppPBGRA:
961 if (prc)
962 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
963 return S_OK;
964 default:
965 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
966 if (SUCCEEDED(hr) && prc)
968 INT x, y;
970 for (y=0; y<prc->Height; y++)
971 for (x=0; x<prc->Width; x++)
973 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
974 if (alpha != 255)
976 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
977 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
978 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
982 return hr;
986 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
987 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
989 HRESULT hr;
991 switch (source_format)
993 case format_32bppPRGBA:
994 if (prc)
995 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
996 return S_OK;
997 default:
998 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
999 if (SUCCEEDED(hr) && prc)
1001 INT x, y;
1003 for (y=0; y<prc->Height; y++)
1004 for (x=0; x<prc->Width; x++)
1006 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1007 if (alpha != 255)
1009 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
1010 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1011 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
1015 return hr;
1019 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1020 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1022 HRESULT hr;
1024 switch (source_format)
1026 case format_24bppBGR:
1027 case format_24bppRGB:
1028 if (prc)
1030 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1031 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1032 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1033 return hr;
1035 return S_OK;
1036 case format_32bppBGR:
1037 case format_32bppBGRA:
1038 case format_32bppPBGRA:
1039 if (prc)
1041 HRESULT res;
1042 INT x, y;
1043 BYTE *srcdata;
1044 UINT srcstride, srcdatasize;
1045 const BYTE *srcrow;
1046 const BYTE *srcpixel;
1047 BYTE *dstrow;
1048 BYTE *dstpixel;
1050 srcstride = 4 * prc->Width;
1051 srcdatasize = srcstride * prc->Height;
1053 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1054 if (!srcdata) return E_OUTOFMEMORY;
1056 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1058 if (SUCCEEDED(res))
1060 srcrow = srcdata;
1061 dstrow = pbBuffer;
1062 for (y=0; y<prc->Height; y++) {
1063 srcpixel=srcrow;
1064 dstpixel=dstrow;
1065 for (x=0; x<prc->Width; x++) {
1066 *dstpixel++=*srcpixel++; /* blue */
1067 *dstpixel++=*srcpixel++; /* green */
1068 *dstpixel++=*srcpixel++; /* red */
1069 srcpixel++; /* alpha */
1071 srcrow += srcstride;
1072 dstrow += cbStride;
1076 HeapFree(GetProcessHeap(), 0, srcdata);
1078 return res;
1080 return S_OK;
1082 case format_32bppGrayFloat:
1083 if (prc)
1085 BYTE *srcdata;
1086 UINT srcstride, srcdatasize;
1088 srcstride = 4 * prc->Width;
1089 srcdatasize = srcstride * prc->Height;
1091 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1092 if (!srcdata) return E_OUTOFMEMORY;
1094 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1096 if (SUCCEEDED(hr))
1098 INT x, y;
1099 BYTE *src = srcdata, *dst = pbBuffer;
1101 for (y = 0; y < prc->Height; y++)
1103 float *gray_float = (float *)src;
1104 BYTE *bgr = dst;
1106 for (x = 0; x < prc->Width; x++)
1108 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1109 *bgr++ = gray;
1110 *bgr++ = gray;
1111 *bgr++ = gray;
1113 src += srcstride;
1114 dst += cbStride;
1118 HeapFree(GetProcessHeap(), 0, srcdata);
1120 return hr;
1122 return S_OK;
1124 default:
1125 FIXME("Unimplemented conversion path!\n");
1126 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1130 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1131 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1133 HRESULT hr;
1135 switch (source_format)
1137 case format_24bppBGR:
1138 case format_24bppRGB:
1139 if (prc)
1141 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1142 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1143 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1144 return hr;
1146 return S_OK;
1147 case format_32bppBGR:
1148 case format_32bppBGRA:
1149 case format_32bppPBGRA:
1150 if (prc)
1152 HRESULT res;
1153 INT x, y;
1154 BYTE *srcdata;
1155 UINT srcstride, srcdatasize;
1156 const BYTE *srcrow;
1157 const BYTE *srcpixel;
1158 BYTE *dstrow;
1159 BYTE *dstpixel;
1160 BYTE tmppixel[3];
1162 srcstride = 4 * prc->Width;
1163 srcdatasize = srcstride * prc->Height;
1165 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1166 if (!srcdata) return E_OUTOFMEMORY;
1168 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1170 if (SUCCEEDED(res))
1172 srcrow = srcdata;
1173 dstrow = pbBuffer;
1174 for (y=0; y<prc->Height; y++) {
1175 srcpixel=srcrow;
1176 dstpixel=dstrow;
1177 for (x=0; x<prc->Width; x++) {
1178 tmppixel[0]=*srcpixel++; /* blue */
1179 tmppixel[1]=*srcpixel++; /* green */
1180 tmppixel[2]=*srcpixel++; /* red */
1181 srcpixel++; /* alpha */
1183 *dstpixel++=tmppixel[2]; /* red */
1184 *dstpixel++=tmppixel[1]; /* green */
1185 *dstpixel++=tmppixel[0]; /* blue */
1187 srcrow += srcstride;
1188 dstrow += cbStride;
1192 HeapFree(GetProcessHeap(), 0, srcdata);
1194 return res;
1196 return S_OK;
1197 default:
1198 FIXME("Unimplemented conversion path!\n");
1199 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1203 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1204 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1206 HRESULT hr;
1208 switch (source_format)
1210 case format_32bppBGR:
1211 case format_32bppBGRA:
1212 case format_32bppPBGRA:
1213 case format_32bppGrayFloat:
1214 if (prc)
1216 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1217 break;
1219 return S_OK;
1221 default:
1222 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1223 break;
1226 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1228 INT x, y;
1229 BYTE *p = pbBuffer;
1231 for (y = 0; y < prc->Height; y++)
1233 BYTE *bgr = p;
1234 for (x = 0; x < prc->Width; x++)
1236 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1237 *(float *)bgr = gray;
1238 bgr += 4;
1240 p += cbStride;
1243 return hr;
1246 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1247 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1249 HRESULT hr;
1250 BYTE *srcdata;
1251 UINT srcstride, srcdatasize;
1253 if (source_format == format_8bppGray)
1255 if (prc)
1256 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1258 return S_OK;
1261 if (source_format == format_32bppGrayFloat)
1263 hr = S_OK;
1265 if (prc)
1267 srcstride = 4 * prc->Width;
1268 srcdatasize = srcstride * prc->Height;
1270 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1271 if (!srcdata) return E_OUTOFMEMORY;
1273 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1274 if (SUCCEEDED(hr))
1276 INT x, y;
1277 BYTE *src = srcdata, *dst = pbBuffer;
1279 for (y=0; y < prc->Height; y++)
1281 float *srcpixel = (float*)src;
1282 BYTE *dstpixel = dst;
1284 for (x=0; x < prc->Width; x++)
1285 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1287 src += srcstride;
1288 dst += cbStride;
1292 HeapFree(GetProcessHeap(), 0, srcdata);
1295 return hr;
1298 if (!prc)
1299 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1301 srcstride = 3 * prc->Width;
1302 srcdatasize = srcstride * prc->Height;
1304 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1305 if (!srcdata) return E_OUTOFMEMORY;
1307 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1308 if (SUCCEEDED(hr) && prc)
1310 INT x, y;
1311 BYTE *src = srcdata, *dst = pbBuffer;
1313 for (y = 0; y < prc->Height; y++)
1315 BYTE *bgr = src;
1317 for (x = 0; x < prc->Width; x++)
1319 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1321 gray = to_sRGB_component(gray) * 255.0f;
1322 dst[x] = (BYTE)floorf(gray + 0.51f);
1323 bgr += 3;
1325 src += srcstride;
1326 dst += cbStride;
1330 HeapFree(GetProcessHeap(), 0, srcdata);
1331 return hr;
1334 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1336 UINT best_diff, best_index, i;
1338 best_diff = ~0;
1339 best_index = 0;
1341 for (i = 0; i < count; i++)
1343 BYTE pal_r, pal_g, pal_b;
1344 UINT diff_r, diff_g, diff_b, diff;
1346 pal_r = colors[i] >> 16;
1347 pal_g = colors[i] >> 8;
1348 pal_b = colors[i];
1350 diff_r = bgr[2] - pal_r;
1351 diff_g = bgr[1] - pal_g;
1352 diff_b = bgr[0] - pal_b;
1354 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1355 if (diff == 0) return i;
1357 if (diff < best_diff)
1359 best_diff = diff;
1360 best_index = i;
1364 return best_index;
1367 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1368 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1370 HRESULT hr;
1371 BYTE *srcdata;
1372 WICColor colors[256];
1373 UINT srcstride, srcdatasize, count;
1375 if (source_format == format_8bppIndexed)
1377 if (prc)
1378 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1380 return S_OK;
1383 if (!prc)
1384 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1386 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1388 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1389 if (hr != S_OK) return hr;
1391 srcstride = 3 * prc->Width;
1392 srcdatasize = srcstride * prc->Height;
1394 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1395 if (!srcdata) return E_OUTOFMEMORY;
1397 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1398 if (SUCCEEDED(hr) && prc)
1400 INT x, y;
1401 BYTE *src = srcdata, *dst = pbBuffer;
1403 for (y = 0; y < prc->Height; y++)
1405 BYTE *bgr = src;
1407 for (x = 0; x < prc->Width; x++)
1409 dst[x] = rgb_to_palette_index(bgr, colors, count);
1410 bgr += 3;
1412 src += srcstride;
1413 dst += cbStride;
1417 HeapFree(GetProcessHeap(), 0, srcdata);
1418 return hr;
1421 static const struct pixelformatinfo supported_formats[] = {
1422 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1423 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1424 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1425 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1426 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1427 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1428 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1429 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1430 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1431 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1432 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1433 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1434 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1435 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1436 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1437 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1438 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1439 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1440 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1441 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1442 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1443 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1444 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1445 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1449 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1451 UINT i;
1453 for (i=0; supported_formats[i].guid; i++)
1454 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1456 return NULL;
1459 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1460 void **ppv)
1462 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1463 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1465 if (!ppv) return E_INVALIDARG;
1467 if (IsEqualIID(&IID_IUnknown, iid) ||
1468 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1469 IsEqualIID(&IID_IWICFormatConverter, iid))
1471 *ppv = &This->IWICFormatConverter_iface;
1473 else
1475 *ppv = NULL;
1476 return E_NOINTERFACE;
1479 IUnknown_AddRef((IUnknown*)*ppv);
1480 return S_OK;
1483 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1485 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1486 ULONG ref = InterlockedIncrement(&This->ref);
1488 TRACE("(%p) refcount=%u\n", iface, ref);
1490 return ref;
1493 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1495 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1496 ULONG ref = InterlockedDecrement(&This->ref);
1498 TRACE("(%p) refcount=%u\n", iface, ref);
1500 if (ref == 0)
1502 This->lock.DebugInfo->Spare[0] = 0;
1503 DeleteCriticalSection(&This->lock);
1504 if (This->source) IWICBitmapSource_Release(This->source);
1505 if (This->palette) IWICPalette_Release(This->palette);
1506 HeapFree(GetProcessHeap(), 0, This);
1509 return ref;
1512 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1513 UINT *puiWidth, UINT *puiHeight)
1515 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1517 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1519 if (This->source)
1520 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1521 else
1522 return WINCODEC_ERR_NOTINITIALIZED;
1525 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1526 WICPixelFormatGUID *pPixelFormat)
1528 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1530 TRACE("(%p,%p)\n", iface, pPixelFormat);
1532 if (This->source)
1533 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1534 else
1535 return WINCODEC_ERR_NOTINITIALIZED;
1537 return S_OK;
1540 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1541 double *pDpiX, double *pDpiY)
1543 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1545 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1547 if (This->source)
1548 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1549 else
1550 return WINCODEC_ERR_NOTINITIALIZED;
1553 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1554 IWICPalette *palette)
1556 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1558 TRACE("(%p,%p)\n", iface, palette);
1560 if (!palette) return E_INVALIDARG;
1561 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1563 if (!This->palette)
1565 HRESULT hr;
1566 UINT bpp;
1568 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1569 if (hr != S_OK) return hr;
1570 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1571 return IWICBitmapSource_CopyPalette(This->source, palette);
1574 return IWICPalette_InitializeFromPalette(palette, This->palette);
1577 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1578 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1580 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1581 WICRect rc;
1582 HRESULT hr;
1583 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1585 if (This->source)
1587 if (!prc)
1589 UINT width, height;
1590 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1591 if (FAILED(hr)) return hr;
1592 rc.X = 0;
1593 rc.Y = 0;
1594 rc.Width = width;
1595 rc.Height = height;
1596 prc = &rc;
1599 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1600 pbBuffer, This->src_format->format);
1602 else
1603 return WINCODEC_ERR_WRONGSTATE;
1606 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1607 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1608 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1610 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1611 const struct pixelformatinfo *srcinfo, *dstinfo;
1612 GUID srcFormat;
1613 HRESULT res;
1615 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1616 dither, palette, alpha_threshold, palette_type);
1618 if (!palette)
1620 UINT bpp;
1621 res = get_pixelformat_bpp(dstFormat, &bpp);
1622 if (res != S_OK) return res;
1624 res = PaletteImpl_Create(&palette);
1625 if (res != S_OK) return res;
1627 switch (palette_type)
1629 case WICBitmapPaletteTypeCustom:
1630 IWICPalette_Release(palette);
1631 palette = NULL;
1632 if (bpp <= 8) return E_INVALIDARG;
1633 break;
1635 case WICBitmapPaletteTypeMedianCut:
1637 if (bpp <= 8)
1638 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1639 break;
1642 default:
1643 if (bpp <= 8)
1644 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1645 break;
1648 if (res != S_OK)
1650 IWICPalette_Release(palette);
1651 return res;
1654 else
1655 IWICPalette_AddRef(palette);
1657 EnterCriticalSection(&This->lock);
1659 if (This->source)
1661 res = WINCODEC_ERR_WRONGSTATE;
1662 goto end;
1665 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1666 if (FAILED(res)) goto end;
1668 srcinfo = get_formatinfo(&srcFormat);
1669 if (!srcinfo)
1671 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1672 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1673 goto end;
1676 dstinfo = get_formatinfo(dstFormat);
1677 if (!dstinfo)
1679 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1680 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1681 goto end;
1684 if (dstinfo->copy_function)
1686 IWICBitmapSource_AddRef(source);
1687 This->src_format = srcinfo;
1688 This->dst_format = dstinfo;
1689 This->dither = dither;
1690 This->alpha_threshold = alpha_threshold;
1691 This->palette = palette;
1692 This->source = source;
1694 else
1696 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1697 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1700 end:
1702 LeaveCriticalSection(&This->lock);
1704 if (res != S_OK && palette)
1705 IWICPalette_Release(palette);
1707 return res;
1710 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1711 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1712 BOOL *pfCanConvert)
1714 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1715 const struct pixelformatinfo *srcinfo, *dstinfo;
1717 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1718 debugstr_guid(dstPixelFormat), pfCanConvert);
1720 srcinfo = get_formatinfo(srcPixelFormat);
1721 if (!srcinfo)
1723 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1724 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1727 dstinfo = get_formatinfo(dstPixelFormat);
1728 if (!dstinfo)
1730 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1731 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1734 if (dstinfo->copy_function &&
1735 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1736 *pfCanConvert = TRUE;
1737 else
1739 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1740 *pfCanConvert = FALSE;
1743 return S_OK;
1746 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1747 FormatConverter_QueryInterface,
1748 FormatConverter_AddRef,
1749 FormatConverter_Release,
1750 FormatConverter_GetSize,
1751 FormatConverter_GetPixelFormat,
1752 FormatConverter_GetResolution,
1753 FormatConverter_CopyPalette,
1754 FormatConverter_CopyPixels,
1755 FormatConverter_Initialize,
1756 FormatConverter_CanConvert
1759 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1761 FormatConverter *This;
1762 HRESULT ret;
1764 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1766 *ppv = NULL;
1768 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1769 if (!This) return E_OUTOFMEMORY;
1771 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1772 This->ref = 1;
1773 This->source = NULL;
1774 This->palette = NULL;
1775 InitializeCriticalSection(&This->lock);
1776 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1778 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1779 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1781 return ret;