windowscodecs: Do not assume that vtable is the first element of the object, avoid...
[wine/multimedia.git] / dlls / windowscodecs / converter.c
blob8611560ca1b6512c352e7a84b0abc088c43f8851
1 /*
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
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "wincodec.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 struct FormatConverter;
38 enum pixelformat {
39 format_1bppIndexed,
40 format_2bppIndexed,
41 format_4bppIndexed,
42 format_8bppIndexed,
43 format_BlackWhite,
44 format_2bppGray,
45 format_4bppGray,
46 format_8bppGray,
47 format_16bppGray,
48 format_16bppBGR555,
49 format_16bppBGR565,
50 format_16bppBGRA5551,
51 format_24bppBGR,
52 format_32bppBGR,
53 format_32bppBGRA,
54 format_32bppPBGRA,
55 format_48bppRGB,
56 format_64bppRGBA,
57 format_32bppCMYK,
60 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
61 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
63 struct pixelformatinfo {
64 enum pixelformat format;
65 const WICPixelFormatGUID *guid;
66 copyfunc copy_function;
69 typedef struct FormatConverter {
70 IWICFormatConverter IWICFormatConverter_iface;
71 LONG ref;
72 IWICBitmapSource *source;
73 const struct pixelformatinfo *dst_format, *src_format;
74 WICBitmapDitherType dither;
75 double alpha_threshold;
76 WICBitmapPaletteType palette_type;
77 CRITICAL_SECTION lock; /* must be held when initialized */
78 } FormatConverter;
80 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
82 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
85 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
86 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
88 switch (source_format)
90 case format_1bppIndexed:
91 case format_BlackWhite:
92 if (prc)
94 HRESULT res;
95 UINT x, y;
96 BYTE *srcdata;
97 UINT srcstride, srcdatasize;
98 const BYTE *srcrow;
99 const BYTE *srcbyte;
100 BYTE *dstrow;
101 DWORD *dstpixel;
102 WICColor colors[2];
103 IWICPalette *palette;
104 UINT actualcolors;
106 res = PaletteImpl_Create(&palette);
107 if (FAILED(res)) return res;
109 if (source_format == format_1bppIndexed)
110 res = IWICBitmapSource_CopyPalette(This->source, palette);
111 else
112 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
114 if (SUCCEEDED(res))
115 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
117 IWICPalette_Release(palette);
118 if (FAILED(res)) return res;
120 srcstride = (prc->Width+7)/8;
121 srcdatasize = srcstride * prc->Height;
123 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
124 if (!srcdata) return E_OUTOFMEMORY;
126 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
128 if (SUCCEEDED(res))
130 srcrow = srcdata;
131 dstrow = pbBuffer;
132 for (y=0; y<prc->Height; y++) {
133 srcbyte = srcrow;
134 dstpixel=(DWORD*)dstrow;
135 for (x=0; x<prc->Width; x+=8) {
136 BYTE srcval;
137 srcval=*srcbyte++;
138 *dstpixel++ = colors[srcval>>7&1];
139 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
140 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
141 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
142 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
143 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
144 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
145 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
147 srcrow += srcstride;
148 dstrow += cbStride;
152 HeapFree(GetProcessHeap(), 0, srcdata);
154 return res;
156 return S_OK;
157 case format_2bppIndexed:
158 case format_2bppGray:
159 if (prc)
161 HRESULT res;
162 UINT x, y;
163 BYTE *srcdata;
164 UINT srcstride, srcdatasize;
165 const BYTE *srcrow;
166 const BYTE *srcbyte;
167 BYTE *dstrow;
168 DWORD *dstpixel;
169 WICColor colors[4];
170 IWICPalette *palette;
171 UINT actualcolors;
173 res = PaletteImpl_Create(&palette);
174 if (FAILED(res)) return res;
176 if (source_format == format_2bppIndexed)
177 res = IWICBitmapSource_CopyPalette(This->source, palette);
178 else
179 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
181 if (SUCCEEDED(res))
182 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
184 IWICPalette_Release(palette);
185 if (FAILED(res)) return res;
187 srcstride = (prc->Width+3)/4;
188 srcdatasize = srcstride * prc->Height;
190 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
191 if (!srcdata) return E_OUTOFMEMORY;
193 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
195 if (SUCCEEDED(res))
197 srcrow = srcdata;
198 dstrow = pbBuffer;
199 for (y=0; y<prc->Height; y++) {
200 srcbyte = srcrow;
201 dstpixel=(DWORD*)dstrow;
202 for (x=0; x<prc->Width; x+=4) {
203 BYTE srcval;
204 srcval=*srcbyte++;
205 *dstpixel++ = colors[srcval>>6];
206 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
207 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
208 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
210 srcrow += srcstride;
211 dstrow += cbStride;
215 HeapFree(GetProcessHeap(), 0, srcdata);
217 return res;
219 return S_OK;
220 case format_4bppIndexed:
221 case format_4bppGray:
222 if (prc)
224 HRESULT res;
225 UINT x, y;
226 BYTE *srcdata;
227 UINT srcstride, srcdatasize;
228 const BYTE *srcrow;
229 const BYTE *srcbyte;
230 BYTE *dstrow;
231 DWORD *dstpixel;
232 WICColor colors[16];
233 IWICPalette *palette;
234 UINT actualcolors;
236 res = PaletteImpl_Create(&palette);
237 if (FAILED(res)) return res;
239 if (source_format == format_4bppIndexed)
240 res = IWICBitmapSource_CopyPalette(This->source, palette);
241 else
242 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
244 if (SUCCEEDED(res))
245 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
247 IWICPalette_Release(palette);
248 if (FAILED(res)) return res;
250 srcstride = (prc->Width+1)/2;
251 srcdatasize = srcstride * prc->Height;
253 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
254 if (!srcdata) return E_OUTOFMEMORY;
256 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
258 if (SUCCEEDED(res))
260 srcrow = srcdata;
261 dstrow = pbBuffer;
262 for (y=0; y<prc->Height; y++) {
263 srcbyte = srcrow;
264 dstpixel=(DWORD*)dstrow;
265 for (x=0; x<prc->Width; x+=2) {
266 BYTE srcval;
267 srcval=*srcbyte++;
268 *dstpixel++ = colors[srcval>>4];
269 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
271 srcrow += srcstride;
272 dstrow += cbStride;
276 HeapFree(GetProcessHeap(), 0, srcdata);
278 return res;
280 return S_OK;
281 case format_8bppGray:
282 if (prc)
284 HRESULT res;
285 UINT x, y;
286 BYTE *srcdata;
287 UINT srcstride, srcdatasize;
288 const BYTE *srcrow;
289 const BYTE *srcbyte;
290 BYTE *dstrow;
291 DWORD *dstpixel;
293 srcstride = prc->Width;
294 srcdatasize = srcstride * prc->Height;
296 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
297 if (!srcdata) return E_OUTOFMEMORY;
299 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
301 if (SUCCEEDED(res))
303 srcrow = srcdata;
304 dstrow = pbBuffer;
305 for (y=0; y<prc->Height; y++) {
306 srcbyte = srcrow;
307 dstpixel=(DWORD*)dstrow;
308 for (x=0; x<prc->Width; x++)
310 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
311 srcbyte++;
313 srcrow += srcstride;
314 dstrow += cbStride;
318 HeapFree(GetProcessHeap(), 0, srcdata);
320 return res;
322 return S_OK;
323 case format_8bppIndexed:
324 if (prc)
326 HRESULT res;
327 UINT x, y;
328 BYTE *srcdata;
329 UINT srcstride, srcdatasize;
330 const BYTE *srcrow;
331 const BYTE *srcbyte;
332 BYTE *dstrow;
333 DWORD *dstpixel;
334 WICColor colors[256];
335 IWICPalette *palette;
336 UINT actualcolors;
338 res = PaletteImpl_Create(&palette);
339 if (FAILED(res)) return res;
341 res = IWICBitmapSource_CopyPalette(This->source, palette);
342 if (SUCCEEDED(res))
343 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
345 IWICPalette_Release(palette);
347 if (FAILED(res)) return res;
349 srcstride = prc->Width;
350 srcdatasize = srcstride * prc->Height;
352 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
353 if (!srcdata) return E_OUTOFMEMORY;
355 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
357 if (SUCCEEDED(res))
359 srcrow = srcdata;
360 dstrow = pbBuffer;
361 for (y=0; y<prc->Height; y++) {
362 srcbyte = srcrow;
363 dstpixel=(DWORD*)dstrow;
364 for (x=0; x<prc->Width; x++)
365 *dstpixel++ = colors[*srcbyte++];
366 srcrow += srcstride;
367 dstrow += cbStride;
371 HeapFree(GetProcessHeap(), 0, srcdata);
373 return res;
375 return S_OK;
376 case format_16bppGray:
377 if (prc)
379 HRESULT res;
380 UINT x, y;
381 BYTE *srcdata;
382 UINT srcstride, srcdatasize;
383 const BYTE *srcrow;
384 const BYTE *srcbyte;
385 BYTE *dstrow;
386 DWORD *dstpixel;
388 srcstride = prc->Width * 2;
389 srcdatasize = srcstride * prc->Height;
391 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
392 if (!srcdata) return E_OUTOFMEMORY;
394 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
396 if (SUCCEEDED(res))
398 srcrow = srcdata;
399 dstrow = pbBuffer;
400 for (y=0; y<prc->Height; y++) {
401 srcbyte = srcrow;
402 dstpixel=(DWORD*)dstrow;
403 for (x=0; x<prc->Width; x++)
405 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
406 srcbyte+=2;
408 srcrow += srcstride;
409 dstrow += cbStride;
413 HeapFree(GetProcessHeap(), 0, srcdata);
415 return res;
417 return S_OK;
418 case format_16bppBGR555:
419 if (prc)
421 HRESULT res;
422 UINT x, y;
423 BYTE *srcdata;
424 UINT srcstride, srcdatasize;
425 const BYTE *srcrow;
426 const WORD *srcpixel;
427 BYTE *dstrow;
428 DWORD *dstpixel;
430 srcstride = 2 * prc->Width;
431 srcdatasize = srcstride * prc->Height;
433 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
434 if (!srcdata) return E_OUTOFMEMORY;
436 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
438 if (SUCCEEDED(res))
440 srcrow = srcdata;
441 dstrow = pbBuffer;
442 for (y=0; y<prc->Height; y++) {
443 srcpixel=(const WORD*)srcrow;
444 dstpixel=(DWORD*)dstrow;
445 for (x=0; x<prc->Width; x++) {
446 WORD srcval;
447 srcval=*srcpixel++;
448 *dstpixel++=0xff000000 | /* constant 255 alpha */
449 ((srcval << 9) & 0xf80000) | /* r */
450 ((srcval << 4) & 0x070000) | /* r - 3 bits */
451 ((srcval << 6) & 0x00f800) | /* g */
452 ((srcval << 1) & 0x000700) | /* g - 3 bits */
453 ((srcval << 3) & 0x0000f8) | /* b */
454 ((srcval >> 2) & 0x000007); /* b - 3 bits */
456 srcrow += srcstride;
457 dstrow += cbStride;
461 HeapFree(GetProcessHeap(), 0, srcdata);
463 return res;
465 return S_OK;
466 case format_16bppBGR565:
467 if (prc)
469 HRESULT res;
470 UINT x, y;
471 BYTE *srcdata;
472 UINT srcstride, srcdatasize;
473 const BYTE *srcrow;
474 const WORD *srcpixel;
475 BYTE *dstrow;
476 DWORD *dstpixel;
478 srcstride = 2 * prc->Width;
479 srcdatasize = srcstride * prc->Height;
481 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
482 if (!srcdata) return E_OUTOFMEMORY;
484 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
486 if (SUCCEEDED(res))
488 srcrow = srcdata;
489 dstrow = pbBuffer;
490 for (y=0; y<prc->Height; y++) {
491 srcpixel=(const WORD*)srcrow;
492 dstpixel=(DWORD*)dstrow;
493 for (x=0; x<prc->Width; x++) {
494 WORD srcval;
495 srcval=*srcpixel++;
496 *dstpixel++=0xff000000 | /* constant 255 alpha */
497 ((srcval << 8) & 0xf80000) | /* r */
498 ((srcval << 3) & 0x070000) | /* r - 3 bits */
499 ((srcval << 5) & 0x00fc00) | /* g */
500 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
501 ((srcval << 3) & 0x0000f8) | /* b */
502 ((srcval >> 2) & 0x000007); /* b - 3 bits */
504 srcrow += srcstride;
505 dstrow += cbStride;
509 HeapFree(GetProcessHeap(), 0, srcdata);
511 return res;
513 return S_OK;
514 case format_16bppBGRA5551:
515 if (prc)
517 HRESULT res;
518 UINT x, y;
519 BYTE *srcdata;
520 UINT srcstride, srcdatasize;
521 const BYTE *srcrow;
522 const WORD *srcpixel;
523 BYTE *dstrow;
524 DWORD *dstpixel;
526 srcstride = 2 * prc->Width;
527 srcdatasize = srcstride * prc->Height;
529 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
530 if (!srcdata) return E_OUTOFMEMORY;
532 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
534 if (SUCCEEDED(res))
536 srcrow = srcdata;
537 dstrow = pbBuffer;
538 for (y=0; y<prc->Height; y++) {
539 srcpixel=(const WORD*)srcrow;
540 dstpixel=(DWORD*)dstrow;
541 for (x=0; x<prc->Width; x++) {
542 WORD srcval;
543 srcval=*srcpixel++;
544 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
545 ((srcval << 9) & 0xf80000) | /* r */
546 ((srcval << 4) & 0x070000) | /* r - 3 bits */
547 ((srcval << 6) & 0x00f800) | /* g */
548 ((srcval << 1) & 0x000700) | /* g - 3 bits */
549 ((srcval << 3) & 0x0000f8) | /* b */
550 ((srcval >> 2) & 0x000007); /* b - 3 bits */
552 srcrow += srcstride;
553 dstrow += cbStride;
557 HeapFree(GetProcessHeap(), 0, srcdata);
559 return res;
561 return S_OK;
562 case format_24bppBGR:
563 if (prc)
565 HRESULT res;
566 UINT x, y;
567 BYTE *srcdata;
568 UINT srcstride, srcdatasize;
569 const BYTE *srcrow;
570 const BYTE *srcpixel;
571 BYTE *dstrow;
572 BYTE *dstpixel;
574 srcstride = 3 * prc->Width;
575 srcdatasize = srcstride * prc->Height;
577 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
578 if (!srcdata) return E_OUTOFMEMORY;
580 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
582 if (SUCCEEDED(res))
584 srcrow = srcdata;
585 dstrow = pbBuffer;
586 for (y=0; y<prc->Height; y++) {
587 srcpixel=srcrow;
588 dstpixel=dstrow;
589 for (x=0; x<prc->Width; x++) {
590 *dstpixel++=*srcpixel++; /* blue */
591 *dstpixel++=*srcpixel++; /* green */
592 *dstpixel++=*srcpixel++; /* red */
593 *dstpixel++=255; /* alpha */
595 srcrow += srcstride;
596 dstrow += cbStride;
600 HeapFree(GetProcessHeap(), 0, srcdata);
602 return res;
604 return S_OK;
605 case format_32bppBGR:
606 if (prc)
608 HRESULT res;
609 UINT x, y;
611 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
612 if (FAILED(res)) return res;
614 /* set all alpha values to 255 */
615 for (y=0; y<prc->Height; y++)
616 for (x=0; x<prc->Width; x++)
617 pbBuffer[cbStride*y+4*x+3] = 0xff;
619 return S_OK;
620 case format_32bppBGRA:
621 if (prc)
622 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
623 return S_OK;
624 case format_32bppPBGRA:
625 if (prc)
627 HRESULT res;
628 UINT x, y;
630 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
631 if (FAILED(res)) return res;
633 for (y=0; y<prc->Height; y++)
634 for (x=0; x<prc->Width; x++)
636 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
637 if (alpha != 0 && alpha != 255)
639 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
640 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
641 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
645 return S_OK;
646 case format_48bppRGB:
647 if (prc)
649 HRESULT res;
650 UINT x, y;
651 BYTE *srcdata;
652 UINT srcstride, srcdatasize;
653 const BYTE *srcrow;
654 const BYTE *srcpixel;
655 BYTE *dstrow;
656 DWORD *dstpixel;
658 srcstride = 6 * prc->Width;
659 srcdatasize = srcstride * prc->Height;
661 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
662 if (!srcdata) return E_OUTOFMEMORY;
664 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
666 if (SUCCEEDED(res))
668 srcrow = srcdata;
669 dstrow = pbBuffer;
670 for (y=0; y<prc->Height; y++) {
671 srcpixel=srcrow;
672 dstpixel=(DWORD*)dstrow;
673 for (x=0; x<prc->Width; x++) {
674 BYTE red, green, blue;
675 red = *srcpixel++; srcpixel++;
676 green = *srcpixel++; srcpixel++;
677 blue = *srcpixel++; srcpixel++;
678 *dstpixel++=0xff000000|red<<16|green<<8|blue;
680 srcrow += srcstride;
681 dstrow += cbStride;
685 HeapFree(GetProcessHeap(), 0, srcdata);
687 return res;
689 return S_OK;
690 case format_64bppRGBA:
691 if (prc)
693 HRESULT res;
694 UINT x, y;
695 BYTE *srcdata;
696 UINT srcstride, srcdatasize;
697 const BYTE *srcrow;
698 const BYTE *srcpixel;
699 BYTE *dstrow;
700 DWORD *dstpixel;
702 srcstride = 8 * prc->Width;
703 srcdatasize = srcstride * prc->Height;
705 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
706 if (!srcdata) return E_OUTOFMEMORY;
708 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
710 if (SUCCEEDED(res))
712 srcrow = srcdata;
713 dstrow = pbBuffer;
714 for (y=0; y<prc->Height; y++) {
715 srcpixel=srcrow;
716 dstpixel=(DWORD*)dstrow;
717 for (x=0; x<prc->Width; x++) {
718 BYTE red, green, blue, alpha;
719 red = *srcpixel++; srcpixel++;
720 green = *srcpixel++; srcpixel++;
721 blue = *srcpixel++; srcpixel++;
722 alpha = *srcpixel++; srcpixel++;
723 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
725 srcrow += srcstride;
726 dstrow += cbStride;
730 HeapFree(GetProcessHeap(), 0, srcdata);
732 return res;
734 return S_OK;
735 case format_32bppCMYK:
736 if (prc)
738 HRESULT res;
739 UINT x, y;
741 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
742 if (FAILED(res)) return res;
744 for (y=0; y<prc->Height; y++)
745 for (x=0; x<prc->Width; x++)
747 BYTE *pixel = pbBuffer+cbStride*y+4*x;
748 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
749 pixel[0] = (255-y)*(255-k)/255; /* blue */
750 pixel[1] = (255-m)*(255-k)/255; /* green */
751 pixel[2] = (255-c)*(255-k)/255; /* red */
752 pixel[3] = 255; /* alpha */
755 return S_OK;
756 default:
757 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
761 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
762 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
764 switch (source_format)
766 case format_32bppBGR:
767 case format_32bppBGRA:
768 case format_32bppPBGRA:
769 if (prc)
770 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
771 return S_OK;
772 default:
773 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
777 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
778 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
780 HRESULT hr;
782 switch (source_format)
784 case format_32bppPBGRA:
785 if (prc)
786 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
787 return S_OK;
788 default:
789 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
790 if (SUCCEEDED(hr) && prc)
792 UINT x, y;
794 for (y=0; y<prc->Height; y++)
795 for (x=0; x<prc->Width; x++)
797 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
798 if (alpha != 255)
800 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
801 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
802 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
806 return hr;
810 static const struct pixelformatinfo supported_formats[] = {
811 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
812 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
813 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
814 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
815 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
816 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
817 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
818 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
819 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
820 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
821 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
822 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
823 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
824 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
825 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
826 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
827 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
828 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
829 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
833 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
835 UINT i;
837 for (i=0; supported_formats[i].guid; i++)
838 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
840 return NULL;
843 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
844 void **ppv)
846 FormatConverter *This = impl_from_IWICFormatConverter(iface);
847 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
849 if (!ppv) return E_INVALIDARG;
851 if (IsEqualIID(&IID_IUnknown, iid) ||
852 IsEqualIID(&IID_IWICBitmapSource, iid) ||
853 IsEqualIID(&IID_IWICFormatConverter, iid))
855 *ppv = &This->IWICFormatConverter_iface;
857 else
859 *ppv = NULL;
860 return E_NOINTERFACE;
863 IUnknown_AddRef((IUnknown*)*ppv);
864 return S_OK;
867 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
869 FormatConverter *This = impl_from_IWICFormatConverter(iface);
870 ULONG ref = InterlockedIncrement(&This->ref);
872 TRACE("(%p) refcount=%u\n", iface, ref);
874 return ref;
877 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
879 FormatConverter *This = impl_from_IWICFormatConverter(iface);
880 ULONG ref = InterlockedDecrement(&This->ref);
882 TRACE("(%p) refcount=%u\n", iface, ref);
884 if (ref == 0)
886 This->lock.DebugInfo->Spare[0] = 0;
887 DeleteCriticalSection(&This->lock);
888 if (This->source) IWICBitmapSource_Release(This->source);
889 HeapFree(GetProcessHeap(), 0, This);
892 return ref;
895 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
896 UINT *puiWidth, UINT *puiHeight)
898 FormatConverter *This = impl_from_IWICFormatConverter(iface);
900 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
902 if (This->source)
903 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
904 else
905 return WINCODEC_ERR_NOTINITIALIZED;
908 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
909 WICPixelFormatGUID *pPixelFormat)
911 FormatConverter *This = impl_from_IWICFormatConverter(iface);
913 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
915 if (This->source)
916 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
917 else
918 return WINCODEC_ERR_NOTINITIALIZED;
920 return S_OK;
923 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
924 double *pDpiX, double *pDpiY)
926 FormatConverter *This = impl_from_IWICFormatConverter(iface);
928 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
930 if (This->source)
931 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
932 else
933 return WINCODEC_ERR_NOTINITIALIZED;
936 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
937 IWICPalette *pIPalette)
939 FIXME("(%p,%p): stub\n", iface, pIPalette);
940 return E_NOTIMPL;
943 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
944 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
946 FormatConverter *This = impl_from_IWICFormatConverter(iface);
947 WICRect rc;
948 HRESULT hr;
949 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
951 if (This->source)
953 if (!prc)
955 UINT width, height;
956 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
957 if (FAILED(hr)) return hr;
958 rc.X = 0;
959 rc.Y = 0;
960 rc.Width = width;
961 rc.Height = height;
962 prc = &rc;
965 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
966 pbBuffer, This->src_format->format);
968 else
969 return WINCODEC_ERR_NOTINITIALIZED;
972 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
973 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
974 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
976 FormatConverter *This = impl_from_IWICFormatConverter(iface);
977 const struct pixelformatinfo *srcinfo, *dstinfo;
978 static INT fixme=0;
979 GUID srcFormat;
980 HRESULT res=S_OK;
982 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
983 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
985 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
987 EnterCriticalSection(&This->lock);
989 if (This->source)
991 res = WINCODEC_ERR_WRONGSTATE;
992 goto end;
995 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
996 if (FAILED(res)) goto end;
998 srcinfo = get_formatinfo(&srcFormat);
999 if (!srcinfo)
1001 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1002 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1003 goto end;
1006 dstinfo = get_formatinfo(dstFormat);
1007 if (!dstinfo)
1009 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1010 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1011 goto end;
1014 if (dstinfo->copy_function)
1016 IWICBitmapSource_AddRef(pISource);
1017 This->src_format = srcinfo;
1018 This->dst_format = dstinfo;
1019 This->dither = dither;
1020 This->alpha_threshold = alphaThresholdPercent;
1021 This->palette_type = paletteTranslate;
1022 This->source = pISource;
1024 else
1026 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1027 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1030 end:
1032 LeaveCriticalSection(&This->lock);
1034 return res;
1037 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1038 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1039 BOOL *pfCanConvert)
1041 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1042 const struct pixelformatinfo *srcinfo, *dstinfo;
1044 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1045 debugstr_guid(dstPixelFormat), pfCanConvert);
1047 srcinfo = get_formatinfo(srcPixelFormat);
1048 if (!srcinfo)
1050 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1051 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1054 dstinfo = get_formatinfo(dstPixelFormat);
1055 if (!dstinfo)
1057 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1058 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1061 if (dstinfo->copy_function &&
1062 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1063 *pfCanConvert = TRUE;
1064 else
1066 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1067 *pfCanConvert = FALSE;
1070 return S_OK;
1073 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1074 FormatConverter_QueryInterface,
1075 FormatConverter_AddRef,
1076 FormatConverter_Release,
1077 FormatConverter_GetSize,
1078 FormatConverter_GetPixelFormat,
1079 FormatConverter_GetResolution,
1080 FormatConverter_CopyPalette,
1081 FormatConverter_CopyPixels,
1082 FormatConverter_Initialize,
1083 FormatConverter_CanConvert
1086 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1088 FormatConverter *This;
1089 HRESULT ret;
1091 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1093 *ppv = NULL;
1095 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1097 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1098 if (!This) return E_OUTOFMEMORY;
1100 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1101 This->ref = 1;
1102 This->source = NULL;
1103 InitializeCriticalSection(&This->lock);
1104 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1106 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1107 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1109 return ret;