2 * Copyright 2009 Vincent Povirk
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 struct FormatConverter;
61 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
62 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
64 struct pixelformatinfo {
65 enum pixelformat format;
66 const WICPixelFormatGUID *guid;
67 copyfunc copy_function;
70 typedef struct FormatConverter {
71 IWICFormatConverter IWICFormatConverter_iface;
73 IWICBitmapSource *source;
74 const struct pixelformatinfo *dst_format, *src_format;
75 WICBitmapDitherType dither;
76 double alpha_threshold;
77 WICBitmapPaletteType palette_type;
78 CRITICAL_SECTION lock; /* must be held when initialized */
81 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
83 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
86 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
87 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
89 switch (source_format)
91 case format_1bppIndexed:
92 case format_BlackWhite:
98 UINT srcstride, srcdatasize;
104 IWICPalette *palette;
107 res = PaletteImpl_Create(&palette);
108 if (FAILED(res)) return res;
110 if (source_format == format_1bppIndexed)
111 res = IWICBitmapSource_CopyPalette(This->source, palette);
113 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
116 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
118 IWICPalette_Release(palette);
119 if (FAILED(res)) return res;
121 srcstride = (prc->Width+7)/8;
122 srcdatasize = srcstride * prc->Height;
124 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
125 if (!srcdata) return E_OUTOFMEMORY;
127 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
133 for (y=0; y<prc->Height; y++) {
135 dstpixel=(DWORD*)dstrow;
136 for (x=0; x<prc->Width; x+=8) {
139 *dstpixel++ = colors[srcval>>7&1];
140 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
141 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
142 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
143 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
144 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
145 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
146 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
153 HeapFree(GetProcessHeap(), 0, srcdata);
158 case format_2bppIndexed:
159 case format_2bppGray:
165 UINT srcstride, srcdatasize;
171 IWICPalette *palette;
174 res = PaletteImpl_Create(&palette);
175 if (FAILED(res)) return res;
177 if (source_format == format_2bppIndexed)
178 res = IWICBitmapSource_CopyPalette(This->source, palette);
180 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
183 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
185 IWICPalette_Release(palette);
186 if (FAILED(res)) return res;
188 srcstride = (prc->Width+3)/4;
189 srcdatasize = srcstride * prc->Height;
191 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
192 if (!srcdata) return E_OUTOFMEMORY;
194 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
200 for (y=0; y<prc->Height; y++) {
202 dstpixel=(DWORD*)dstrow;
203 for (x=0; x<prc->Width; x+=4) {
206 *dstpixel++ = colors[srcval>>6];
207 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
208 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
209 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
216 HeapFree(GetProcessHeap(), 0, srcdata);
221 case format_4bppIndexed:
222 case format_4bppGray:
228 UINT srcstride, srcdatasize;
234 IWICPalette *palette;
237 res = PaletteImpl_Create(&palette);
238 if (FAILED(res)) return res;
240 if (source_format == format_4bppIndexed)
241 res = IWICBitmapSource_CopyPalette(This->source, palette);
243 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
246 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
248 IWICPalette_Release(palette);
249 if (FAILED(res)) return res;
251 srcstride = (prc->Width+1)/2;
252 srcdatasize = srcstride * prc->Height;
254 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
255 if (!srcdata) return E_OUTOFMEMORY;
257 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
263 for (y=0; y<prc->Height; y++) {
265 dstpixel=(DWORD*)dstrow;
266 for (x=0; x<prc->Width; x+=2) {
269 *dstpixel++ = colors[srcval>>4];
270 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
277 HeapFree(GetProcessHeap(), 0, srcdata);
282 case format_8bppGray:
288 UINT srcstride, srcdatasize;
294 srcstride = prc->Width;
295 srcdatasize = srcstride * prc->Height;
297 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
298 if (!srcdata) return E_OUTOFMEMORY;
300 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
306 for (y=0; y<prc->Height; y++) {
308 dstpixel=(DWORD*)dstrow;
309 for (x=0; x<prc->Width; x++)
311 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
319 HeapFree(GetProcessHeap(), 0, srcdata);
324 case format_8bppIndexed:
330 UINT srcstride, srcdatasize;
335 WICColor colors[256];
336 IWICPalette *palette;
339 res = PaletteImpl_Create(&palette);
340 if (FAILED(res)) return res;
342 res = IWICBitmapSource_CopyPalette(This->source, palette);
344 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
346 IWICPalette_Release(palette);
348 if (FAILED(res)) return res;
350 srcstride = prc->Width;
351 srcdatasize = srcstride * prc->Height;
353 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
354 if (!srcdata) return E_OUTOFMEMORY;
356 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
362 for (y=0; y<prc->Height; y++) {
364 dstpixel=(DWORD*)dstrow;
365 for (x=0; x<prc->Width; x++)
366 *dstpixel++ = colors[*srcbyte++];
372 HeapFree(GetProcessHeap(), 0, srcdata);
377 case format_16bppGray:
383 UINT srcstride, srcdatasize;
389 srcstride = prc->Width * 2;
390 srcdatasize = srcstride * prc->Height;
392 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
393 if (!srcdata) return E_OUTOFMEMORY;
395 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
401 for (y=0; y<prc->Height; y++) {
403 dstpixel=(DWORD*)dstrow;
404 for (x=0; x<prc->Width; x++)
406 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
414 HeapFree(GetProcessHeap(), 0, srcdata);
419 case format_16bppBGR555:
425 UINT srcstride, srcdatasize;
427 const WORD *srcpixel;
431 srcstride = 2 * prc->Width;
432 srcdatasize = srcstride * prc->Height;
434 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
435 if (!srcdata) return E_OUTOFMEMORY;
437 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
443 for (y=0; y<prc->Height; y++) {
444 srcpixel=(const WORD*)srcrow;
445 dstpixel=(DWORD*)dstrow;
446 for (x=0; x<prc->Width; x++) {
449 *dstpixel++=0xff000000 | /* constant 255 alpha */
450 ((srcval << 9) & 0xf80000) | /* r */
451 ((srcval << 4) & 0x070000) | /* r - 3 bits */
452 ((srcval << 6) & 0x00f800) | /* g */
453 ((srcval << 1) & 0x000700) | /* g - 3 bits */
454 ((srcval << 3) & 0x0000f8) | /* b */
455 ((srcval >> 2) & 0x000007); /* b - 3 bits */
462 HeapFree(GetProcessHeap(), 0, srcdata);
467 case format_16bppBGR565:
473 UINT srcstride, srcdatasize;
475 const WORD *srcpixel;
479 srcstride = 2 * prc->Width;
480 srcdatasize = srcstride * prc->Height;
482 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
483 if (!srcdata) return E_OUTOFMEMORY;
485 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
491 for (y=0; y<prc->Height; y++) {
492 srcpixel=(const WORD*)srcrow;
493 dstpixel=(DWORD*)dstrow;
494 for (x=0; x<prc->Width; x++) {
497 *dstpixel++=0xff000000 | /* constant 255 alpha */
498 ((srcval << 8) & 0xf80000) | /* r */
499 ((srcval << 3) & 0x070000) | /* r - 3 bits */
500 ((srcval << 5) & 0x00fc00) | /* g */
501 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
502 ((srcval << 3) & 0x0000f8) | /* b */
503 ((srcval >> 2) & 0x000007); /* b - 3 bits */
510 HeapFree(GetProcessHeap(), 0, srcdata);
515 case format_16bppBGRA5551:
521 UINT srcstride, srcdatasize;
523 const WORD *srcpixel;
527 srcstride = 2 * prc->Width;
528 srcdatasize = srcstride * prc->Height;
530 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
531 if (!srcdata) return E_OUTOFMEMORY;
533 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
539 for (y=0; y<prc->Height; y++) {
540 srcpixel=(const WORD*)srcrow;
541 dstpixel=(DWORD*)dstrow;
542 for (x=0; x<prc->Width; x++) {
545 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
546 ((srcval << 9) & 0xf80000) | /* r */
547 ((srcval << 4) & 0x070000) | /* r - 3 bits */
548 ((srcval << 6) & 0x00f800) | /* g */
549 ((srcval << 1) & 0x000700) | /* g - 3 bits */
550 ((srcval << 3) & 0x0000f8) | /* b */
551 ((srcval >> 2) & 0x000007); /* b - 3 bits */
558 HeapFree(GetProcessHeap(), 0, srcdata);
563 case format_24bppBGR:
569 UINT srcstride, srcdatasize;
571 const BYTE *srcpixel;
575 srcstride = 3 * prc->Width;
576 srcdatasize = srcstride * prc->Height;
578 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
579 if (!srcdata) return E_OUTOFMEMORY;
581 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
587 for (y=0; y<prc->Height; y++) {
590 for (x=0; x<prc->Width; x++) {
591 *dstpixel++=*srcpixel++; /* blue */
592 *dstpixel++=*srcpixel++; /* green */
593 *dstpixel++=*srcpixel++; /* red */
594 *dstpixel++=255; /* alpha */
601 HeapFree(GetProcessHeap(), 0, srcdata);
606 case format_24bppRGB:
612 UINT srcstride, srcdatasize;
614 const BYTE *srcpixel;
619 srcstride = 3 * prc->Width;
620 srcdatasize = srcstride * prc->Height;
622 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
623 if (!srcdata) return E_OUTOFMEMORY;
625 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
631 for (y=0; y<prc->Height; y++) {
634 for (x=0; x<prc->Width; x++) {
635 tmppixel[0]=*srcpixel++; /* red */
636 tmppixel[1]=*srcpixel++; /* green */
637 tmppixel[2]=*srcpixel++; /* blue */
639 *dstpixel++=tmppixel[2]; /* blue */
640 *dstpixel++=tmppixel[1]; /* green */
641 *dstpixel++=tmppixel[0]; /* red */
642 *dstpixel++=255; /* alpha */
649 HeapFree(GetProcessHeap(), 0, srcdata);
654 case format_32bppBGR:
660 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
661 if (FAILED(res)) return res;
663 /* set all alpha values to 255 */
664 for (y=0; y<prc->Height; y++)
665 for (x=0; x<prc->Width; x++)
666 pbBuffer[cbStride*y+4*x+3] = 0xff;
669 case format_32bppBGRA:
671 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
673 case format_32bppPBGRA:
679 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
680 if (FAILED(res)) return res;
682 for (y=0; y<prc->Height; y++)
683 for (x=0; x<prc->Width; x++)
685 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
686 if (alpha != 0 && alpha != 255)
688 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
689 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
690 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
695 case format_48bppRGB:
701 UINT srcstride, srcdatasize;
703 const BYTE *srcpixel;
707 srcstride = 6 * prc->Width;
708 srcdatasize = srcstride * prc->Height;
710 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
711 if (!srcdata) return E_OUTOFMEMORY;
713 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
719 for (y=0; y<prc->Height; y++) {
721 dstpixel=(DWORD*)dstrow;
722 for (x=0; x<prc->Width; x++) {
723 BYTE red, green, blue;
724 red = *srcpixel++; srcpixel++;
725 green = *srcpixel++; srcpixel++;
726 blue = *srcpixel++; srcpixel++;
727 *dstpixel++=0xff000000|red<<16|green<<8|blue;
734 HeapFree(GetProcessHeap(), 0, srcdata);
739 case format_64bppRGBA:
745 UINT srcstride, srcdatasize;
747 const BYTE *srcpixel;
751 srcstride = 8 * prc->Width;
752 srcdatasize = srcstride * prc->Height;
754 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
755 if (!srcdata) return E_OUTOFMEMORY;
757 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
763 for (y=0; y<prc->Height; y++) {
765 dstpixel=(DWORD*)dstrow;
766 for (x=0; x<prc->Width; x++) {
767 BYTE red, green, blue, alpha;
768 red = *srcpixel++; srcpixel++;
769 green = *srcpixel++; srcpixel++;
770 blue = *srcpixel++; srcpixel++;
771 alpha = *srcpixel++; srcpixel++;
772 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
779 HeapFree(GetProcessHeap(), 0, srcdata);
784 case format_32bppCMYK:
790 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
791 if (FAILED(res)) return res;
793 for (y=0; y<prc->Height; y++)
794 for (x=0; x<prc->Width; x++)
796 BYTE *pixel = pbBuffer+cbStride*y+4*x;
797 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
798 pixel[0] = (255-y)*(255-k)/255; /* blue */
799 pixel[1] = (255-m)*(255-k)/255; /* green */
800 pixel[2] = (255-c)*(255-k)/255; /* red */
801 pixel[3] = 255; /* alpha */
806 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
810 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
811 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
813 switch (source_format)
815 case format_32bppBGR:
816 case format_32bppBGRA:
817 case format_32bppPBGRA:
819 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
822 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
826 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
827 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
831 switch (source_format)
833 case format_32bppPBGRA:
835 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
838 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
839 if (SUCCEEDED(hr) && prc)
843 for (y=0; y<prc->Height; y++)
844 for (x=0; x<prc->Width; x++)
846 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
849 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
850 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
851 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
859 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
860 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
864 switch (source_format)
866 case format_24bppBGR:
867 case format_24bppRGB:
870 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
871 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
872 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
876 case format_32bppBGR:
877 case format_32bppBGRA:
878 case format_32bppPBGRA:
884 UINT srcstride, srcdatasize;
886 const BYTE *srcpixel;
890 srcstride = 4 * prc->Width;
891 srcdatasize = srcstride * prc->Height;
893 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
894 if (!srcdata) return E_OUTOFMEMORY;
896 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
902 for (y=0; y<prc->Height; y++) {
905 for (x=0; x<prc->Width; x++) {
906 *dstpixel++=*srcpixel++; /* blue */
907 *dstpixel++=*srcpixel++; /* green */
908 *dstpixel++=*srcpixel++; /* red */
909 srcpixel++; /* alpha */
916 HeapFree(GetProcessHeap(), 0, srcdata);
922 FIXME("Unimplemented conversion path!\n");
923 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
927 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
928 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
932 switch (source_format)
934 case format_24bppBGR:
935 case format_24bppRGB:
938 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
939 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
940 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
944 case format_32bppBGR:
945 case format_32bppBGRA:
946 case format_32bppPBGRA:
952 UINT srcstride, srcdatasize;
954 const BYTE *srcpixel;
958 srcstride = 4 * prc->Width;
959 srcdatasize = srcstride * prc->Height;
961 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
962 if (!srcdata) return E_OUTOFMEMORY;
964 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
970 for (y=0; y<prc->Height; y++) {
973 for (x=0; x<prc->Width; x++) {
974 *dstpixel++=*srcpixel++; /* blue */
975 *dstpixel++=*srcpixel++; /* green */
976 *dstpixel++=*srcpixel++; /* red */
977 srcpixel++; /* alpha */
983 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
986 HeapFree(GetProcessHeap(), 0, srcdata);
992 FIXME("Unimplemented conversion path!\n");
993 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
997 static const struct pixelformatinfo supported_formats[] = {
998 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
999 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1000 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1001 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
1002 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1003 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1004 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1005 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
1006 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1007 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1008 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1009 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1010 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1011 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1012 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1013 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1014 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1015 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1016 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1017 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1021 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1025 for (i=0; supported_formats[i].guid; i++)
1026 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1031 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1034 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1035 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1037 if (!ppv) return E_INVALIDARG;
1039 if (IsEqualIID(&IID_IUnknown, iid) ||
1040 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1041 IsEqualIID(&IID_IWICFormatConverter, iid))
1043 *ppv = &This->IWICFormatConverter_iface;
1048 return E_NOINTERFACE;
1051 IUnknown_AddRef((IUnknown*)*ppv);
1055 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1057 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1058 ULONG ref = InterlockedIncrement(&This->ref);
1060 TRACE("(%p) refcount=%u\n", iface, ref);
1065 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1067 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1068 ULONG ref = InterlockedDecrement(&This->ref);
1070 TRACE("(%p) refcount=%u\n", iface, ref);
1074 This->lock.DebugInfo->Spare[0] = 0;
1075 DeleteCriticalSection(&This->lock);
1076 if (This->source) IWICBitmapSource_Release(This->source);
1077 HeapFree(GetProcessHeap(), 0, This);
1083 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1084 UINT *puiWidth, UINT *puiHeight)
1086 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1088 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1091 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1093 return WINCODEC_ERR_NOTINITIALIZED;
1096 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1097 WICPixelFormatGUID *pPixelFormat)
1099 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1101 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
1104 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1106 return WINCODEC_ERR_NOTINITIALIZED;
1111 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1112 double *pDpiX, double *pDpiY)
1114 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1116 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
1119 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1121 return WINCODEC_ERR_NOTINITIALIZED;
1124 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1125 IWICPalette *pIPalette)
1127 FIXME("(%p,%p): stub\n", iface, pIPalette);
1131 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1132 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1134 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1137 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1144 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1145 if (FAILED(hr)) return hr;
1153 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1154 pbBuffer, This->src_format->format);
1157 return WINCODEC_ERR_NOTINITIALIZED;
1160 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1161 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1162 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
1164 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1165 const struct pixelformatinfo *srcinfo, *dstinfo;
1170 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1171 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1173 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1175 EnterCriticalSection(&This->lock);
1179 res = WINCODEC_ERR_WRONGSTATE;
1183 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1184 if (FAILED(res)) goto end;
1186 srcinfo = get_formatinfo(&srcFormat);
1189 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1190 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1194 dstinfo = get_formatinfo(dstFormat);
1197 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1198 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1202 if (dstinfo->copy_function)
1204 IWICBitmapSource_AddRef(pISource);
1205 This->src_format = srcinfo;
1206 This->dst_format = dstinfo;
1207 This->dither = dither;
1208 This->alpha_threshold = alphaThresholdPercent;
1209 This->palette_type = paletteTranslate;
1210 This->source = pISource;
1214 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1215 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1220 LeaveCriticalSection(&This->lock);
1225 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1226 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1229 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1230 const struct pixelformatinfo *srcinfo, *dstinfo;
1232 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1233 debugstr_guid(dstPixelFormat), pfCanConvert);
1235 srcinfo = get_formatinfo(srcPixelFormat);
1238 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1239 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1242 dstinfo = get_formatinfo(dstPixelFormat);
1245 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1246 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1249 if (dstinfo->copy_function &&
1250 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1251 *pfCanConvert = TRUE;
1254 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1255 *pfCanConvert = FALSE;
1261 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1262 FormatConverter_QueryInterface,
1263 FormatConverter_AddRef,
1264 FormatConverter_Release,
1265 FormatConverter_GetSize,
1266 FormatConverter_GetPixelFormat,
1267 FormatConverter_GetResolution,
1268 FormatConverter_CopyPalette,
1269 FormatConverter_CopyPixels,
1270 FormatConverter_Initialize,
1271 FormatConverter_CanConvert
1274 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1276 FormatConverter *This;
1279 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1283 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1285 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1286 if (!This) return E_OUTOFMEMORY;
1288 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1290 This->source = NULL;
1291 InitializeCriticalSection(&This->lock);
1292 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1294 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1295 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);