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
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
37 struct FormatConverter
;
54 format_32bppGrayFloat
,
63 typedef HRESULT (*copyfunc
)(struct FormatConverter
*This
, const WICRect
*prc
,
64 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
);
66 struct pixelformatinfo
{
67 enum pixelformat format
;
68 const WICPixelFormatGUID
*guid
;
69 copyfunc copy_function
;
72 typedef struct FormatConverter
{
73 IWICFormatConverter IWICFormatConverter_iface
;
75 IWICBitmapSource
*source
;
76 const struct pixelformatinfo
*dst_format
, *src_format
;
77 WICBitmapDitherType dither
;
78 double alpha_threshold
;
79 WICBitmapPaletteType palette_type
;
80 CRITICAL_SECTION lock
; /* must be held when initialized */
83 /* https://www.w3.org/Graphics/Color/srgb */
84 static inline float from_sRGB_component(float f
)
86 if (f
<= 0.04045f
) return f
/ 12.92f
;
87 return powf((f
+ 0.055f
) / 1.055f
, 2.4f
);
90 static inline float to_sRGB_component(float f
)
92 if (f
<= 0.0031308f
) return 12.92f
* f
;
93 return 1.055f
* powf(f
, 1.0f
/2.4f
) - 0.055f
;
96 #if 0 /* FIXME: enable once needed */
97 static void from_sRGB(BYTE
*bgr
)
105 r
= from_sRGB_component(r
);
106 g
= from_sRGB_component(g
);
107 b
= from_sRGB_component(b
);
109 bgr
[2] = (BYTE
)(r
* 255.0f
);
110 bgr
[1] = (BYTE
)(g
* 255.0f
);
111 bgr
[0] = (BYTE
)(b
* 255.0f
);
114 static void to_sRGB(BYTE
*bgr
)
122 r
= to_sRGB_component(r
);
123 g
= to_sRGB_component(g
);
124 b
= to_sRGB_component(b
);
126 bgr
[2] = (BYTE
)(r
* 255.0f
);
127 bgr
[1] = (BYTE
)(g
* 255.0f
);
128 bgr
[0] = (BYTE
)(b
* 255.0f
);
132 static inline FormatConverter
*impl_from_IWICFormatConverter(IWICFormatConverter
*iface
)
134 return CONTAINING_RECORD(iface
, FormatConverter
, IWICFormatConverter_iface
);
137 static HRESULT
copypixels_to_32bppBGRA(struct FormatConverter
*This
, const WICRect
*prc
,
138 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
140 switch (source_format
)
142 case format_1bppIndexed
:
143 case format_BlackWhite
:
149 UINT srcstride
, srcdatasize
;
155 IWICPalette
*palette
;
158 res
= PaletteImpl_Create(&palette
);
159 if (FAILED(res
)) return res
;
161 if (source_format
== format_1bppIndexed
)
162 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
164 res
= IWICPalette_InitializePredefined(palette
, WICBitmapPaletteTypeFixedBW
, FALSE
);
167 res
= IWICPalette_GetColors(palette
, 2, colors
, &actualcolors
);
169 IWICPalette_Release(palette
);
170 if (FAILED(res
)) return res
;
172 srcstride
= (prc
->Width
+7)/8;
173 srcdatasize
= srcstride
* prc
->Height
;
175 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
176 if (!srcdata
) return E_OUTOFMEMORY
;
178 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
184 for (y
=0; y
<prc
->Height
; y
++) {
186 dstpixel
=(DWORD
*)dstrow
;
187 for (x
=0; x
<prc
->Width
; x
+=8) {
190 *dstpixel
++ = colors
[srcval
>>7&1];
191 if (x
+1 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>6&1];
192 if (x
+2 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>5&1];
193 if (x
+3 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>4&1];
194 if (x
+4 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>3&1];
195 if (x
+5 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>2&1];
196 if (x
+6 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>1&1];
197 if (x
+7 < prc
->Width
) *dstpixel
++ = colors
[srcval
&1];
204 HeapFree(GetProcessHeap(), 0, srcdata
);
209 case format_2bppIndexed
:
210 case format_2bppGray
:
216 UINT srcstride
, srcdatasize
;
222 IWICPalette
*palette
;
225 res
= PaletteImpl_Create(&palette
);
226 if (FAILED(res
)) return res
;
228 if (source_format
== format_2bppIndexed
)
229 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
231 res
= IWICPalette_InitializePredefined(palette
, WICBitmapPaletteTypeFixedGray4
, FALSE
);
234 res
= IWICPalette_GetColors(palette
, 4, colors
, &actualcolors
);
236 IWICPalette_Release(palette
);
237 if (FAILED(res
)) return res
;
239 srcstride
= (prc
->Width
+3)/4;
240 srcdatasize
= srcstride
* prc
->Height
;
242 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
243 if (!srcdata
) return E_OUTOFMEMORY
;
245 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
251 for (y
=0; y
<prc
->Height
; y
++) {
253 dstpixel
=(DWORD
*)dstrow
;
254 for (x
=0; x
<prc
->Width
; x
+=4) {
257 *dstpixel
++ = colors
[srcval
>>6];
258 if (x
+1 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>4&0x3];
259 if (x
+2 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>2&0x3];
260 if (x
+3 < prc
->Width
) *dstpixel
++ = colors
[srcval
&0x3];
267 HeapFree(GetProcessHeap(), 0, srcdata
);
272 case format_4bppIndexed
:
273 case format_4bppGray
:
279 UINT srcstride
, srcdatasize
;
285 IWICPalette
*palette
;
288 res
= PaletteImpl_Create(&palette
);
289 if (FAILED(res
)) return res
;
291 if (source_format
== format_4bppIndexed
)
292 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
294 res
= IWICPalette_InitializePredefined(palette
, WICBitmapPaletteTypeFixedGray16
, FALSE
);
297 res
= IWICPalette_GetColors(palette
, 16, colors
, &actualcolors
);
299 IWICPalette_Release(palette
);
300 if (FAILED(res
)) return res
;
302 srcstride
= (prc
->Width
+1)/2;
303 srcdatasize
= srcstride
* prc
->Height
;
305 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
306 if (!srcdata
) return E_OUTOFMEMORY
;
308 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
314 for (y
=0; y
<prc
->Height
; y
++) {
316 dstpixel
=(DWORD
*)dstrow
;
317 for (x
=0; x
<prc
->Width
; x
+=2) {
320 *dstpixel
++ = colors
[srcval
>>4];
321 if (x
+1 < prc
->Width
) *dstpixel
++ = colors
[srcval
&0xf];
328 HeapFree(GetProcessHeap(), 0, srcdata
);
333 case format_8bppGray
:
339 UINT srcstride
, srcdatasize
;
345 srcstride
= prc
->Width
;
346 srcdatasize
= srcstride
* prc
->Height
;
348 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
349 if (!srcdata
) return E_OUTOFMEMORY
;
351 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
357 for (y
=0; y
<prc
->Height
; y
++) {
359 dstpixel
=(DWORD
*)dstrow
;
360 for (x
=0; x
<prc
->Width
; x
++)
362 *dstpixel
++ = 0xff000000|(*srcbyte
<<16)|(*srcbyte
<<8)|*srcbyte
;
370 HeapFree(GetProcessHeap(), 0, srcdata
);
375 case format_8bppIndexed
:
381 UINT srcstride
, srcdatasize
;
386 WICColor colors
[256];
387 IWICPalette
*palette
;
390 res
= PaletteImpl_Create(&palette
);
391 if (FAILED(res
)) return res
;
393 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
395 res
= IWICPalette_GetColors(palette
, 256, colors
, &actualcolors
);
397 IWICPalette_Release(palette
);
399 if (FAILED(res
)) return res
;
401 srcstride
= prc
->Width
;
402 srcdatasize
= srcstride
* prc
->Height
;
404 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
405 if (!srcdata
) return E_OUTOFMEMORY
;
407 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
413 for (y
=0; y
<prc
->Height
; y
++) {
415 dstpixel
=(DWORD
*)dstrow
;
416 for (x
=0; x
<prc
->Width
; x
++)
417 *dstpixel
++ = colors
[*srcbyte
++];
423 HeapFree(GetProcessHeap(), 0, srcdata
);
428 case format_16bppGray
:
434 UINT srcstride
, srcdatasize
;
440 srcstride
= prc
->Width
* 2;
441 srcdatasize
= srcstride
* prc
->Height
;
443 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
444 if (!srcdata
) return E_OUTOFMEMORY
;
446 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
452 for (y
=0; y
<prc
->Height
; y
++) {
454 dstpixel
=(DWORD
*)dstrow
;
455 for (x
=0; x
<prc
->Width
; x
++)
457 *dstpixel
++ = 0xff000000|(*srcbyte
<<16)|(*srcbyte
<<8)|*srcbyte
;
465 HeapFree(GetProcessHeap(), 0, srcdata
);
470 case format_16bppBGR555
:
476 UINT srcstride
, srcdatasize
;
478 const WORD
*srcpixel
;
482 srcstride
= 2 * prc
->Width
;
483 srcdatasize
= srcstride
* prc
->Height
;
485 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
486 if (!srcdata
) return E_OUTOFMEMORY
;
488 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
494 for (y
=0; y
<prc
->Height
; y
++) {
495 srcpixel
=(const WORD
*)srcrow
;
496 dstpixel
=(DWORD
*)dstrow
;
497 for (x
=0; x
<prc
->Width
; x
++) {
500 *dstpixel
++=0xff000000 | /* constant 255 alpha */
501 ((srcval
<< 9) & 0xf80000) | /* r */
502 ((srcval
<< 4) & 0x070000) | /* r - 3 bits */
503 ((srcval
<< 6) & 0x00f800) | /* g */
504 ((srcval
<< 1) & 0x000700) | /* g - 3 bits */
505 ((srcval
<< 3) & 0x0000f8) | /* b */
506 ((srcval
>> 2) & 0x000007); /* b - 3 bits */
513 HeapFree(GetProcessHeap(), 0, srcdata
);
518 case format_16bppBGR565
:
524 UINT srcstride
, srcdatasize
;
526 const WORD
*srcpixel
;
530 srcstride
= 2 * prc
->Width
;
531 srcdatasize
= srcstride
* prc
->Height
;
533 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
534 if (!srcdata
) return E_OUTOFMEMORY
;
536 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
542 for (y
=0; y
<prc
->Height
; y
++) {
543 srcpixel
=(const WORD
*)srcrow
;
544 dstpixel
=(DWORD
*)dstrow
;
545 for (x
=0; x
<prc
->Width
; x
++) {
548 *dstpixel
++=0xff000000 | /* constant 255 alpha */
549 ((srcval
<< 8) & 0xf80000) | /* r */
550 ((srcval
<< 3) & 0x070000) | /* r - 3 bits */
551 ((srcval
<< 5) & 0x00fc00) | /* g */
552 ((srcval
>> 1) & 0x000300) | /* g - 2 bits */
553 ((srcval
<< 3) & 0x0000f8) | /* b */
554 ((srcval
>> 2) & 0x000007); /* b - 3 bits */
561 HeapFree(GetProcessHeap(), 0, srcdata
);
566 case format_16bppBGRA5551
:
572 UINT srcstride
, srcdatasize
;
574 const WORD
*srcpixel
;
578 srcstride
= 2 * prc
->Width
;
579 srcdatasize
= srcstride
* prc
->Height
;
581 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
582 if (!srcdata
) return E_OUTOFMEMORY
;
584 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
590 for (y
=0; y
<prc
->Height
; y
++) {
591 srcpixel
=(const WORD
*)srcrow
;
592 dstpixel
=(DWORD
*)dstrow
;
593 for (x
=0; x
<prc
->Width
; x
++) {
596 *dstpixel
++=((srcval
& 0x8000) ? 0xff000000 : 0) | /* alpha */
597 ((srcval
<< 9) & 0xf80000) | /* r */
598 ((srcval
<< 4) & 0x070000) | /* r - 3 bits */
599 ((srcval
<< 6) & 0x00f800) | /* g */
600 ((srcval
<< 1) & 0x000700) | /* g - 3 bits */
601 ((srcval
<< 3) & 0x0000f8) | /* b */
602 ((srcval
>> 2) & 0x000007); /* b - 3 bits */
609 HeapFree(GetProcessHeap(), 0, srcdata
);
614 case format_24bppBGR
:
620 UINT srcstride
, srcdatasize
;
622 const BYTE
*srcpixel
;
626 srcstride
= 3 * prc
->Width
;
627 srcdatasize
= srcstride
* prc
->Height
;
629 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
630 if (!srcdata
) return E_OUTOFMEMORY
;
632 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
638 for (y
=0; y
<prc
->Height
; y
++) {
641 for (x
=0; x
<prc
->Width
; x
++) {
642 *dstpixel
++=*srcpixel
++; /* blue */
643 *dstpixel
++=*srcpixel
++; /* green */
644 *dstpixel
++=*srcpixel
++; /* red */
645 *dstpixel
++=255; /* alpha */
652 HeapFree(GetProcessHeap(), 0, srcdata
);
657 case format_24bppRGB
:
663 UINT srcstride
, srcdatasize
;
665 const BYTE
*srcpixel
;
670 srcstride
= 3 * prc
->Width
;
671 srcdatasize
= srcstride
* prc
->Height
;
673 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
674 if (!srcdata
) return E_OUTOFMEMORY
;
676 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
682 for (y
=0; y
<prc
->Height
; y
++) {
685 for (x
=0; x
<prc
->Width
; x
++) {
686 tmppixel
[0]=*srcpixel
++; /* red */
687 tmppixel
[1]=*srcpixel
++; /* green */
688 tmppixel
[2]=*srcpixel
++; /* blue */
690 *dstpixel
++=tmppixel
[2]; /* blue */
691 *dstpixel
++=tmppixel
[1]; /* green */
692 *dstpixel
++=tmppixel
[0]; /* red */
693 *dstpixel
++=255; /* alpha */
700 HeapFree(GetProcessHeap(), 0, srcdata
);
705 case format_32bppBGR
:
711 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
712 if (FAILED(res
)) return res
;
714 /* set all alpha values to 255 */
715 for (y
=0; y
<prc
->Height
; y
++)
716 for (x
=0; x
<prc
->Width
; x
++)
717 pbBuffer
[cbStride
*y
+4*x
+3] = 0xff;
720 case format_32bppBGRA
:
722 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
724 case format_32bppPBGRA
:
730 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
731 if (FAILED(res
)) return res
;
733 for (y
=0; y
<prc
->Height
; y
++)
734 for (x
=0; x
<prc
->Width
; x
++)
736 BYTE alpha
= pbBuffer
[cbStride
*y
+4*x
+3];
737 if (alpha
!= 0 && alpha
!= 255)
739 pbBuffer
[cbStride
*y
+4*x
] = pbBuffer
[cbStride
*y
+4*x
] * 255 / alpha
;
740 pbBuffer
[cbStride
*y
+4*x
+1] = pbBuffer
[cbStride
*y
+4*x
+1] * 255 / alpha
;
741 pbBuffer
[cbStride
*y
+4*x
+2] = pbBuffer
[cbStride
*y
+4*x
+2] * 255 / alpha
;
746 case format_48bppRGB
:
752 UINT srcstride
, srcdatasize
;
754 const BYTE
*srcpixel
;
758 srcstride
= 6 * prc
->Width
;
759 srcdatasize
= srcstride
* prc
->Height
;
761 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
762 if (!srcdata
) return E_OUTOFMEMORY
;
764 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
770 for (y
=0; y
<prc
->Height
; y
++) {
772 dstpixel
=(DWORD
*)dstrow
;
773 for (x
=0; x
<prc
->Width
; x
++) {
774 BYTE red
, green
, blue
;
775 red
= *srcpixel
++; srcpixel
++;
776 green
= *srcpixel
++; srcpixel
++;
777 blue
= *srcpixel
++; srcpixel
++;
778 *dstpixel
++=0xff000000|red
<<16|green
<<8|blue
;
785 HeapFree(GetProcessHeap(), 0, srcdata
);
790 case format_64bppRGBA
:
796 UINT srcstride
, srcdatasize
;
798 const BYTE
*srcpixel
;
802 srcstride
= 8 * prc
->Width
;
803 srcdatasize
= srcstride
* prc
->Height
;
805 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
806 if (!srcdata
) return E_OUTOFMEMORY
;
808 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
814 for (y
=0; y
<prc
->Height
; y
++) {
816 dstpixel
=(DWORD
*)dstrow
;
817 for (x
=0; x
<prc
->Width
; x
++) {
818 BYTE red
, green
, blue
, alpha
;
819 red
= *srcpixel
++; srcpixel
++;
820 green
= *srcpixel
++; srcpixel
++;
821 blue
= *srcpixel
++; srcpixel
++;
822 alpha
= *srcpixel
++; srcpixel
++;
823 *dstpixel
++=alpha
<<24|red
<<16|green
<<8|blue
;
830 HeapFree(GetProcessHeap(), 0, srcdata
);
835 case format_32bppCMYK
:
841 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
842 if (FAILED(res
)) return res
;
844 for (y
=0; y
<prc
->Height
; y
++)
845 for (x
=0; x
<prc
->Width
; x
++)
847 BYTE
*pixel
= pbBuffer
+cbStride
*y
+4*x
;
848 BYTE c
=pixel
[0], m
=pixel
[1], y
=pixel
[2], k
=pixel
[3];
849 pixel
[0] = (255-y
)*(255-k
)/255; /* blue */
850 pixel
[1] = (255-m
)*(255-k
)/255; /* green */
851 pixel
[2] = (255-c
)*(255-k
)/255; /* red */
852 pixel
[3] = 255; /* alpha */
857 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
861 static HRESULT
copypixels_to_32bppBGR(struct FormatConverter
*This
, const WICRect
*prc
,
862 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
864 switch (source_format
)
866 case format_32bppBGR
:
867 case format_32bppBGRA
:
868 case format_32bppPBGRA
:
870 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
873 return copypixels_to_32bppBGRA(This
, prc
, cbStride
, cbBufferSize
, pbBuffer
, source_format
);
877 static HRESULT
copypixels_to_32bppPBGRA(struct FormatConverter
*This
, const WICRect
*prc
,
878 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
882 switch (source_format
)
884 case format_32bppPBGRA
:
886 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
889 hr
= copypixels_to_32bppBGRA(This
, prc
, cbStride
, cbBufferSize
, pbBuffer
, source_format
);
890 if (SUCCEEDED(hr
) && prc
)
894 for (y
=0; y
<prc
->Height
; y
++)
895 for (x
=0; x
<prc
->Width
; x
++)
897 BYTE alpha
= pbBuffer
[cbStride
*y
+4*x
+3];
900 pbBuffer
[cbStride
*y
+4*x
] = pbBuffer
[cbStride
*y
+4*x
] * alpha
/ 255;
901 pbBuffer
[cbStride
*y
+4*x
+1] = pbBuffer
[cbStride
*y
+4*x
+1] * alpha
/ 255;
902 pbBuffer
[cbStride
*y
+4*x
+2] = pbBuffer
[cbStride
*y
+4*x
+2] * alpha
/ 255;
910 static HRESULT
copypixels_to_24bppBGR(struct FormatConverter
*This
, const WICRect
*prc
,
911 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
915 switch (source_format
)
917 case format_24bppBGR
:
918 case format_24bppRGB
:
921 hr
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
922 if (SUCCEEDED(hr
) && source_format
== format_24bppRGB
)
923 reverse_bgr8(3, pbBuffer
, prc
->Width
, prc
->Height
, cbStride
);
927 case format_32bppBGR
:
928 case format_32bppBGRA
:
929 case format_32bppPBGRA
:
935 UINT srcstride
, srcdatasize
;
937 const BYTE
*srcpixel
;
941 srcstride
= 4 * prc
->Width
;
942 srcdatasize
= srcstride
* prc
->Height
;
944 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
945 if (!srcdata
) return E_OUTOFMEMORY
;
947 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
953 for (y
=0; y
<prc
->Height
; y
++) {
956 for (x
=0; x
<prc
->Width
; x
++) {
957 *dstpixel
++=*srcpixel
++; /* blue */
958 *dstpixel
++=*srcpixel
++; /* green */
959 *dstpixel
++=*srcpixel
++; /* red */
960 srcpixel
++; /* alpha */
967 HeapFree(GetProcessHeap(), 0, srcdata
);
973 case format_32bppGrayFloat
:
977 UINT srcstride
, srcdatasize
;
979 srcstride
= 4 * prc
->Width
;
980 srcdatasize
= srcstride
* prc
->Height
;
982 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
983 if (!srcdata
) return E_OUTOFMEMORY
;
985 hr
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
990 BYTE
*src
= srcdata
, *dst
= pbBuffer
;
992 for (y
= 0; y
< prc
->Height
; y
++)
994 float *gray_float
= (float *)src
;
997 for (x
= 0; x
< prc
->Width
; x
++)
999 BYTE gray
= (BYTE
)floorf(to_sRGB_component(gray_float
[x
]) * 255.0f
+ 0.51f
);
1009 HeapFree(GetProcessHeap(), 0, srcdata
);
1016 FIXME("Unimplemented conversion path!\n");
1017 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1021 static HRESULT
copypixels_to_24bppRGB(struct FormatConverter
*This
, const WICRect
*prc
,
1022 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
1026 switch (source_format
)
1028 case format_24bppBGR
:
1029 case format_24bppRGB
:
1032 hr
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1033 if (SUCCEEDED(hr
) && source_format
== format_24bppBGR
)
1034 reverse_bgr8(3, pbBuffer
, prc
->Width
, prc
->Height
, cbStride
);
1038 case format_32bppBGR
:
1039 case format_32bppBGRA
:
1040 case format_32bppPBGRA
:
1046 UINT srcstride
, srcdatasize
;
1048 const BYTE
*srcpixel
;
1053 srcstride
= 4 * prc
->Width
;
1054 srcdatasize
= srcstride
* prc
->Height
;
1056 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
1057 if (!srcdata
) return E_OUTOFMEMORY
;
1059 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
1065 for (y
=0; y
<prc
->Height
; y
++) {
1068 for (x
=0; x
<prc
->Width
; x
++) {
1069 tmppixel
[0]=*srcpixel
++; /* blue */
1070 tmppixel
[1]=*srcpixel
++; /* green */
1071 tmppixel
[2]=*srcpixel
++; /* red */
1072 srcpixel
++; /* alpha */
1074 *dstpixel
++=tmppixel
[2]; /* red */
1075 *dstpixel
++=tmppixel
[1]; /* green */
1076 *dstpixel
++=tmppixel
[0]; /* blue */
1078 srcrow
+= srcstride
;
1083 HeapFree(GetProcessHeap(), 0, srcdata
);
1089 FIXME("Unimplemented conversion path!\n");
1090 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1094 static HRESULT
copypixels_to_32bppGrayFloat(struct FormatConverter
*This
, const WICRect
*prc
,
1095 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
1099 switch (source_format
)
1101 case format_32bppBGR
:
1102 case format_32bppBGRA
:
1103 case format_32bppPBGRA
:
1104 case format_32bppGrayFloat
:
1107 hr
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1113 hr
= copypixels_to_32bppBGRA(This
, prc
, cbStride
, cbBufferSize
, pbBuffer
, source_format
);
1117 if (SUCCEEDED(hr
) && prc
&& source_format
!= format_32bppGrayFloat
)
1122 for (y
= 0; y
< prc
->Height
; y
++)
1125 for (x
= 0; x
< prc
->Width
; x
++)
1127 float gray
= (bgr
[2] * 0.2126f
+ bgr
[1] * 0.7152f
+ bgr
[0] * 0.0722f
) / 255.0f
;
1128 *(float *)bgr
= gray
;
1137 static HRESULT
copypixels_to_8bppGray(struct FormatConverter
*This
, const WICRect
*prc
,
1138 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
1142 UINT srcstride
, srcdatasize
;
1144 if (source_format
== format_8bppGray
)
1147 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1152 srcstride
= 3 * prc
->Width
;
1153 srcdatasize
= srcstride
* prc
->Height
;
1155 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
1156 if (!srcdata
) return E_OUTOFMEMORY
;
1158 hr
= copypixels_to_24bppBGR(This
, prc
, srcstride
, srcdatasize
, srcdata
, source_format
);
1159 if (SUCCEEDED(hr
) && prc
)
1162 BYTE
*src
= srcdata
, *dst
= pbBuffer
;
1164 for (y
= 0; y
< prc
->Height
; y
++)
1168 for (x
= 0; x
< prc
->Width
; x
++)
1170 float gray
= (bgr
[2] * 0.2126f
+ bgr
[1] * 0.7152f
+ bgr
[0] * 0.0722f
) / 255.0f
;
1172 gray
= to_sRGB_component(gray
) * 255.0f
;
1173 dst
[x
] = (BYTE
)floorf(gray
+ 0.51f
);
1181 HeapFree(GetProcessHeap(), 0, srcdata
);
1185 static const struct pixelformatinfo supported_formats
[] = {
1186 {format_1bppIndexed
, &GUID_WICPixelFormat1bppIndexed
, NULL
},
1187 {format_2bppIndexed
, &GUID_WICPixelFormat2bppIndexed
, NULL
},
1188 {format_4bppIndexed
, &GUID_WICPixelFormat4bppIndexed
, NULL
},
1189 {format_8bppIndexed
, &GUID_WICPixelFormat8bppIndexed
, NULL
},
1190 {format_BlackWhite
, &GUID_WICPixelFormatBlackWhite
, NULL
},
1191 {format_2bppGray
, &GUID_WICPixelFormat2bppGray
, NULL
},
1192 {format_4bppGray
, &GUID_WICPixelFormat4bppGray
, NULL
},
1193 {format_8bppGray
, &GUID_WICPixelFormat8bppGray
, copypixels_to_8bppGray
},
1194 {format_16bppGray
, &GUID_WICPixelFormat16bppGray
, NULL
},
1195 {format_16bppBGR555
, &GUID_WICPixelFormat16bppBGR555
, NULL
},
1196 {format_16bppBGR565
, &GUID_WICPixelFormat16bppBGR565
, NULL
},
1197 {format_16bppBGRA5551
, &GUID_WICPixelFormat16bppBGRA5551
, NULL
},
1198 {format_24bppBGR
, &GUID_WICPixelFormat24bppBGR
, copypixels_to_24bppBGR
},
1199 {format_24bppRGB
, &GUID_WICPixelFormat24bppRGB
, copypixels_to_24bppRGB
},
1200 {format_32bppGrayFloat
, &GUID_WICPixelFormat32bppGrayFloat
, copypixels_to_32bppGrayFloat
},
1201 {format_32bppBGR
, &GUID_WICPixelFormat32bppBGR
, copypixels_to_32bppBGR
},
1202 {format_32bppBGRA
, &GUID_WICPixelFormat32bppBGRA
, copypixels_to_32bppBGRA
},
1203 {format_32bppPBGRA
, &GUID_WICPixelFormat32bppPBGRA
, copypixels_to_32bppPBGRA
},
1204 {format_48bppRGB
, &GUID_WICPixelFormat48bppRGB
, NULL
},
1205 {format_64bppRGBA
, &GUID_WICPixelFormat64bppRGBA
, NULL
},
1206 {format_32bppCMYK
, &GUID_WICPixelFormat32bppCMYK
, NULL
},
1210 static const struct pixelformatinfo
*get_formatinfo(const WICPixelFormatGUID
*format
)
1214 for (i
=0; supported_formats
[i
].guid
; i
++)
1215 if (IsEqualGUID(supported_formats
[i
].guid
, format
)) return &supported_formats
[i
];
1220 static HRESULT WINAPI
FormatConverter_QueryInterface(IWICFormatConverter
*iface
, REFIID iid
,
1223 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1224 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1226 if (!ppv
) return E_INVALIDARG
;
1228 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1229 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
1230 IsEqualIID(&IID_IWICFormatConverter
, iid
))
1232 *ppv
= &This
->IWICFormatConverter_iface
;
1237 return E_NOINTERFACE
;
1240 IUnknown_AddRef((IUnknown
*)*ppv
);
1244 static ULONG WINAPI
FormatConverter_AddRef(IWICFormatConverter
*iface
)
1246 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1247 ULONG ref
= InterlockedIncrement(&This
->ref
);
1249 TRACE("(%p) refcount=%u\n", iface
, ref
);
1254 static ULONG WINAPI
FormatConverter_Release(IWICFormatConverter
*iface
)
1256 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1257 ULONG ref
= InterlockedDecrement(&This
->ref
);
1259 TRACE("(%p) refcount=%u\n", iface
, ref
);
1263 This
->lock
.DebugInfo
->Spare
[0] = 0;
1264 DeleteCriticalSection(&This
->lock
);
1265 if (This
->source
) IWICBitmapSource_Release(This
->source
);
1266 HeapFree(GetProcessHeap(), 0, This
);
1272 static HRESULT WINAPI
FormatConverter_GetSize(IWICFormatConverter
*iface
,
1273 UINT
*puiWidth
, UINT
*puiHeight
)
1275 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1277 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
1280 return IWICBitmapSource_GetSize(This
->source
, puiWidth
, puiHeight
);
1282 return WINCODEC_ERR_NOTINITIALIZED
;
1285 static HRESULT WINAPI
FormatConverter_GetPixelFormat(IWICFormatConverter
*iface
,
1286 WICPixelFormatGUID
*pPixelFormat
)
1288 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1290 TRACE("(%p,%p)\n", iface
, pPixelFormat
);
1293 memcpy(pPixelFormat
, This
->dst_format
->guid
, sizeof(GUID
));
1295 return WINCODEC_ERR_NOTINITIALIZED
;
1300 static HRESULT WINAPI
FormatConverter_GetResolution(IWICFormatConverter
*iface
,
1301 double *pDpiX
, double *pDpiY
)
1303 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1305 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
1308 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
1310 return WINCODEC_ERR_NOTINITIALIZED
;
1313 static HRESULT WINAPI
FormatConverter_CopyPalette(IWICFormatConverter
*iface
,
1314 IWICPalette
*pIPalette
)
1316 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
1320 static HRESULT WINAPI
FormatConverter_CopyPixels(IWICFormatConverter
*iface
,
1321 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
1323 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1326 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
1333 hr
= IWICBitmapSource_GetSize(This
->source
, &width
, &height
);
1334 if (FAILED(hr
)) return hr
;
1342 return This
->dst_format
->copy_function(This
, prc
, cbStride
, cbBufferSize
,
1343 pbBuffer
, This
->src_format
->format
);
1346 return WINCODEC_ERR_NOTINITIALIZED
;
1349 static HRESULT WINAPI
FormatConverter_Initialize(IWICFormatConverter
*iface
,
1350 IWICBitmapSource
*pISource
, REFWICPixelFormatGUID dstFormat
, WICBitmapDitherType dither
,
1351 IWICPalette
*pIPalette
, double alphaThresholdPercent
, WICBitmapPaletteType paletteTranslate
)
1353 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1354 const struct pixelformatinfo
*srcinfo
, *dstinfo
;
1359 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface
, pISource
, debugstr_guid(dstFormat
),
1360 dither
, pIPalette
, alphaThresholdPercent
, paletteTranslate
);
1362 if (pIPalette
&& !fixme
++) FIXME("ignoring palette\n");
1364 EnterCriticalSection(&This
->lock
);
1368 res
= WINCODEC_ERR_WRONGSTATE
;
1372 res
= IWICBitmapSource_GetPixelFormat(pISource
, &srcFormat
);
1373 if (FAILED(res
)) goto end
;
1375 srcinfo
= get_formatinfo(&srcFormat
);
1378 res
= WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
1379 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat
));
1383 dstinfo
= get_formatinfo(dstFormat
);
1386 res
= WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
1387 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat
));
1391 if (dstinfo
->copy_function
)
1393 IWICBitmapSource_AddRef(pISource
);
1394 This
->src_format
= srcinfo
;
1395 This
->dst_format
= dstinfo
;
1396 This
->dither
= dither
;
1397 This
->alpha_threshold
= alphaThresholdPercent
;
1398 This
->palette_type
= paletteTranslate
;
1399 This
->source
= pISource
;
1403 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat
), debugstr_guid(dstFormat
));
1404 res
= WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1409 LeaveCriticalSection(&This
->lock
);
1414 static HRESULT WINAPI
FormatConverter_CanConvert(IWICFormatConverter
*iface
,
1415 REFWICPixelFormatGUID srcPixelFormat
, REFWICPixelFormatGUID dstPixelFormat
,
1418 FormatConverter
*This
= impl_from_IWICFormatConverter(iface
);
1419 const struct pixelformatinfo
*srcinfo
, *dstinfo
;
1421 TRACE("(%p,%s,%s,%p)\n", iface
, debugstr_guid(srcPixelFormat
),
1422 debugstr_guid(dstPixelFormat
), pfCanConvert
);
1424 srcinfo
= get_formatinfo(srcPixelFormat
);
1427 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat
));
1428 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
1431 dstinfo
= get_formatinfo(dstPixelFormat
);
1434 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat
));
1435 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
1438 if (dstinfo
->copy_function
&&
1439 SUCCEEDED(dstinfo
->copy_function(This
, NULL
, 0, 0, NULL
, dstinfo
->format
)))
1440 *pfCanConvert
= TRUE
;
1443 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat
), debugstr_guid(dstPixelFormat
));
1444 *pfCanConvert
= FALSE
;
1450 static const IWICFormatConverterVtbl FormatConverter_Vtbl
= {
1451 FormatConverter_QueryInterface
,
1452 FormatConverter_AddRef
,
1453 FormatConverter_Release
,
1454 FormatConverter_GetSize
,
1455 FormatConverter_GetPixelFormat
,
1456 FormatConverter_GetResolution
,
1457 FormatConverter_CopyPalette
,
1458 FormatConverter_CopyPixels
,
1459 FormatConverter_Initialize
,
1460 FormatConverter_CanConvert
1463 HRESULT
FormatConverter_CreateInstance(REFIID iid
, void** ppv
)
1465 FormatConverter
*This
;
1468 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1472 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter
));
1473 if (!This
) return E_OUTOFMEMORY
;
1475 This
->IWICFormatConverter_iface
.lpVtbl
= &FormatConverter_Vtbl
;
1477 This
->source
= NULL
;
1478 InitializeCriticalSection(&This
->lock
);
1479 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": FormatConverter.lock");
1481 ret
= IWICFormatConverter_QueryInterface(&This
->IWICFormatConverter_iface
, iid
, ppv
);
1482 IWICFormatConverter_Release(&This
->IWICFormatConverter_iface
);