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
;
49 typedef HRESULT (*copyfunc
)(struct FormatConverter
*This
, const WICRect
*prc
,
50 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
);
52 struct pixelformatinfo
{
53 enum pixelformat format
;
54 const WICPixelFormatGUID
*guid
;
55 copyfunc copy_function
;
58 typedef struct FormatConverter
{
59 const IWICFormatConverterVtbl
*lpVtbl
;
61 IWICBitmapSource
*source
;
62 const struct pixelformatinfo
*dst_format
, *src_format
;
63 WICBitmapDitherType dither
;
64 double alpha_threshold
;
65 WICBitmapPaletteType palette_type
;
68 static HRESULT
copypixels_to_32bppBGRA(struct FormatConverter
*This
, const WICRect
*prc
,
69 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
71 switch (source_format
)
73 case format_1bppIndexed
:
79 UINT srcstride
, srcdatasize
;
88 res
= PaletteImpl_Create(&palette
);
89 if (FAILED(res
)) return res
;
91 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
93 res
= IWICPalette_GetColors(palette
, 2, colors
, &actualcolors
);
95 IWICPalette_Release(palette
);
97 if (FAILED(res
)) return res
;
99 srcstride
= (prc
->Width
+7)/8;
100 srcdatasize
= srcstride
* prc
->Height
;
102 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
103 if (!srcdata
) return E_OUTOFMEMORY
;
105 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
111 for (y
=0; y
<prc
->Height
; y
++) {
112 srcbyte
=(const BYTE
*)srcrow
;
113 dstpixel
=(DWORD
*)dstrow
;
114 for (x
=0; x
<prc
->Width
; x
+=8) {
117 *dstpixel
++ = colors
[srcval
>>7&1];
118 if (x
+1 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>6&1];
119 if (x
+2 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>5&1];
120 if (x
+3 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>4&1];
121 if (x
+4 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>3&1];
122 if (x
+5 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>2&1];
123 if (x
+6 < prc
->Width
) *dstpixel
++ = colors
[srcval
>>1&1];
124 if (x
+7 < prc
->Width
) *dstpixel
++ = colors
[srcval
&1];
131 HeapFree(GetProcessHeap(), 0, srcdata
);
136 case format_4bppIndexed
:
142 UINT srcstride
, srcdatasize
;
148 IWICPalette
*palette
;
151 res
= PaletteImpl_Create(&palette
);
152 if (FAILED(res
)) return res
;
154 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
156 res
= IWICPalette_GetColors(palette
, 16, colors
, &actualcolors
);
158 IWICPalette_Release(palette
);
160 if (FAILED(res
)) return res
;
162 srcstride
= (prc
->Width
+1)/2;
163 srcdatasize
= srcstride
* prc
->Height
;
165 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
166 if (!srcdata
) return E_OUTOFMEMORY
;
168 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
174 for (y
=0; y
<prc
->Height
; y
++) {
175 srcbyte
=(const BYTE
*)srcrow
;
176 dstpixel
=(DWORD
*)dstrow
;
177 for (x
=0; x
<prc
->Width
; x
+=2) {
180 *dstpixel
++ = colors
[srcval
>>4];
181 if (x
+1 < prc
->Width
) *dstpixel
++ = colors
[srcval
&0xf];
188 HeapFree(GetProcessHeap(), 0, srcdata
);
193 case format_8bppIndexed
:
199 UINT srcstride
, srcdatasize
;
204 WICColor colors
[256];
205 IWICPalette
*palette
;
208 res
= PaletteImpl_Create(&palette
);
209 if (FAILED(res
)) return res
;
211 res
= IWICBitmapSource_CopyPalette(This
->source
, palette
);
213 res
= IWICPalette_GetColors(palette
, 256, colors
, &actualcolors
);
215 IWICPalette_Release(palette
);
217 if (FAILED(res
)) return res
;
219 srcstride
= prc
->Width
;
220 srcdatasize
= srcstride
* prc
->Height
;
222 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
223 if (!srcdata
) return E_OUTOFMEMORY
;
225 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
231 for (y
=0; y
<prc
->Height
; y
++) {
232 srcbyte
=(const BYTE
*)srcrow
;
233 dstpixel
=(DWORD
*)dstrow
;
234 for (x
=0; x
<prc
->Width
; x
++)
235 *dstpixel
++ = colors
[*srcbyte
++];
241 HeapFree(GetProcessHeap(), 0, srcdata
);
246 case format_16bppBGR555
:
252 UINT srcstride
, srcdatasize
;
254 const WORD
*srcpixel
;
258 srcstride
= 2 * prc
->Width
;
259 srcdatasize
= srcstride
* prc
->Height
;
261 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
262 if (!srcdata
) return E_OUTOFMEMORY
;
264 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
270 for (y
=0; y
<prc
->Height
; y
++) {
271 srcpixel
=(const WORD
*)srcrow
;
272 dstpixel
=(DWORD
*)dstrow
;
273 for (x
=0; x
<prc
->Width
; x
++) {
276 *dstpixel
++=0xff000000 | /* constant 255 alpha */
277 ((srcval
<< 9) & 0xf80000) | /* r */
278 ((srcval
<< 4) & 0x070000) | /* r - 3 bits */
279 ((srcval
<< 6) & 0x00f800) | /* g */
280 ((srcval
<< 1) & 0x000700) | /* g - 3 bits */
281 ((srcval
<< 3) & 0x0000f8) | /* b */
282 ((srcval
>> 2) & 0x000007); /* b - 3 bits */
289 HeapFree(GetProcessHeap(), 0, srcdata
);
294 case format_16bppBGR565
:
300 UINT srcstride
, srcdatasize
;
302 const WORD
*srcpixel
;
306 srcstride
= 2 * prc
->Width
;
307 srcdatasize
= srcstride
* prc
->Height
;
309 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
310 if (!srcdata
) return E_OUTOFMEMORY
;
312 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
318 for (y
=0; y
<prc
->Height
; y
++) {
319 srcpixel
=(const WORD
*)srcrow
;
320 dstpixel
=(DWORD
*)dstrow
;
321 for (x
=0; x
<prc
->Width
; x
++) {
324 *dstpixel
++=0xff000000 | /* constant 255 alpha */
325 ((srcval
<< 8) & 0xf80000) | /* r */
326 ((srcval
<< 3) & 0x070000) | /* r - 3 bits */
327 ((srcval
<< 5) & 0x00fc00) | /* g */
328 ((srcval
>> 1) & 0x000300) | /* g - 2 bits */
329 ((srcval
<< 3) & 0x0000f8) | /* b */
330 ((srcval
>> 2) & 0x000007); /* b - 3 bits */
337 HeapFree(GetProcessHeap(), 0, srcdata
);
342 case format_24bppBGR
:
348 UINT srcstride
, srcdatasize
;
350 const BYTE
*srcpixel
;
354 srcstride
= 3 * prc
->Width
;
355 srcdatasize
= srcstride
* prc
->Height
;
357 srcdata
= HeapAlloc(GetProcessHeap(), 0, srcdatasize
);
358 if (!srcdata
) return E_OUTOFMEMORY
;
360 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, srcstride
, srcdatasize
, srcdata
);
366 for (y
=0; y
<prc
->Height
; y
++) {
369 for (x
=0; x
<prc
->Width
; x
++) {
370 *dstpixel
++=*srcpixel
++; /* blue */
371 *dstpixel
++=*srcpixel
++; /* green */
372 *dstpixel
++=*srcpixel
++; /* red */
373 *dstpixel
++=255; /* alpha */
380 HeapFree(GetProcessHeap(), 0, srcdata
);
385 case format_32bppBGR
:
391 res
= IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
392 if (FAILED(res
)) return res
;
394 /* set all alpha values to 255 */
395 for (y
=0; y
<prc
->Height
; y
++)
396 for (x
=0; x
<prc
->Width
; x
++)
397 pbBuffer
[cbStride
*y
+4*x
+3] = 0xff;
400 case format_32bppBGRA
:
402 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
405 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
409 static HRESULT
copypixels_to_32bppBGR(struct FormatConverter
*This
, const WICRect
*prc
,
410 UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
, enum pixelformat source_format
)
412 switch (source_format
)
414 case format_32bppBGR
:
415 case format_32bppBGRA
:
417 return IWICBitmapSource_CopyPixels(This
->source
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
420 return copypixels_to_32bppBGRA(This
, prc
, cbStride
, cbBufferSize
, pbBuffer
, source_format
);
424 static const struct pixelformatinfo supported_formats
[] = {
425 {format_1bppIndexed
, &GUID_WICPixelFormat1bppIndexed
, NULL
},
426 {format_4bppIndexed
, &GUID_WICPixelFormat4bppIndexed
, NULL
},
427 {format_8bppIndexed
, &GUID_WICPixelFormat8bppIndexed
, NULL
},
428 {format_16bppBGR555
, &GUID_WICPixelFormat16bppBGR555
, NULL
},
429 {format_16bppBGR565
, &GUID_WICPixelFormat16bppBGR565
, NULL
},
430 {format_24bppBGR
, &GUID_WICPixelFormat24bppBGR
, NULL
},
431 {format_32bppBGR
, &GUID_WICPixelFormat32bppBGR
, copypixels_to_32bppBGR
},
432 {format_32bppBGRA
, &GUID_WICPixelFormat32bppBGRA
, copypixels_to_32bppBGRA
},
436 static const struct pixelformatinfo
*get_formatinfo(const WICPixelFormatGUID
*format
)
440 for (i
=0; supported_formats
[i
].guid
; i
++)
441 if (IsEqualGUID(supported_formats
[i
].guid
, format
)) return &supported_formats
[i
];
446 static HRESULT WINAPI
FormatConverter_QueryInterface(IWICFormatConverter
*iface
, REFIID iid
,
449 FormatConverter
*This
= (FormatConverter
*)iface
;
450 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
452 if (!ppv
) return E_INVALIDARG
;
454 if (IsEqualIID(&IID_IUnknown
, iid
) ||
455 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
456 IsEqualIID(&IID_IWICFormatConverter
, iid
))
463 return E_NOINTERFACE
;
466 IUnknown_AddRef((IUnknown
*)*ppv
);
470 static ULONG WINAPI
FormatConverter_AddRef(IWICFormatConverter
*iface
)
472 FormatConverter
*This
= (FormatConverter
*)iface
;
473 ULONG ref
= InterlockedIncrement(&This
->ref
);
475 TRACE("(%p) refcount=%u\n", iface
, ref
);
480 static ULONG WINAPI
FormatConverter_Release(IWICFormatConverter
*iface
)
482 FormatConverter
*This
= (FormatConverter
*)iface
;
483 ULONG ref
= InterlockedDecrement(&This
->ref
);
485 TRACE("(%p) refcount=%u\n", iface
, ref
);
489 if (This
->source
) IWICBitmapSource_Release(This
->source
);
490 HeapFree(GetProcessHeap(), 0, This
);
496 static HRESULT WINAPI
FormatConverter_GetSize(IWICFormatConverter
*iface
,
497 UINT
*puiWidth
, UINT
*puiHeight
)
499 FormatConverter
*This
= (FormatConverter
*)iface
;
501 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
504 return IWICBitmapSource_GetSize(This
->source
, puiWidth
, puiHeight
);
506 return WINCODEC_ERR_NOTINITIALIZED
;
509 static HRESULT WINAPI
FormatConverter_GetPixelFormat(IWICFormatConverter
*iface
,
510 WICPixelFormatGUID
*pPixelFormat
)
512 FormatConverter
*This
= (FormatConverter
*)iface
;
514 TRACE("(%p,%p): stub\n", iface
, pPixelFormat
);
517 memcpy(pPixelFormat
, This
->dst_format
->guid
, sizeof(GUID
));
519 return WINCODEC_ERR_NOTINITIALIZED
;
524 static HRESULT WINAPI
FormatConverter_GetResolution(IWICFormatConverter
*iface
,
525 double *pDpiX
, double *pDpiY
)
527 FormatConverter
*This
= (FormatConverter
*)iface
;
529 TRACE("(%p,%p,%p): stub\n", iface
, pDpiX
, pDpiY
);
532 return IWICBitmapSource_GetResolution(This
->source
, pDpiX
, pDpiY
);
534 return WINCODEC_ERR_NOTINITIALIZED
;
537 static HRESULT WINAPI
FormatConverter_CopyPalette(IWICFormatConverter
*iface
,
538 IWICPalette
*pIPalette
)
540 FIXME("(%p,%p): stub\n", iface
, pIPalette
);
544 static HRESULT WINAPI
FormatConverter_CopyPixels(IWICFormatConverter
*iface
,
545 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
547 FormatConverter
*This
= (FormatConverter
*)iface
;
548 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
551 return This
->dst_format
->copy_function(This
, prc
, cbStride
, cbBufferSize
,
552 pbBuffer
, This
->src_format
->format
);
554 return WINCODEC_ERR_NOTINITIALIZED
;
557 static HRESULT WINAPI
FormatConverter_Initialize(IWICFormatConverter
*iface
,
558 IWICBitmapSource
*pISource
, REFWICPixelFormatGUID dstFormat
, WICBitmapDitherType dither
,
559 IWICPalette
*pIPalette
, double alphaThresholdPercent
, WICBitmapPaletteType paletteTranslate
)
561 FormatConverter
*This
= (FormatConverter
*)iface
;
562 const struct pixelformatinfo
*srcinfo
, *dstinfo
;
567 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface
, pISource
, debugstr_guid(dstFormat
),
568 dither
, pIPalette
, alphaThresholdPercent
, paletteTranslate
);
570 if (pIPalette
&& !fixme
++) FIXME("ignoring palette\n");
572 if (This
->source
) return WINCODEC_ERR_WRONGSTATE
;
574 res
= IWICBitmapSource_GetPixelFormat(pISource
, &srcFormat
);
575 if (FAILED(res
)) return res
;
577 srcinfo
= get_formatinfo(&srcFormat
);
578 if (!srcinfo
) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
580 dstinfo
= get_formatinfo(dstFormat
);
581 if (!dstinfo
) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
583 if (dstinfo
->copy_function
)
585 IWICBitmapSource_AddRef(pISource
);
586 This
->source
= pISource
;
587 This
->src_format
= srcinfo
;
588 This
->dst_format
= dstinfo
;
589 This
->dither
= dither
;
590 This
->alpha_threshold
= alphaThresholdPercent
;
591 This
->palette_type
= paletteTranslate
;
594 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
599 static HRESULT WINAPI
FormatConverter_CanConvert(IWICFormatConverter
*iface
,
600 REFWICPixelFormatGUID srcPixelFormat
, REFWICPixelFormatGUID dstPixelFormat
,
603 FormatConverter
*This
= (FormatConverter
*)iface
;
604 const struct pixelformatinfo
*srcinfo
, *dstinfo
;
606 TRACE("(%p,%s,%s,%p)\n", iface
, debugstr_guid(srcPixelFormat
),
607 debugstr_guid(dstPixelFormat
), pfCanConvert
);
609 srcinfo
= get_formatinfo(srcPixelFormat
);
610 if (!srcinfo
) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
612 dstinfo
= get_formatinfo(dstPixelFormat
);
613 if (!dstinfo
) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT
;
615 if (dstinfo
->copy_function
&&
616 SUCCEEDED(dstinfo
->copy_function(This
, NULL
, 0, 0, NULL
, dstinfo
->format
)))
617 *pfCanConvert
= TRUE
;
619 *pfCanConvert
= FALSE
;
624 static const IWICFormatConverterVtbl FormatConverter_Vtbl
= {
625 FormatConverter_QueryInterface
,
626 FormatConverter_AddRef
,
627 FormatConverter_Release
,
628 FormatConverter_GetSize
,
629 FormatConverter_GetPixelFormat
,
630 FormatConverter_GetResolution
,
631 FormatConverter_CopyPalette
,
632 FormatConverter_CopyPixels
,
633 FormatConverter_Initialize
,
634 FormatConverter_CanConvert
637 HRESULT
FormatConverter_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
639 FormatConverter
*This
;
642 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
646 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
648 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter
));
649 if (!This
) return E_OUTOFMEMORY
;
651 This
->lpVtbl
= &FormatConverter_Vtbl
;
655 ret
= IUnknown_QueryInterface((IUnknown
*)This
, iid
, ppv
);
656 IUnknown_Release((IUnknown
*)This
);