mmsystem.dll16: Fix the pointer arithmetic and memory leak issues when unmapping.
[wine.git] / dlls / windowscodecs / converter.c
bloba52c7d28daf35892d5823588d825e4e6843d1836
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 void make_grayscale_palette(WICColor *colors, UINT num_colors)
87 int i, v;
88 for (i=0; i<num_colors; i++)
90 v = i * 255 / (num_colors-1);
91 colors[i] = 0xff000000 | v<<16 | v<<8 | v;
95 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
96 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
98 switch (source_format)
100 case format_1bppIndexed:
101 case format_BlackWhite:
102 if (prc)
104 HRESULT res;
105 UINT x, y;
106 BYTE *srcdata;
107 UINT srcstride, srcdatasize;
108 const BYTE *srcrow;
109 const BYTE *srcbyte;
110 BYTE *dstrow;
111 DWORD *dstpixel;
112 WICColor colors[2];
113 IWICPalette *palette;
114 UINT actualcolors;
116 if (source_format == format_1bppIndexed)
118 res = PaletteImpl_Create(&palette);
119 if (FAILED(res)) return res;
121 res = IWICBitmapSource_CopyPalette(This->source, palette);
122 if (SUCCEEDED(res))
123 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
125 IWICPalette_Release(palette);
127 if (FAILED(res)) return res;
129 else
131 colors[0] = 0xff000000;
132 colors[1] = 0xffffffff;
135 srcstride = (prc->Width+7)/8;
136 srcdatasize = srcstride * prc->Height;
138 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
139 if (!srcdata) return E_OUTOFMEMORY;
141 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
143 if (SUCCEEDED(res))
145 srcrow = srcdata;
146 dstrow = pbBuffer;
147 for (y=0; y<prc->Height; y++) {
148 srcbyte=(const BYTE*)srcrow;
149 dstpixel=(DWORD*)dstrow;
150 for (x=0; x<prc->Width; x+=8) {
151 BYTE srcval;
152 srcval=*srcbyte++;
153 *dstpixel++ = colors[srcval>>7&1];
154 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
155 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
156 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
157 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
158 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
159 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
160 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
162 srcrow += srcstride;
163 dstrow += cbStride;
167 HeapFree(GetProcessHeap(), 0, srcdata);
169 return res;
171 return S_OK;
172 case format_2bppIndexed:
173 case format_2bppGray:
174 if (prc)
176 HRESULT res;
177 UINT x, y;
178 BYTE *srcdata;
179 UINT srcstride, srcdatasize;
180 const BYTE *srcrow;
181 const BYTE *srcbyte;
182 BYTE *dstrow;
183 DWORD *dstpixel;
184 WICColor colors[4];
185 IWICPalette *palette;
186 UINT actualcolors;
188 if (source_format == format_2bppIndexed)
190 res = PaletteImpl_Create(&palette);
191 if (FAILED(res)) return res;
193 res = IWICBitmapSource_CopyPalette(This->source, palette);
194 if (SUCCEEDED(res))
195 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
197 IWICPalette_Release(palette);
199 if (FAILED(res)) return res;
201 else
202 make_grayscale_palette(colors, 4);
204 srcstride = (prc->Width+3)/4;
205 srcdatasize = srcstride * prc->Height;
207 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
208 if (!srcdata) return E_OUTOFMEMORY;
210 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
212 if (SUCCEEDED(res))
214 srcrow = srcdata;
215 dstrow = pbBuffer;
216 for (y=0; y<prc->Height; y++) {
217 srcbyte=(const BYTE*)srcrow;
218 dstpixel=(DWORD*)dstrow;
219 for (x=0; x<prc->Width; x+=4) {
220 BYTE srcval;
221 srcval=*srcbyte++;
222 *dstpixel++ = colors[srcval>>6];
223 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
224 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
225 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
227 srcrow += srcstride;
228 dstrow += cbStride;
232 HeapFree(GetProcessHeap(), 0, srcdata);
234 return res;
236 return S_OK;
237 case format_4bppIndexed:
238 case format_4bppGray:
239 if (prc)
241 HRESULT res;
242 UINT x, y;
243 BYTE *srcdata;
244 UINT srcstride, srcdatasize;
245 const BYTE *srcrow;
246 const BYTE *srcbyte;
247 BYTE *dstrow;
248 DWORD *dstpixel;
249 WICColor colors[16];
250 IWICPalette *palette;
251 UINT actualcolors;
253 if (source_format == format_4bppIndexed)
255 res = PaletteImpl_Create(&palette);
256 if (FAILED(res)) return res;
258 res = IWICBitmapSource_CopyPalette(This->source, palette);
259 if (SUCCEEDED(res))
260 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
262 IWICPalette_Release(palette);
264 if (FAILED(res)) return res;
266 else
267 make_grayscale_palette(colors, 16);
269 srcstride = (prc->Width+1)/2;
270 srcdatasize = srcstride * prc->Height;
272 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
273 if (!srcdata) return E_OUTOFMEMORY;
275 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
277 if (SUCCEEDED(res))
279 srcrow = srcdata;
280 dstrow = pbBuffer;
281 for (y=0; y<prc->Height; y++) {
282 srcbyte=(const BYTE*)srcrow;
283 dstpixel=(DWORD*)dstrow;
284 for (x=0; x<prc->Width; x+=2) {
285 BYTE srcval;
286 srcval=*srcbyte++;
287 *dstpixel++ = colors[srcval>>4];
288 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
290 srcrow += srcstride;
291 dstrow += cbStride;
295 HeapFree(GetProcessHeap(), 0, srcdata);
297 return res;
299 return S_OK;
300 case format_8bppGray:
301 if (prc)
303 HRESULT res;
304 UINT x, y;
305 BYTE *srcdata;
306 UINT srcstride, srcdatasize;
307 const BYTE *srcrow;
308 const BYTE *srcbyte;
309 BYTE *dstrow;
310 DWORD *dstpixel;
312 srcstride = prc->Width;
313 srcdatasize = srcstride * prc->Height;
315 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
316 if (!srcdata) return E_OUTOFMEMORY;
318 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
320 if (SUCCEEDED(res))
322 srcrow = srcdata;
323 dstrow = pbBuffer;
324 for (y=0; y<prc->Height; y++) {
325 srcbyte=(const BYTE*)srcrow;
326 dstpixel=(DWORD*)dstrow;
327 for (x=0; x<prc->Width; x++)
329 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
330 srcbyte++;
332 srcrow += srcstride;
333 dstrow += cbStride;
337 HeapFree(GetProcessHeap(), 0, srcdata);
339 return res;
341 return S_OK;
342 case format_8bppIndexed:
343 if (prc)
345 HRESULT res;
346 UINT x, y;
347 BYTE *srcdata;
348 UINT srcstride, srcdatasize;
349 const BYTE *srcrow;
350 const BYTE *srcbyte;
351 BYTE *dstrow;
352 DWORD *dstpixel;
353 WICColor colors[256];
354 IWICPalette *palette;
355 UINT actualcolors;
357 res = PaletteImpl_Create(&palette);
358 if (FAILED(res)) return res;
360 res = IWICBitmapSource_CopyPalette(This->source, palette);
361 if (SUCCEEDED(res))
362 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
364 IWICPalette_Release(palette);
366 if (FAILED(res)) return res;
368 srcstride = prc->Width;
369 srcdatasize = srcstride * prc->Height;
371 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
372 if (!srcdata) return E_OUTOFMEMORY;
374 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
376 if (SUCCEEDED(res))
378 srcrow = srcdata;
379 dstrow = pbBuffer;
380 for (y=0; y<prc->Height; y++) {
381 srcbyte=(const BYTE*)srcrow;
382 dstpixel=(DWORD*)dstrow;
383 for (x=0; x<prc->Width; x++)
384 *dstpixel++ = colors[*srcbyte++];
385 srcrow += srcstride;
386 dstrow += cbStride;
390 HeapFree(GetProcessHeap(), 0, srcdata);
392 return res;
394 return S_OK;
395 case format_16bppGray:
396 if (prc)
398 HRESULT res;
399 UINT x, y;
400 BYTE *srcdata;
401 UINT srcstride, srcdatasize;
402 const BYTE *srcrow;
403 const BYTE *srcbyte;
404 BYTE *dstrow;
405 DWORD *dstpixel;
407 srcstride = prc->Width * 2;
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);
415 if (SUCCEEDED(res))
417 srcrow = srcdata;
418 dstrow = pbBuffer;
419 for (y=0; y<prc->Height; y++) {
420 srcbyte=(const BYTE*)srcrow;
421 dstpixel=(DWORD*)dstrow;
422 for (x=0; x<prc->Width; x++)
424 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
425 srcbyte+=2;
427 srcrow += srcstride;
428 dstrow += cbStride;
432 HeapFree(GetProcessHeap(), 0, srcdata);
434 return res;
436 return S_OK;
437 case format_16bppBGR555:
438 if (prc)
440 HRESULT res;
441 UINT x, y;
442 BYTE *srcdata;
443 UINT srcstride, srcdatasize;
444 const BYTE *srcrow;
445 const WORD *srcpixel;
446 BYTE *dstrow;
447 DWORD *dstpixel;
449 srcstride = 2 * prc->Width;
450 srcdatasize = srcstride * prc->Height;
452 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
453 if (!srcdata) return E_OUTOFMEMORY;
455 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
457 if (SUCCEEDED(res))
459 srcrow = srcdata;
460 dstrow = pbBuffer;
461 for (y=0; y<prc->Height; y++) {
462 srcpixel=(const WORD*)srcrow;
463 dstpixel=(DWORD*)dstrow;
464 for (x=0; x<prc->Width; x++) {
465 WORD srcval;
466 srcval=*srcpixel++;
467 *dstpixel++=0xff000000 | /* constant 255 alpha */
468 ((srcval << 9) & 0xf80000) | /* r */
469 ((srcval << 4) & 0x070000) | /* r - 3 bits */
470 ((srcval << 6) & 0x00f800) | /* g */
471 ((srcval << 1) & 0x000700) | /* g - 3 bits */
472 ((srcval << 3) & 0x0000f8) | /* b */
473 ((srcval >> 2) & 0x000007); /* b - 3 bits */
475 srcrow += srcstride;
476 dstrow += cbStride;
480 HeapFree(GetProcessHeap(), 0, srcdata);
482 return res;
484 return S_OK;
485 case format_16bppBGR565:
486 if (prc)
488 HRESULT res;
489 UINT x, y;
490 BYTE *srcdata;
491 UINT srcstride, srcdatasize;
492 const BYTE *srcrow;
493 const WORD *srcpixel;
494 BYTE *dstrow;
495 DWORD *dstpixel;
497 srcstride = 2 * prc->Width;
498 srcdatasize = srcstride * prc->Height;
500 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
501 if (!srcdata) return E_OUTOFMEMORY;
503 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
505 if (SUCCEEDED(res))
507 srcrow = srcdata;
508 dstrow = pbBuffer;
509 for (y=0; y<prc->Height; y++) {
510 srcpixel=(const WORD*)srcrow;
511 dstpixel=(DWORD*)dstrow;
512 for (x=0; x<prc->Width; x++) {
513 WORD srcval;
514 srcval=*srcpixel++;
515 *dstpixel++=0xff000000 | /* constant 255 alpha */
516 ((srcval << 8) & 0xf80000) | /* r */
517 ((srcval << 3) & 0x070000) | /* r - 3 bits */
518 ((srcval << 5) & 0x00fc00) | /* g */
519 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
520 ((srcval << 3) & 0x0000f8) | /* b */
521 ((srcval >> 2) & 0x000007); /* b - 3 bits */
523 srcrow += srcstride;
524 dstrow += cbStride;
528 HeapFree(GetProcessHeap(), 0, srcdata);
530 return res;
532 return S_OK;
533 case format_16bppBGRA5551:
534 if (prc)
536 HRESULT res;
537 UINT x, y;
538 BYTE *srcdata;
539 UINT srcstride, srcdatasize;
540 const BYTE *srcrow;
541 const WORD *srcpixel;
542 BYTE *dstrow;
543 DWORD *dstpixel;
545 srcstride = 2 * prc->Width;
546 srcdatasize = srcstride * prc->Height;
548 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
549 if (!srcdata) return E_OUTOFMEMORY;
551 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
553 if (SUCCEEDED(res))
555 srcrow = srcdata;
556 dstrow = pbBuffer;
557 for (y=0; y<prc->Height; y++) {
558 srcpixel=(const WORD*)srcrow;
559 dstpixel=(DWORD*)dstrow;
560 for (x=0; x<prc->Width; x++) {
561 WORD srcval;
562 srcval=*srcpixel++;
563 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
564 ((srcval << 9) & 0xf80000) | /* r */
565 ((srcval << 4) & 0x070000) | /* r - 3 bits */
566 ((srcval << 6) & 0x00f800) | /* g */
567 ((srcval << 1) & 0x000700) | /* g - 3 bits */
568 ((srcval << 3) & 0x0000f8) | /* b */
569 ((srcval >> 2) & 0x000007); /* b - 3 bits */
571 srcrow += srcstride;
572 dstrow += cbStride;
576 HeapFree(GetProcessHeap(), 0, srcdata);
578 return res;
580 return S_OK;
581 case format_24bppBGR:
582 if (prc)
584 HRESULT res;
585 UINT x, y;
586 BYTE *srcdata;
587 UINT srcstride, srcdatasize;
588 const BYTE *srcrow;
589 const BYTE *srcpixel;
590 BYTE *dstrow;
591 BYTE *dstpixel;
593 srcstride = 3 * prc->Width;
594 srcdatasize = srcstride * prc->Height;
596 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
597 if (!srcdata) return E_OUTOFMEMORY;
599 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
601 if (SUCCEEDED(res))
603 srcrow = srcdata;
604 dstrow = pbBuffer;
605 for (y=0; y<prc->Height; y++) {
606 srcpixel=srcrow;
607 dstpixel=dstrow;
608 for (x=0; x<prc->Width; x++) {
609 *dstpixel++=*srcpixel++; /* blue */
610 *dstpixel++=*srcpixel++; /* green */
611 *dstpixel++=*srcpixel++; /* red */
612 *dstpixel++=255; /* alpha */
614 srcrow += srcstride;
615 dstrow += cbStride;
619 HeapFree(GetProcessHeap(), 0, srcdata);
621 return res;
623 return S_OK;
624 case format_32bppBGR:
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 /* set all alpha values to 255 */
634 for (y=0; y<prc->Height; y++)
635 for (x=0; x<prc->Width; x++)
636 pbBuffer[cbStride*y+4*x+3] = 0xff;
638 return S_OK;
639 case format_32bppBGRA:
640 if (prc)
641 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
642 return S_OK;
643 case format_32bppPBGRA:
644 if (prc)
646 HRESULT res;
647 UINT x, y;
649 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
650 if (FAILED(res)) return res;
652 for (y=0; y<prc->Height; y++)
653 for (x=0; x<prc->Width; x++)
655 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
656 if (alpha != 0 && alpha != 255)
658 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
659 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
660 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
664 return S_OK;
665 case format_48bppRGB:
666 if (prc)
668 HRESULT res;
669 UINT x, y;
670 BYTE *srcdata;
671 UINT srcstride, srcdatasize;
672 const BYTE *srcrow;
673 const BYTE *srcpixel;
674 BYTE *dstrow;
675 DWORD *dstpixel;
677 srcstride = 6 * prc->Width;
678 srcdatasize = srcstride * prc->Height;
680 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
681 if (!srcdata) return E_OUTOFMEMORY;
683 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
685 if (SUCCEEDED(res))
687 srcrow = srcdata;
688 dstrow = pbBuffer;
689 for (y=0; y<prc->Height; y++) {
690 srcpixel=srcrow;
691 dstpixel=(DWORD*)dstrow;
692 for (x=0; x<prc->Width; x++) {
693 BYTE red, green, blue;
694 red = *srcpixel++; srcpixel++;
695 green = *srcpixel++; srcpixel++;
696 blue = *srcpixel++; srcpixel++;
697 *dstpixel++=0xff000000|red<<16|green<<8|blue;
699 srcrow += srcstride;
700 dstrow += cbStride;
704 HeapFree(GetProcessHeap(), 0, srcdata);
706 return res;
708 return S_OK;
709 case format_64bppRGBA:
710 if (prc)
712 HRESULT res;
713 UINT x, y;
714 BYTE *srcdata;
715 UINT srcstride, srcdatasize;
716 const BYTE *srcrow;
717 const BYTE *srcpixel;
718 BYTE *dstrow;
719 DWORD *dstpixel;
721 srcstride = 8 * prc->Width;
722 srcdatasize = srcstride * prc->Height;
724 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
725 if (!srcdata) return E_OUTOFMEMORY;
727 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
729 if (SUCCEEDED(res))
731 srcrow = srcdata;
732 dstrow = pbBuffer;
733 for (y=0; y<prc->Height; y++) {
734 srcpixel=srcrow;
735 dstpixel=(DWORD*)dstrow;
736 for (x=0; x<prc->Width; x++) {
737 BYTE red, green, blue, alpha;
738 red = *srcpixel++; srcpixel++;
739 green = *srcpixel++; srcpixel++;
740 blue = *srcpixel++; srcpixel++;
741 alpha = *srcpixel++; srcpixel++;
742 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
744 srcrow += srcstride;
745 dstrow += cbStride;
749 HeapFree(GetProcessHeap(), 0, srcdata);
751 return res;
753 return S_OK;
754 case format_32bppCMYK:
755 if (prc)
757 HRESULT res;
758 UINT x, y;
760 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
761 if (FAILED(res)) return res;
763 for (y=0; y<prc->Height; y++)
764 for (x=0; x<prc->Width; x++)
766 BYTE *pixel = pbBuffer+cbStride*y+4*x;
767 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
768 pixel[0] = (255-y)*(255-k)/255; /* blue */
769 pixel[1] = (255-m)*(255-k)/255; /* green */
770 pixel[2] = (255-c)*(255-k)/255; /* red */
771 pixel[3] = 255; /* alpha */
774 return S_OK;
775 default:
776 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
780 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
781 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
783 switch (source_format)
785 case format_32bppBGR:
786 case format_32bppBGRA:
787 case format_32bppPBGRA:
788 if (prc)
789 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
790 return S_OK;
791 default:
792 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
796 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
797 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
799 HRESULT hr;
801 switch (source_format)
803 case format_32bppPBGRA:
804 if (prc)
805 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
806 return S_OK;
807 default:
808 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
809 if (SUCCEEDED(hr) && prc)
811 UINT x, y;
813 for (y=0; y<prc->Height; y++)
814 for (x=0; x<prc->Width; x++)
816 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
817 if (alpha != 255)
819 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
820 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
821 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
825 return hr;
829 static const struct pixelformatinfo supported_formats[] = {
830 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
831 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
832 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
833 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
834 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
835 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
836 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
837 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
838 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
839 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
840 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
841 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
842 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
843 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
844 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
845 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
846 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
847 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
848 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
852 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
854 UINT i;
856 for (i=0; supported_formats[i].guid; i++)
857 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
859 return NULL;
862 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
863 void **ppv)
865 FormatConverter *This = impl_from_IWICFormatConverter(iface);
866 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
868 if (!ppv) return E_INVALIDARG;
870 if (IsEqualIID(&IID_IUnknown, iid) ||
871 IsEqualIID(&IID_IWICBitmapSource, iid) ||
872 IsEqualIID(&IID_IWICFormatConverter, iid))
874 *ppv = This;
876 else
878 *ppv = NULL;
879 return E_NOINTERFACE;
882 IUnknown_AddRef((IUnknown*)*ppv);
883 return S_OK;
886 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
888 FormatConverter *This = impl_from_IWICFormatConverter(iface);
889 ULONG ref = InterlockedIncrement(&This->ref);
891 TRACE("(%p) refcount=%u\n", iface, ref);
893 return ref;
896 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
898 FormatConverter *This = impl_from_IWICFormatConverter(iface);
899 ULONG ref = InterlockedDecrement(&This->ref);
901 TRACE("(%p) refcount=%u\n", iface, ref);
903 if (ref == 0)
905 This->lock.DebugInfo->Spare[0] = 0;
906 DeleteCriticalSection(&This->lock);
907 if (This->source) IWICBitmapSource_Release(This->source);
908 HeapFree(GetProcessHeap(), 0, This);
911 return ref;
914 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
915 UINT *puiWidth, UINT *puiHeight)
917 FormatConverter *This = impl_from_IWICFormatConverter(iface);
919 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
921 if (This->source)
922 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
923 else
924 return WINCODEC_ERR_NOTINITIALIZED;
927 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
928 WICPixelFormatGUID *pPixelFormat)
930 FormatConverter *This = impl_from_IWICFormatConverter(iface);
932 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
934 if (This->source)
935 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
936 else
937 return WINCODEC_ERR_NOTINITIALIZED;
939 return S_OK;
942 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
943 double *pDpiX, double *pDpiY)
945 FormatConverter *This = impl_from_IWICFormatConverter(iface);
947 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
949 if (This->source)
950 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
951 else
952 return WINCODEC_ERR_NOTINITIALIZED;
955 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
956 IWICPalette *pIPalette)
958 FIXME("(%p,%p): stub\n", iface, pIPalette);
959 return E_NOTIMPL;
962 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
963 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
965 FormatConverter *This = impl_from_IWICFormatConverter(iface);
966 WICRect rc;
967 HRESULT hr;
968 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
970 if (This->source)
972 if (!prc)
974 UINT width, height;
975 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
976 if (FAILED(hr)) return hr;
977 rc.X = 0;
978 rc.Y = 0;
979 rc.Width = width;
980 rc.Height = height;
981 prc = &rc;
984 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
985 pbBuffer, This->src_format->format);
987 else
988 return WINCODEC_ERR_NOTINITIALIZED;
991 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
992 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
993 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
995 FormatConverter *This = impl_from_IWICFormatConverter(iface);
996 const struct pixelformatinfo *srcinfo, *dstinfo;
997 static INT fixme=0;
998 GUID srcFormat;
999 HRESULT res=S_OK;
1001 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1002 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1004 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1006 EnterCriticalSection(&This->lock);
1008 if (This->source)
1010 res = WINCODEC_ERR_WRONGSTATE;
1011 goto end;
1014 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1015 if (FAILED(res)) goto end;
1017 srcinfo = get_formatinfo(&srcFormat);
1018 if (!srcinfo)
1020 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1021 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1022 goto end;
1025 dstinfo = get_formatinfo(dstFormat);
1026 if (!dstinfo)
1028 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1029 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1030 goto end;
1033 if (dstinfo->copy_function)
1035 IWICBitmapSource_AddRef(pISource);
1036 This->src_format = srcinfo;
1037 This->dst_format = dstinfo;
1038 This->dither = dither;
1039 This->alpha_threshold = alphaThresholdPercent;
1040 This->palette_type = paletteTranslate;
1041 This->source = pISource;
1043 else
1045 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1046 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1049 end:
1051 LeaveCriticalSection(&This->lock);
1053 return res;
1056 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1057 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1058 BOOL *pfCanConvert)
1060 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1061 const struct pixelformatinfo *srcinfo, *dstinfo;
1063 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1064 debugstr_guid(dstPixelFormat), pfCanConvert);
1066 srcinfo = get_formatinfo(srcPixelFormat);
1067 if (!srcinfo)
1069 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1070 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1073 dstinfo = get_formatinfo(dstPixelFormat);
1074 if (!dstinfo)
1076 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1077 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1080 if (dstinfo->copy_function &&
1081 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1082 *pfCanConvert = TRUE;
1083 else
1085 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1086 *pfCanConvert = FALSE;
1089 return S_OK;
1092 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1093 FormatConverter_QueryInterface,
1094 FormatConverter_AddRef,
1095 FormatConverter_Release,
1096 FormatConverter_GetSize,
1097 FormatConverter_GetPixelFormat,
1098 FormatConverter_GetResolution,
1099 FormatConverter_CopyPalette,
1100 FormatConverter_CopyPixels,
1101 FormatConverter_Initialize,
1102 FormatConverter_CanConvert
1105 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1107 FormatConverter *This;
1108 HRESULT ret;
1110 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1112 *ppv = NULL;
1114 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1116 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1117 if (!This) return E_OUTOFMEMORY;
1119 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1120 This->ref = 1;
1121 This->source = NULL;
1122 InitializeCriticalSection(&This->lock);
1123 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1125 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
1126 IUnknown_Release((IUnknown*)This);
1128 return ret;