wined3d: Use the texture dimension helpers in surface_depth_blt().
[wine.git] / dlls / windowscodecs / converter.c
blobe701f2a80b50f8d28ce7d96bcb7baa0062b82da2
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"
29 #include "wincodecs_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
35 struct FormatConverter;
37 enum pixelformat {
38 format_1bppIndexed,
39 format_2bppIndexed,
40 format_4bppIndexed,
41 format_8bppIndexed,
42 format_BlackWhite,
43 format_2bppGray,
44 format_4bppGray,
45 format_8bppGray,
46 format_16bppGray,
47 format_16bppBGR555,
48 format_16bppBGR565,
49 format_16bppBGRA5551,
50 format_24bppBGR,
51 format_24bppRGB,
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 INT 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 INT 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 INT 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 INT 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 INT 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 INT 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 INT 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 INT 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 INT 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 INT 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_24bppRGB:
606 if (prc)
608 HRESULT res;
609 INT x, y;
610 BYTE *srcdata;
611 UINT srcstride, srcdatasize;
612 const BYTE *srcrow;
613 const BYTE *srcpixel;
614 BYTE *dstrow;
615 BYTE *dstpixel;
616 BYTE tmppixel[3];
618 srcstride = 3 * prc->Width;
619 srcdatasize = srcstride * prc->Height;
621 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
622 if (!srcdata) return E_OUTOFMEMORY;
624 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
626 if (SUCCEEDED(res))
628 srcrow = srcdata;
629 dstrow = pbBuffer;
630 for (y=0; y<prc->Height; y++) {
631 srcpixel=srcrow;
632 dstpixel=dstrow;
633 for (x=0; x<prc->Width; x++) {
634 tmppixel[0]=*srcpixel++; /* red */
635 tmppixel[1]=*srcpixel++; /* green */
636 tmppixel[2]=*srcpixel++; /* blue */
638 *dstpixel++=tmppixel[2]; /* blue */
639 *dstpixel++=tmppixel[1]; /* green */
640 *dstpixel++=tmppixel[0]; /* red */
641 *dstpixel++=255; /* alpha */
643 srcrow += srcstride;
644 dstrow += cbStride;
648 HeapFree(GetProcessHeap(), 0, srcdata);
650 return res;
652 return S_OK;
653 case format_32bppBGR:
654 if (prc)
656 HRESULT res;
657 INT x, y;
659 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
660 if (FAILED(res)) return res;
662 /* set all alpha values to 255 */
663 for (y=0; y<prc->Height; y++)
664 for (x=0; x<prc->Width; x++)
665 pbBuffer[cbStride*y+4*x+3] = 0xff;
667 return S_OK;
668 case format_32bppBGRA:
669 if (prc)
670 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
671 return S_OK;
672 case format_32bppPBGRA:
673 if (prc)
675 HRESULT res;
676 INT x, y;
678 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
679 if (FAILED(res)) return res;
681 for (y=0; y<prc->Height; y++)
682 for (x=0; x<prc->Width; x++)
684 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
685 if (alpha != 0 && alpha != 255)
687 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
688 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
689 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
693 return S_OK;
694 case format_48bppRGB:
695 if (prc)
697 HRESULT res;
698 INT x, y;
699 BYTE *srcdata;
700 UINT srcstride, srcdatasize;
701 const BYTE *srcrow;
702 const BYTE *srcpixel;
703 BYTE *dstrow;
704 DWORD *dstpixel;
706 srcstride = 6 * prc->Width;
707 srcdatasize = srcstride * prc->Height;
709 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
710 if (!srcdata) return E_OUTOFMEMORY;
712 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
714 if (SUCCEEDED(res))
716 srcrow = srcdata;
717 dstrow = pbBuffer;
718 for (y=0; y<prc->Height; y++) {
719 srcpixel=srcrow;
720 dstpixel=(DWORD*)dstrow;
721 for (x=0; x<prc->Width; x++) {
722 BYTE red, green, blue;
723 red = *srcpixel++; srcpixel++;
724 green = *srcpixel++; srcpixel++;
725 blue = *srcpixel++; srcpixel++;
726 *dstpixel++=0xff000000|red<<16|green<<8|blue;
728 srcrow += srcstride;
729 dstrow += cbStride;
733 HeapFree(GetProcessHeap(), 0, srcdata);
735 return res;
737 return S_OK;
738 case format_64bppRGBA:
739 if (prc)
741 HRESULT res;
742 INT x, y;
743 BYTE *srcdata;
744 UINT srcstride, srcdatasize;
745 const BYTE *srcrow;
746 const BYTE *srcpixel;
747 BYTE *dstrow;
748 DWORD *dstpixel;
750 srcstride = 8 * prc->Width;
751 srcdatasize = srcstride * prc->Height;
753 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
754 if (!srcdata) return E_OUTOFMEMORY;
756 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
758 if (SUCCEEDED(res))
760 srcrow = srcdata;
761 dstrow = pbBuffer;
762 for (y=0; y<prc->Height; y++) {
763 srcpixel=srcrow;
764 dstpixel=(DWORD*)dstrow;
765 for (x=0; x<prc->Width; x++) {
766 BYTE red, green, blue, alpha;
767 red = *srcpixel++; srcpixel++;
768 green = *srcpixel++; srcpixel++;
769 blue = *srcpixel++; srcpixel++;
770 alpha = *srcpixel++; srcpixel++;
771 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
773 srcrow += srcstride;
774 dstrow += cbStride;
778 HeapFree(GetProcessHeap(), 0, srcdata);
780 return res;
782 return S_OK;
783 case format_32bppCMYK:
784 if (prc)
786 HRESULT res;
787 UINT x, y;
789 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
790 if (FAILED(res)) return res;
792 for (y=0; y<prc->Height; y++)
793 for (x=0; x<prc->Width; x++)
795 BYTE *pixel = pbBuffer+cbStride*y+4*x;
796 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
797 pixel[0] = (255-y)*(255-k)/255; /* blue */
798 pixel[1] = (255-m)*(255-k)/255; /* green */
799 pixel[2] = (255-c)*(255-k)/255; /* red */
800 pixel[3] = 255; /* alpha */
803 return S_OK;
804 default:
805 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
809 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
810 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
812 switch (source_format)
814 case format_32bppBGR:
815 case format_32bppBGRA:
816 case format_32bppPBGRA:
817 if (prc)
818 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
819 return S_OK;
820 default:
821 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
825 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
826 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
828 HRESULT hr;
830 switch (source_format)
832 case format_32bppPBGRA:
833 if (prc)
834 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
835 return S_OK;
836 default:
837 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
838 if (SUCCEEDED(hr) && prc)
840 INT x, y;
842 for (y=0; y<prc->Height; y++)
843 for (x=0; x<prc->Width; x++)
845 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
846 if (alpha != 255)
848 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
849 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
850 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
854 return hr;
858 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
859 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
861 HRESULT hr;
863 switch (source_format)
865 case format_24bppBGR:
866 case format_24bppRGB:
867 if (prc)
869 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
870 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
871 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
872 return hr;
874 return S_OK;
875 case format_32bppBGR:
876 case format_32bppBGRA:
877 case format_32bppPBGRA:
878 if (prc)
880 HRESULT res;
881 INT x, y;
882 BYTE *srcdata;
883 UINT srcstride, srcdatasize;
884 const BYTE *srcrow;
885 const BYTE *srcpixel;
886 BYTE *dstrow;
887 BYTE *dstpixel;
889 srcstride = 4 * prc->Width;
890 srcdatasize = srcstride * prc->Height;
892 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
893 if (!srcdata) return E_OUTOFMEMORY;
895 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
897 if (SUCCEEDED(res))
899 srcrow = srcdata;
900 dstrow = pbBuffer;
901 for (y=0; y<prc->Height; y++) {
902 srcpixel=srcrow;
903 dstpixel=dstrow;
904 for (x=0; x<prc->Width; x++) {
905 *dstpixel++=*srcpixel++; /* blue */
906 *dstpixel++=*srcpixel++; /* green */
907 *dstpixel++=*srcpixel++; /* red */
908 srcpixel++; /* alpha */
910 srcrow += srcstride;
911 dstrow += cbStride;
915 HeapFree(GetProcessHeap(), 0, srcdata);
917 return res;
919 return S_OK;
920 default:
921 FIXME("Unimplemented conversion path!\n");
922 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
926 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
927 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
929 HRESULT hr;
931 switch (source_format)
933 case format_24bppBGR:
934 case format_24bppRGB:
935 if (prc)
937 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
938 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
939 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
940 return hr;
942 return S_OK;
943 case format_32bppBGR:
944 case format_32bppBGRA:
945 case format_32bppPBGRA:
946 if (prc)
948 HRESULT res;
949 INT x, y;
950 BYTE *srcdata;
951 UINT srcstride, srcdatasize;
952 const BYTE *srcrow;
953 const BYTE *srcpixel;
954 BYTE *dstrow;
955 BYTE *dstpixel;
957 srcstride = 4 * prc->Width;
958 srcdatasize = srcstride * prc->Height;
960 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
961 if (!srcdata) return E_OUTOFMEMORY;
963 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
965 if (SUCCEEDED(res))
967 srcrow = srcdata;
968 dstrow = pbBuffer;
969 for (y=0; y<prc->Height; y++) {
970 srcpixel=srcrow;
971 dstpixel=dstrow;
972 for (x=0; x<prc->Width; x++) {
973 *dstpixel++=*srcpixel++; /* blue */
974 *dstpixel++=*srcpixel++; /* green */
975 *dstpixel++=*srcpixel++; /* red */
976 srcpixel++; /* alpha */
978 srcrow += srcstride;
979 dstrow += cbStride;
982 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
985 HeapFree(GetProcessHeap(), 0, srcdata);
987 return res;
989 return S_OK;
990 default:
991 FIXME("Unimplemented conversion path!\n");
992 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
996 static const struct pixelformatinfo supported_formats[] = {
997 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
998 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
999 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1000 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
1001 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1002 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1003 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1004 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
1005 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1006 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1007 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1008 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1009 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1010 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1011 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1012 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1013 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1014 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1015 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1016 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1020 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1022 UINT i;
1024 for (i=0; supported_formats[i].guid; i++)
1025 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1027 return NULL;
1030 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1031 void **ppv)
1033 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1034 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1036 if (!ppv) return E_INVALIDARG;
1038 if (IsEqualIID(&IID_IUnknown, iid) ||
1039 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1040 IsEqualIID(&IID_IWICFormatConverter, iid))
1042 *ppv = &This->IWICFormatConverter_iface;
1044 else
1046 *ppv = NULL;
1047 return E_NOINTERFACE;
1050 IUnknown_AddRef((IUnknown*)*ppv);
1051 return S_OK;
1054 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1056 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1057 ULONG ref = InterlockedIncrement(&This->ref);
1059 TRACE("(%p) refcount=%u\n", iface, ref);
1061 return ref;
1064 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1066 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1067 ULONG ref = InterlockedDecrement(&This->ref);
1069 TRACE("(%p) refcount=%u\n", iface, ref);
1071 if (ref == 0)
1073 This->lock.DebugInfo->Spare[0] = 0;
1074 DeleteCriticalSection(&This->lock);
1075 if (This->source) IWICBitmapSource_Release(This->source);
1076 HeapFree(GetProcessHeap(), 0, This);
1079 return ref;
1082 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1083 UINT *puiWidth, UINT *puiHeight)
1085 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1087 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1089 if (This->source)
1090 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1091 else
1092 return WINCODEC_ERR_NOTINITIALIZED;
1095 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1096 WICPixelFormatGUID *pPixelFormat)
1098 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1100 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
1102 if (This->source)
1103 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1104 else
1105 return WINCODEC_ERR_NOTINITIALIZED;
1107 return S_OK;
1110 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1111 double *pDpiX, double *pDpiY)
1113 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1115 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
1117 if (This->source)
1118 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1119 else
1120 return WINCODEC_ERR_NOTINITIALIZED;
1123 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1124 IWICPalette *pIPalette)
1126 FIXME("(%p,%p): stub\n", iface, pIPalette);
1127 return E_NOTIMPL;
1130 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1131 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1133 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1134 WICRect rc;
1135 HRESULT hr;
1136 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1138 if (This->source)
1140 if (!prc)
1142 UINT width, height;
1143 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1144 if (FAILED(hr)) return hr;
1145 rc.X = 0;
1146 rc.Y = 0;
1147 rc.Width = width;
1148 rc.Height = height;
1149 prc = &rc;
1152 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1153 pbBuffer, This->src_format->format);
1155 else
1156 return WINCODEC_ERR_NOTINITIALIZED;
1159 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1160 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1161 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
1163 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1164 const struct pixelformatinfo *srcinfo, *dstinfo;
1165 static INT fixme=0;
1166 GUID srcFormat;
1167 HRESULT res=S_OK;
1169 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1170 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1172 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1174 EnterCriticalSection(&This->lock);
1176 if (This->source)
1178 res = WINCODEC_ERR_WRONGSTATE;
1179 goto end;
1182 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1183 if (FAILED(res)) goto end;
1185 srcinfo = get_formatinfo(&srcFormat);
1186 if (!srcinfo)
1188 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1189 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1190 goto end;
1193 dstinfo = get_formatinfo(dstFormat);
1194 if (!dstinfo)
1196 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1197 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1198 goto end;
1201 if (dstinfo->copy_function)
1203 IWICBitmapSource_AddRef(pISource);
1204 This->src_format = srcinfo;
1205 This->dst_format = dstinfo;
1206 This->dither = dither;
1207 This->alpha_threshold = alphaThresholdPercent;
1208 This->palette_type = paletteTranslate;
1209 This->source = pISource;
1211 else
1213 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1214 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1217 end:
1219 LeaveCriticalSection(&This->lock);
1221 return res;
1224 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1225 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1226 BOOL *pfCanConvert)
1228 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1229 const struct pixelformatinfo *srcinfo, *dstinfo;
1231 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1232 debugstr_guid(dstPixelFormat), pfCanConvert);
1234 srcinfo = get_formatinfo(srcPixelFormat);
1235 if (!srcinfo)
1237 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1238 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1241 dstinfo = get_formatinfo(dstPixelFormat);
1242 if (!dstinfo)
1244 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1245 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1248 if (dstinfo->copy_function &&
1249 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1250 *pfCanConvert = TRUE;
1251 else
1253 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1254 *pfCanConvert = FALSE;
1257 return S_OK;
1260 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1261 FormatConverter_QueryInterface,
1262 FormatConverter_AddRef,
1263 FormatConverter_Release,
1264 FormatConverter_GetSize,
1265 FormatConverter_GetPixelFormat,
1266 FormatConverter_GetResolution,
1267 FormatConverter_CopyPalette,
1268 FormatConverter_CopyPixels,
1269 FormatConverter_Initialize,
1270 FormatConverter_CanConvert
1273 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1275 FormatConverter *This;
1276 HRESULT ret;
1278 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1280 *ppv = NULL;
1282 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1283 if (!This) return E_OUTOFMEMORY;
1285 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1286 This->ref = 1;
1287 This->source = NULL;
1288 InitializeCriticalSection(&This->lock);
1289 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1291 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1292 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1294 return ret;