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;
51 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
52 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
54 struct pixelformatinfo {
55 enum pixelformat format;
56 const WICPixelFormatGUID *guid;
57 copyfunc copy_function;
60 typedef struct FormatConverter {
61 const IWICFormatConverterVtbl *lpVtbl;
63 IWICBitmapSource *source;
64 const struct pixelformatinfo *dst_format, *src_format;
65 WICBitmapDitherType dither;
66 double alpha_threshold;
67 WICBitmapPaletteType palette_type;
70 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
71 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
73 switch (source_format)
75 case format_1bppIndexed:
76 case format_BlackWhite:
82 UINT srcstride, srcdatasize;
91 if (source_format == format_1bppIndexed)
93 res = PaletteImpl_Create(&palette);
94 if (FAILED(res)) return res;
96 res = IWICBitmapSource_CopyPalette(This->source, palette);
98 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
100 IWICPalette_Release(palette);
102 if (FAILED(res)) return res;
106 colors[0] = 0xff000000;
107 colors[1] = 0xffffffff;
110 srcstride = (prc->Width+7)/8;
111 srcdatasize = srcstride * prc->Height;
113 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
114 if (!srcdata) return E_OUTOFMEMORY;
116 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
122 for (y=0; y<prc->Height; y++) {
123 srcbyte=(const BYTE*)srcrow;
124 dstpixel=(DWORD*)dstrow;
125 for (x=0; x<prc->Width; x+=8) {
128 *dstpixel++ = colors[srcval>>7&1];
129 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
130 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
131 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
132 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
133 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
134 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
135 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
142 HeapFree(GetProcessHeap(), 0, srcdata);
147 case format_4bppIndexed:
153 UINT srcstride, srcdatasize;
159 IWICPalette *palette;
162 res = PaletteImpl_Create(&palette);
163 if (FAILED(res)) return res;
165 res = IWICBitmapSource_CopyPalette(This->source, palette);
167 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
169 IWICPalette_Release(palette);
171 if (FAILED(res)) return res;
173 srcstride = (prc->Width+1)/2;
174 srcdatasize = srcstride * prc->Height;
176 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
177 if (!srcdata) return E_OUTOFMEMORY;
179 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
185 for (y=0; y<prc->Height; y++) {
186 srcbyte=(const BYTE*)srcrow;
187 dstpixel=(DWORD*)dstrow;
188 for (x=0; x<prc->Width; x+=2) {
191 *dstpixel++ = colors[srcval>>4];
192 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
199 HeapFree(GetProcessHeap(), 0, srcdata);
204 case format_8bppGray:
210 UINT srcstride, srcdatasize;
216 srcstride = prc->Width;
217 srcdatasize = srcstride * prc->Height;
219 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
220 if (!srcdata) return E_OUTOFMEMORY;
222 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
228 for (y=0; y<prc->Height; y++) {
229 srcbyte=(const BYTE*)srcrow;
230 dstpixel=(DWORD*)dstrow;
231 for (x=0; x<prc->Width; x++)
233 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
241 HeapFree(GetProcessHeap(), 0, srcdata);
246 case format_8bppIndexed:
252 UINT srcstride, srcdatasize;
257 WICColor colors[256];
258 IWICPalette *palette;
261 res = PaletteImpl_Create(&palette);
262 if (FAILED(res)) return res;
264 res = IWICBitmapSource_CopyPalette(This->source, palette);
266 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
268 IWICPalette_Release(palette);
270 if (FAILED(res)) return res;
272 srcstride = prc->Width;
273 srcdatasize = srcstride * prc->Height;
275 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
276 if (!srcdata) return E_OUTOFMEMORY;
278 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
284 for (y=0; y<prc->Height; y++) {
285 srcbyte=(const BYTE*)srcrow;
286 dstpixel=(DWORD*)dstrow;
287 for (x=0; x<prc->Width; x++)
288 *dstpixel++ = colors[*srcbyte++];
294 HeapFree(GetProcessHeap(), 0, srcdata);
299 case format_16bppBGR555:
305 UINT srcstride, srcdatasize;
307 const WORD *srcpixel;
311 srcstride = 2 * prc->Width;
312 srcdatasize = srcstride * prc->Height;
314 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
315 if (!srcdata) return E_OUTOFMEMORY;
317 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
323 for (y=0; y<prc->Height; y++) {
324 srcpixel=(const WORD*)srcrow;
325 dstpixel=(DWORD*)dstrow;
326 for (x=0; x<prc->Width; x++) {
329 *dstpixel++=0xff000000 | /* constant 255 alpha */
330 ((srcval << 9) & 0xf80000) | /* r */
331 ((srcval << 4) & 0x070000) | /* r - 3 bits */
332 ((srcval << 6) & 0x00f800) | /* g */
333 ((srcval << 1) & 0x000700) | /* g - 3 bits */
334 ((srcval << 3) & 0x0000f8) | /* b */
335 ((srcval >> 2) & 0x000007); /* b - 3 bits */
342 HeapFree(GetProcessHeap(), 0, srcdata);
347 case format_16bppBGR565:
353 UINT srcstride, srcdatasize;
355 const WORD *srcpixel;
359 srcstride = 2 * prc->Width;
360 srcdatasize = srcstride * prc->Height;
362 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
363 if (!srcdata) return E_OUTOFMEMORY;
365 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
371 for (y=0; y<prc->Height; y++) {
372 srcpixel=(const WORD*)srcrow;
373 dstpixel=(DWORD*)dstrow;
374 for (x=0; x<prc->Width; x++) {
377 *dstpixel++=0xff000000 | /* constant 255 alpha */
378 ((srcval << 8) & 0xf80000) | /* r */
379 ((srcval << 3) & 0x070000) | /* r - 3 bits */
380 ((srcval << 5) & 0x00fc00) | /* g */
381 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
382 ((srcval << 3) & 0x0000f8) | /* b */
383 ((srcval >> 2) & 0x000007); /* b - 3 bits */
390 HeapFree(GetProcessHeap(), 0, srcdata);
395 case format_24bppBGR:
401 UINT srcstride, srcdatasize;
403 const BYTE *srcpixel;
407 srcstride = 3 * prc->Width;
408 srcdatasize = srcstride * prc->Height;
410 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
411 if (!srcdata) return E_OUTOFMEMORY;
413 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
419 for (y=0; y<prc->Height; y++) {
422 for (x=0; x<prc->Width; x++) {
423 *dstpixel++=*srcpixel++; /* blue */
424 *dstpixel++=*srcpixel++; /* green */
425 *dstpixel++=*srcpixel++; /* red */
426 *dstpixel++=255; /* alpha */
433 HeapFree(GetProcessHeap(), 0, srcdata);
438 case format_32bppBGR:
444 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
445 if (FAILED(res)) return res;
447 /* set all alpha values to 255 */
448 for (y=0; y<prc->Height; y++)
449 for (x=0; x<prc->Width; x++)
450 pbBuffer[cbStride*y+4*x+3] = 0xff;
453 case format_32bppBGRA:
455 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
458 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
462 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
463 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
465 switch (source_format)
467 case format_32bppBGR:
468 case format_32bppBGRA:
470 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
473 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
477 static const struct pixelformatinfo supported_formats[] = {
478 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
479 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
480 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
481 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
482 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
483 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
484 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
485 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
486 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
487 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
491 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
495 for (i=0; supported_formats[i].guid; i++)
496 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
501 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
504 FormatConverter *This = (FormatConverter*)iface;
505 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
507 if (!ppv) return E_INVALIDARG;
509 if (IsEqualIID(&IID_IUnknown, iid) ||
510 IsEqualIID(&IID_IWICBitmapSource, iid) ||
511 IsEqualIID(&IID_IWICFormatConverter, iid))
518 return E_NOINTERFACE;
521 IUnknown_AddRef((IUnknown*)*ppv);
525 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
527 FormatConverter *This = (FormatConverter*)iface;
528 ULONG ref = InterlockedIncrement(&This->ref);
530 TRACE("(%p) refcount=%u\n", iface, ref);
535 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
537 FormatConverter *This = (FormatConverter*)iface;
538 ULONG ref = InterlockedDecrement(&This->ref);
540 TRACE("(%p) refcount=%u\n", iface, ref);
544 if (This->source) IWICBitmapSource_Release(This->source);
545 HeapFree(GetProcessHeap(), 0, This);
551 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
552 UINT *puiWidth, UINT *puiHeight)
554 FormatConverter *This = (FormatConverter*)iface;
556 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
559 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
561 return WINCODEC_ERR_NOTINITIALIZED;
564 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
565 WICPixelFormatGUID *pPixelFormat)
567 FormatConverter *This = (FormatConverter*)iface;
569 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
572 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
574 return WINCODEC_ERR_NOTINITIALIZED;
579 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
580 double *pDpiX, double *pDpiY)
582 FormatConverter *This = (FormatConverter*)iface;
584 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
587 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
589 return WINCODEC_ERR_NOTINITIALIZED;
592 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
593 IWICPalette *pIPalette)
595 FIXME("(%p,%p): stub\n", iface, pIPalette);
599 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
600 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
602 FormatConverter *This = (FormatConverter*)iface;
603 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
606 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
607 pbBuffer, This->src_format->format);
609 return WINCODEC_ERR_NOTINITIALIZED;
612 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
613 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
614 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
616 FormatConverter *This = (FormatConverter*)iface;
617 const struct pixelformatinfo *srcinfo, *dstinfo;
622 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
623 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
625 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
627 if (This->source) return WINCODEC_ERR_WRONGSTATE;
629 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
630 if (FAILED(res)) return res;
632 srcinfo = get_formatinfo(&srcFormat);
633 if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
635 dstinfo = get_formatinfo(dstFormat);
636 if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
638 if (dstinfo->copy_function)
640 IWICBitmapSource_AddRef(pISource);
641 This->source = pISource;
642 This->src_format = srcinfo;
643 This->dst_format = dstinfo;
644 This->dither = dither;
645 This->alpha_threshold = alphaThresholdPercent;
646 This->palette_type = paletteTranslate;
649 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
654 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
655 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
658 FormatConverter *This = (FormatConverter*)iface;
659 const struct pixelformatinfo *srcinfo, *dstinfo;
661 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
662 debugstr_guid(dstPixelFormat), pfCanConvert);
664 srcinfo = get_formatinfo(srcPixelFormat);
665 if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
667 dstinfo = get_formatinfo(dstPixelFormat);
668 if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
670 if (dstinfo->copy_function &&
671 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
672 *pfCanConvert = TRUE;
674 *pfCanConvert = FALSE;
679 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
680 FormatConverter_QueryInterface,
681 FormatConverter_AddRef,
682 FormatConverter_Release,
683 FormatConverter_GetSize,
684 FormatConverter_GetPixelFormat,
685 FormatConverter_GetResolution,
686 FormatConverter_CopyPalette,
687 FormatConverter_CopyPixels,
688 FormatConverter_Initialize,
689 FormatConverter_CanConvert
692 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
694 FormatConverter *This;
697 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
701 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
703 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
704 if (!This) return E_OUTOFMEMORY;
706 This->lpVtbl = &FormatConverter_Vtbl;
710 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
711 IUnknown_Release((IUnknown*)This);