taskschd: Add initial version of the task definition XML writer.
[wine.git] / dlls / windowscodecs / converter.c
blob11f04d9794f0a41507bd47f5e3244848ac85e86e
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_24bppRGB,
53 format_32bppBGR,
54 format_32bppBGRA,
55 format_32bppPBGRA,
56 format_48bppRGB,
57 format_64bppRGBA,
58 format_32bppCMYK,
61 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
62 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
64 struct pixelformatinfo {
65 enum pixelformat format;
66 const WICPixelFormatGUID *guid;
67 copyfunc copy_function;
70 typedef struct FormatConverter {
71 IWICFormatConverter IWICFormatConverter_iface;
72 LONG ref;
73 IWICBitmapSource *source;
74 const struct pixelformatinfo *dst_format, *src_format;
75 WICBitmapDitherType dither;
76 double alpha_threshold;
77 WICBitmapPaletteType palette_type;
78 CRITICAL_SECTION lock; /* must be held when initialized */
79 } FormatConverter;
81 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
83 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
86 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
87 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
89 switch (source_format)
91 case format_1bppIndexed:
92 case format_BlackWhite:
93 if (prc)
95 HRESULT res;
96 INT x, y;
97 BYTE *srcdata;
98 UINT srcstride, srcdatasize;
99 const BYTE *srcrow;
100 const BYTE *srcbyte;
101 BYTE *dstrow;
102 DWORD *dstpixel;
103 WICColor colors[2];
104 IWICPalette *palette;
105 UINT actualcolors;
107 res = PaletteImpl_Create(&palette);
108 if (FAILED(res)) return res;
110 if (source_format == format_1bppIndexed)
111 res = IWICBitmapSource_CopyPalette(This->source, palette);
112 else
113 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
115 if (SUCCEEDED(res))
116 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
118 IWICPalette_Release(palette);
119 if (FAILED(res)) return res;
121 srcstride = (prc->Width+7)/8;
122 srcdatasize = srcstride * prc->Height;
124 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
125 if (!srcdata) return E_OUTOFMEMORY;
127 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
129 if (SUCCEEDED(res))
131 srcrow = srcdata;
132 dstrow = pbBuffer;
133 for (y=0; y<prc->Height; y++) {
134 srcbyte = srcrow;
135 dstpixel=(DWORD*)dstrow;
136 for (x=0; x<prc->Width; x+=8) {
137 BYTE srcval;
138 srcval=*srcbyte++;
139 *dstpixel++ = colors[srcval>>7&1];
140 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
141 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
142 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
143 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
144 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
145 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
146 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
148 srcrow += srcstride;
149 dstrow += cbStride;
153 HeapFree(GetProcessHeap(), 0, srcdata);
155 return res;
157 return S_OK;
158 case format_2bppIndexed:
159 case format_2bppGray:
160 if (prc)
162 HRESULT res;
163 INT x, y;
164 BYTE *srcdata;
165 UINT srcstride, srcdatasize;
166 const BYTE *srcrow;
167 const BYTE *srcbyte;
168 BYTE *dstrow;
169 DWORD *dstpixel;
170 WICColor colors[4];
171 IWICPalette *palette;
172 UINT actualcolors;
174 res = PaletteImpl_Create(&palette);
175 if (FAILED(res)) return res;
177 if (source_format == format_2bppIndexed)
178 res = IWICBitmapSource_CopyPalette(This->source, palette);
179 else
180 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
182 if (SUCCEEDED(res))
183 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
185 IWICPalette_Release(palette);
186 if (FAILED(res)) return res;
188 srcstride = (prc->Width+3)/4;
189 srcdatasize = srcstride * prc->Height;
191 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
192 if (!srcdata) return E_OUTOFMEMORY;
194 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
196 if (SUCCEEDED(res))
198 srcrow = srcdata;
199 dstrow = pbBuffer;
200 for (y=0; y<prc->Height; y++) {
201 srcbyte = srcrow;
202 dstpixel=(DWORD*)dstrow;
203 for (x=0; x<prc->Width; x+=4) {
204 BYTE srcval;
205 srcval=*srcbyte++;
206 *dstpixel++ = colors[srcval>>6];
207 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
208 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
209 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
211 srcrow += srcstride;
212 dstrow += cbStride;
216 HeapFree(GetProcessHeap(), 0, srcdata);
218 return res;
220 return S_OK;
221 case format_4bppIndexed:
222 case format_4bppGray:
223 if (prc)
225 HRESULT res;
226 INT x, y;
227 BYTE *srcdata;
228 UINT srcstride, srcdatasize;
229 const BYTE *srcrow;
230 const BYTE *srcbyte;
231 BYTE *dstrow;
232 DWORD *dstpixel;
233 WICColor colors[16];
234 IWICPalette *palette;
235 UINT actualcolors;
237 res = PaletteImpl_Create(&palette);
238 if (FAILED(res)) return res;
240 if (source_format == format_4bppIndexed)
241 res = IWICBitmapSource_CopyPalette(This->source, palette);
242 else
243 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
245 if (SUCCEEDED(res))
246 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
248 IWICPalette_Release(palette);
249 if (FAILED(res)) return res;
251 srcstride = (prc->Width+1)/2;
252 srcdatasize = srcstride * prc->Height;
254 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
255 if (!srcdata) return E_OUTOFMEMORY;
257 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
259 if (SUCCEEDED(res))
261 srcrow = srcdata;
262 dstrow = pbBuffer;
263 for (y=0; y<prc->Height; y++) {
264 srcbyte = srcrow;
265 dstpixel=(DWORD*)dstrow;
266 for (x=0; x<prc->Width; x+=2) {
267 BYTE srcval;
268 srcval=*srcbyte++;
269 *dstpixel++ = colors[srcval>>4];
270 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
272 srcrow += srcstride;
273 dstrow += cbStride;
277 HeapFree(GetProcessHeap(), 0, srcdata);
279 return res;
281 return S_OK;
282 case format_8bppGray:
283 if (prc)
285 HRESULT res;
286 INT x, y;
287 BYTE *srcdata;
288 UINT srcstride, srcdatasize;
289 const BYTE *srcrow;
290 const BYTE *srcbyte;
291 BYTE *dstrow;
292 DWORD *dstpixel;
294 srcstride = prc->Width;
295 srcdatasize = srcstride * prc->Height;
297 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
298 if (!srcdata) return E_OUTOFMEMORY;
300 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
302 if (SUCCEEDED(res))
304 srcrow = srcdata;
305 dstrow = pbBuffer;
306 for (y=0; y<prc->Height; y++) {
307 srcbyte = srcrow;
308 dstpixel=(DWORD*)dstrow;
309 for (x=0; x<prc->Width; x++)
311 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
312 srcbyte++;
314 srcrow += srcstride;
315 dstrow += cbStride;
319 HeapFree(GetProcessHeap(), 0, srcdata);
321 return res;
323 return S_OK;
324 case format_8bppIndexed:
325 if (prc)
327 HRESULT res;
328 INT x, y;
329 BYTE *srcdata;
330 UINT srcstride, srcdatasize;
331 const BYTE *srcrow;
332 const BYTE *srcbyte;
333 BYTE *dstrow;
334 DWORD *dstpixel;
335 WICColor colors[256];
336 IWICPalette *palette;
337 UINT actualcolors;
339 res = PaletteImpl_Create(&palette);
340 if (FAILED(res)) return res;
342 res = IWICBitmapSource_CopyPalette(This->source, palette);
343 if (SUCCEEDED(res))
344 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
346 IWICPalette_Release(palette);
348 if (FAILED(res)) return res;
350 srcstride = prc->Width;
351 srcdatasize = srcstride * prc->Height;
353 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
354 if (!srcdata) return E_OUTOFMEMORY;
356 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
358 if (SUCCEEDED(res))
360 srcrow = srcdata;
361 dstrow = pbBuffer;
362 for (y=0; y<prc->Height; y++) {
363 srcbyte = srcrow;
364 dstpixel=(DWORD*)dstrow;
365 for (x=0; x<prc->Width; x++)
366 *dstpixel++ = colors[*srcbyte++];
367 srcrow += srcstride;
368 dstrow += cbStride;
372 HeapFree(GetProcessHeap(), 0, srcdata);
374 return res;
376 return S_OK;
377 case format_16bppGray:
378 if (prc)
380 HRESULT res;
381 INT x, y;
382 BYTE *srcdata;
383 UINT srcstride, srcdatasize;
384 const BYTE *srcrow;
385 const BYTE *srcbyte;
386 BYTE *dstrow;
387 DWORD *dstpixel;
389 srcstride = prc->Width * 2;
390 srcdatasize = srcstride * prc->Height;
392 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
393 if (!srcdata) return E_OUTOFMEMORY;
395 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
397 if (SUCCEEDED(res))
399 srcrow = srcdata;
400 dstrow = pbBuffer;
401 for (y=0; y<prc->Height; y++) {
402 srcbyte = srcrow;
403 dstpixel=(DWORD*)dstrow;
404 for (x=0; x<prc->Width; x++)
406 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
407 srcbyte+=2;
409 srcrow += srcstride;
410 dstrow += cbStride;
414 HeapFree(GetProcessHeap(), 0, srcdata);
416 return res;
418 return S_OK;
419 case format_16bppBGR555:
420 if (prc)
422 HRESULT res;
423 INT x, y;
424 BYTE *srcdata;
425 UINT srcstride, srcdatasize;
426 const BYTE *srcrow;
427 const WORD *srcpixel;
428 BYTE *dstrow;
429 DWORD *dstpixel;
431 srcstride = 2 * prc->Width;
432 srcdatasize = srcstride * prc->Height;
434 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
435 if (!srcdata) return E_OUTOFMEMORY;
437 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
439 if (SUCCEEDED(res))
441 srcrow = srcdata;
442 dstrow = pbBuffer;
443 for (y=0; y<prc->Height; y++) {
444 srcpixel=(const WORD*)srcrow;
445 dstpixel=(DWORD*)dstrow;
446 for (x=0; x<prc->Width; x++) {
447 WORD srcval;
448 srcval=*srcpixel++;
449 *dstpixel++=0xff000000 | /* constant 255 alpha */
450 ((srcval << 9) & 0xf80000) | /* r */
451 ((srcval << 4) & 0x070000) | /* r - 3 bits */
452 ((srcval << 6) & 0x00f800) | /* g */
453 ((srcval << 1) & 0x000700) | /* g - 3 bits */
454 ((srcval << 3) & 0x0000f8) | /* b */
455 ((srcval >> 2) & 0x000007); /* b - 3 bits */
457 srcrow += srcstride;
458 dstrow += cbStride;
462 HeapFree(GetProcessHeap(), 0, srcdata);
464 return res;
466 return S_OK;
467 case format_16bppBGR565:
468 if (prc)
470 HRESULT res;
471 INT x, y;
472 BYTE *srcdata;
473 UINT srcstride, srcdatasize;
474 const BYTE *srcrow;
475 const WORD *srcpixel;
476 BYTE *dstrow;
477 DWORD *dstpixel;
479 srcstride = 2 * prc->Width;
480 srcdatasize = srcstride * prc->Height;
482 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
483 if (!srcdata) return E_OUTOFMEMORY;
485 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
487 if (SUCCEEDED(res))
489 srcrow = srcdata;
490 dstrow = pbBuffer;
491 for (y=0; y<prc->Height; y++) {
492 srcpixel=(const WORD*)srcrow;
493 dstpixel=(DWORD*)dstrow;
494 for (x=0; x<prc->Width; x++) {
495 WORD srcval;
496 srcval=*srcpixel++;
497 *dstpixel++=0xff000000 | /* constant 255 alpha */
498 ((srcval << 8) & 0xf80000) | /* r */
499 ((srcval << 3) & 0x070000) | /* r - 3 bits */
500 ((srcval << 5) & 0x00fc00) | /* g */
501 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
502 ((srcval << 3) & 0x0000f8) | /* b */
503 ((srcval >> 2) & 0x000007); /* b - 3 bits */
505 srcrow += srcstride;
506 dstrow += cbStride;
510 HeapFree(GetProcessHeap(), 0, srcdata);
512 return res;
514 return S_OK;
515 case format_16bppBGRA5551:
516 if (prc)
518 HRESULT res;
519 INT x, y;
520 BYTE *srcdata;
521 UINT srcstride, srcdatasize;
522 const BYTE *srcrow;
523 const WORD *srcpixel;
524 BYTE *dstrow;
525 DWORD *dstpixel;
527 srcstride = 2 * prc->Width;
528 srcdatasize = srcstride * prc->Height;
530 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
531 if (!srcdata) return E_OUTOFMEMORY;
533 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
535 if (SUCCEEDED(res))
537 srcrow = srcdata;
538 dstrow = pbBuffer;
539 for (y=0; y<prc->Height; y++) {
540 srcpixel=(const WORD*)srcrow;
541 dstpixel=(DWORD*)dstrow;
542 for (x=0; x<prc->Width; x++) {
543 WORD srcval;
544 srcval=*srcpixel++;
545 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
546 ((srcval << 9) & 0xf80000) | /* r */
547 ((srcval << 4) & 0x070000) | /* r - 3 bits */
548 ((srcval << 6) & 0x00f800) | /* g */
549 ((srcval << 1) & 0x000700) | /* g - 3 bits */
550 ((srcval << 3) & 0x0000f8) | /* b */
551 ((srcval >> 2) & 0x000007); /* b - 3 bits */
553 srcrow += srcstride;
554 dstrow += cbStride;
558 HeapFree(GetProcessHeap(), 0, srcdata);
560 return res;
562 return S_OK;
563 case format_24bppBGR:
564 if (prc)
566 HRESULT res;
567 INT x, y;
568 BYTE *srcdata;
569 UINT srcstride, srcdatasize;
570 const BYTE *srcrow;
571 const BYTE *srcpixel;
572 BYTE *dstrow;
573 BYTE *dstpixel;
575 srcstride = 3 * prc->Width;
576 srcdatasize = srcstride * prc->Height;
578 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
579 if (!srcdata) return E_OUTOFMEMORY;
581 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
583 if (SUCCEEDED(res))
585 srcrow = srcdata;
586 dstrow = pbBuffer;
587 for (y=0; y<prc->Height; y++) {
588 srcpixel=srcrow;
589 dstpixel=dstrow;
590 for (x=0; x<prc->Width; x++) {
591 *dstpixel++=*srcpixel++; /* blue */
592 *dstpixel++=*srcpixel++; /* green */
593 *dstpixel++=*srcpixel++; /* red */
594 *dstpixel++=255; /* alpha */
596 srcrow += srcstride;
597 dstrow += cbStride;
601 HeapFree(GetProcessHeap(), 0, srcdata);
603 return res;
605 return S_OK;
606 case format_24bppRGB:
607 if (prc)
609 HRESULT res;
610 INT x, y;
611 BYTE *srcdata;
612 UINT srcstride, srcdatasize;
613 const BYTE *srcrow;
614 const BYTE *srcpixel;
615 BYTE *dstrow;
616 BYTE *dstpixel;
617 BYTE tmppixel[3];
619 srcstride = 3 * prc->Width;
620 srcdatasize = srcstride * prc->Height;
622 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
623 if (!srcdata) return E_OUTOFMEMORY;
625 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
627 if (SUCCEEDED(res))
629 srcrow = srcdata;
630 dstrow = pbBuffer;
631 for (y=0; y<prc->Height; y++) {
632 srcpixel=srcrow;
633 dstpixel=dstrow;
634 for (x=0; x<prc->Width; x++) {
635 tmppixel[0]=*srcpixel++; /* red */
636 tmppixel[1]=*srcpixel++; /* green */
637 tmppixel[2]=*srcpixel++; /* blue */
639 *dstpixel++=tmppixel[2]; /* blue */
640 *dstpixel++=tmppixel[1]; /* green */
641 *dstpixel++=tmppixel[0]; /* red */
642 *dstpixel++=255; /* alpha */
644 srcrow += srcstride;
645 dstrow += cbStride;
649 HeapFree(GetProcessHeap(), 0, srcdata);
651 return res;
653 return S_OK;
654 case format_32bppBGR:
655 if (prc)
657 HRESULT res;
658 INT x, y;
660 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
661 if (FAILED(res)) return res;
663 /* set all alpha values to 255 */
664 for (y=0; y<prc->Height; y++)
665 for (x=0; x<prc->Width; x++)
666 pbBuffer[cbStride*y+4*x+3] = 0xff;
668 return S_OK;
669 case format_32bppBGRA:
670 if (prc)
671 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
672 return S_OK;
673 case format_32bppPBGRA:
674 if (prc)
676 HRESULT res;
677 INT x, y;
679 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
680 if (FAILED(res)) return res;
682 for (y=0; y<prc->Height; y++)
683 for (x=0; x<prc->Width; x++)
685 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
686 if (alpha != 0 && alpha != 255)
688 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
689 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
690 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
694 return S_OK;
695 case format_48bppRGB:
696 if (prc)
698 HRESULT res;
699 INT x, y;
700 BYTE *srcdata;
701 UINT srcstride, srcdatasize;
702 const BYTE *srcrow;
703 const BYTE *srcpixel;
704 BYTE *dstrow;
705 DWORD *dstpixel;
707 srcstride = 6 * prc->Width;
708 srcdatasize = srcstride * prc->Height;
710 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
711 if (!srcdata) return E_OUTOFMEMORY;
713 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
715 if (SUCCEEDED(res))
717 srcrow = srcdata;
718 dstrow = pbBuffer;
719 for (y=0; y<prc->Height; y++) {
720 srcpixel=srcrow;
721 dstpixel=(DWORD*)dstrow;
722 for (x=0; x<prc->Width; x++) {
723 BYTE red, green, blue;
724 red = *srcpixel++; srcpixel++;
725 green = *srcpixel++; srcpixel++;
726 blue = *srcpixel++; srcpixel++;
727 *dstpixel++=0xff000000|red<<16|green<<8|blue;
729 srcrow += srcstride;
730 dstrow += cbStride;
734 HeapFree(GetProcessHeap(), 0, srcdata);
736 return res;
738 return S_OK;
739 case format_64bppRGBA:
740 if (prc)
742 HRESULT res;
743 INT x, y;
744 BYTE *srcdata;
745 UINT srcstride, srcdatasize;
746 const BYTE *srcrow;
747 const BYTE *srcpixel;
748 BYTE *dstrow;
749 DWORD *dstpixel;
751 srcstride = 8 * prc->Width;
752 srcdatasize = srcstride * prc->Height;
754 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
755 if (!srcdata) return E_OUTOFMEMORY;
757 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
759 if (SUCCEEDED(res))
761 srcrow = srcdata;
762 dstrow = pbBuffer;
763 for (y=0; y<prc->Height; y++) {
764 srcpixel=srcrow;
765 dstpixel=(DWORD*)dstrow;
766 for (x=0; x<prc->Width; x++) {
767 BYTE red, green, blue, alpha;
768 red = *srcpixel++; srcpixel++;
769 green = *srcpixel++; srcpixel++;
770 blue = *srcpixel++; srcpixel++;
771 alpha = *srcpixel++; srcpixel++;
772 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
774 srcrow += srcstride;
775 dstrow += cbStride;
779 HeapFree(GetProcessHeap(), 0, srcdata);
781 return res;
783 return S_OK;
784 case format_32bppCMYK:
785 if (prc)
787 HRESULT res;
788 UINT x, y;
790 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
791 if (FAILED(res)) return res;
793 for (y=0; y<prc->Height; y++)
794 for (x=0; x<prc->Width; x++)
796 BYTE *pixel = pbBuffer+cbStride*y+4*x;
797 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
798 pixel[0] = (255-y)*(255-k)/255; /* blue */
799 pixel[1] = (255-m)*(255-k)/255; /* green */
800 pixel[2] = (255-c)*(255-k)/255; /* red */
801 pixel[3] = 255; /* alpha */
804 return S_OK;
805 default:
806 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
810 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
811 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
813 switch (source_format)
815 case format_32bppBGR:
816 case format_32bppBGRA:
817 case format_32bppPBGRA:
818 if (prc)
819 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
820 return S_OK;
821 default:
822 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
826 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
827 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
829 HRESULT hr;
831 switch (source_format)
833 case format_32bppPBGRA:
834 if (prc)
835 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
836 return S_OK;
837 default:
838 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
839 if (SUCCEEDED(hr) && prc)
841 INT x, y;
843 for (y=0; y<prc->Height; y++)
844 for (x=0; x<prc->Width; x++)
846 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
847 if (alpha != 255)
849 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
850 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
851 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
855 return hr;
859 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
860 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
862 HRESULT hr;
864 switch (source_format)
866 case format_24bppBGR:
867 case format_24bppRGB:
868 if (prc)
870 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
871 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
872 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
873 return hr;
875 return S_OK;
876 case format_32bppBGR:
877 case format_32bppBGRA:
878 case format_32bppPBGRA:
879 if (prc)
881 HRESULT res;
882 INT x, y;
883 BYTE *srcdata;
884 UINT srcstride, srcdatasize;
885 const BYTE *srcrow;
886 const BYTE *srcpixel;
887 BYTE *dstrow;
888 BYTE *dstpixel;
890 srcstride = 4 * prc->Width;
891 srcdatasize = srcstride * prc->Height;
893 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
894 if (!srcdata) return E_OUTOFMEMORY;
896 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
898 if (SUCCEEDED(res))
900 srcrow = srcdata;
901 dstrow = pbBuffer;
902 for (y=0; y<prc->Height; y++) {
903 srcpixel=srcrow;
904 dstpixel=dstrow;
905 for (x=0; x<prc->Width; x++) {
906 *dstpixel++=*srcpixel++; /* blue */
907 *dstpixel++=*srcpixel++; /* green */
908 *dstpixel++=*srcpixel++; /* red */
909 srcpixel++; /* alpha */
911 srcrow += srcstride;
912 dstrow += cbStride;
916 HeapFree(GetProcessHeap(), 0, srcdata);
918 return res;
920 return S_OK;
921 default:
922 FIXME("Unimplemented conversion path!\n");
923 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
927 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
928 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
930 HRESULT hr;
932 switch (source_format)
934 case format_24bppBGR:
935 case format_24bppRGB:
936 if (prc)
938 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
939 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
940 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
941 return hr;
943 return S_OK;
944 case format_32bppBGR:
945 case format_32bppBGRA:
946 case format_32bppPBGRA:
947 if (prc)
949 HRESULT res;
950 INT x, y;
951 BYTE *srcdata;
952 UINT srcstride, srcdatasize;
953 const BYTE *srcrow;
954 const BYTE *srcpixel;
955 BYTE *dstrow;
956 BYTE *dstpixel;
958 srcstride = 4 * prc->Width;
959 srcdatasize = srcstride * prc->Height;
961 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
962 if (!srcdata) return E_OUTOFMEMORY;
964 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
966 if (SUCCEEDED(res))
968 srcrow = srcdata;
969 dstrow = pbBuffer;
970 for (y=0; y<prc->Height; y++) {
971 srcpixel=srcrow;
972 dstpixel=dstrow;
973 for (x=0; x<prc->Width; x++) {
974 *dstpixel++=*srcpixel++; /* blue */
975 *dstpixel++=*srcpixel++; /* green */
976 *dstpixel++=*srcpixel++; /* red */
977 srcpixel++; /* alpha */
979 srcrow += srcstride;
980 dstrow += cbStride;
983 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
986 HeapFree(GetProcessHeap(), 0, srcdata);
988 return res;
990 return S_OK;
991 default:
992 FIXME("Unimplemented conversion path!\n");
993 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
997 static const struct pixelformatinfo supported_formats[] = {
998 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
999 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1000 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1001 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
1002 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1003 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1004 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1005 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
1006 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1007 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1008 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1009 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1010 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1011 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1012 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1013 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1014 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1015 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1016 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1017 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1021 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1023 UINT i;
1025 for (i=0; supported_formats[i].guid; i++)
1026 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1028 return NULL;
1031 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1032 void **ppv)
1034 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1035 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1037 if (!ppv) return E_INVALIDARG;
1039 if (IsEqualIID(&IID_IUnknown, iid) ||
1040 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1041 IsEqualIID(&IID_IWICFormatConverter, iid))
1043 *ppv = &This->IWICFormatConverter_iface;
1045 else
1047 *ppv = NULL;
1048 return E_NOINTERFACE;
1051 IUnknown_AddRef((IUnknown*)*ppv);
1052 return S_OK;
1055 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1057 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1058 ULONG ref = InterlockedIncrement(&This->ref);
1060 TRACE("(%p) refcount=%u\n", iface, ref);
1062 return ref;
1065 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1067 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1068 ULONG ref = InterlockedDecrement(&This->ref);
1070 TRACE("(%p) refcount=%u\n", iface, ref);
1072 if (ref == 0)
1074 This->lock.DebugInfo->Spare[0] = 0;
1075 DeleteCriticalSection(&This->lock);
1076 if (This->source) IWICBitmapSource_Release(This->source);
1077 HeapFree(GetProcessHeap(), 0, This);
1080 return ref;
1083 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1084 UINT *puiWidth, UINT *puiHeight)
1086 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1088 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1090 if (This->source)
1091 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1092 else
1093 return WINCODEC_ERR_NOTINITIALIZED;
1096 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1097 WICPixelFormatGUID *pPixelFormat)
1099 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1101 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
1103 if (This->source)
1104 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1105 else
1106 return WINCODEC_ERR_NOTINITIALIZED;
1108 return S_OK;
1111 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1112 double *pDpiX, double *pDpiY)
1114 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1116 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
1118 if (This->source)
1119 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1120 else
1121 return WINCODEC_ERR_NOTINITIALIZED;
1124 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1125 IWICPalette *pIPalette)
1127 FIXME("(%p,%p): stub\n", iface, pIPalette);
1128 return E_NOTIMPL;
1131 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1132 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1134 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1135 WICRect rc;
1136 HRESULT hr;
1137 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1139 if (This->source)
1141 if (!prc)
1143 UINT width, height;
1144 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1145 if (FAILED(hr)) return hr;
1146 rc.X = 0;
1147 rc.Y = 0;
1148 rc.Width = width;
1149 rc.Height = height;
1150 prc = &rc;
1153 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1154 pbBuffer, This->src_format->format);
1156 else
1157 return WINCODEC_ERR_NOTINITIALIZED;
1160 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1161 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1162 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
1164 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1165 const struct pixelformatinfo *srcinfo, *dstinfo;
1166 static INT fixme=0;
1167 GUID srcFormat;
1168 HRESULT res=S_OK;
1170 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1171 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1173 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1175 EnterCriticalSection(&This->lock);
1177 if (This->source)
1179 res = WINCODEC_ERR_WRONGSTATE;
1180 goto end;
1183 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1184 if (FAILED(res)) goto end;
1186 srcinfo = get_formatinfo(&srcFormat);
1187 if (!srcinfo)
1189 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1190 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1191 goto end;
1194 dstinfo = get_formatinfo(dstFormat);
1195 if (!dstinfo)
1197 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1198 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1199 goto end;
1202 if (dstinfo->copy_function)
1204 IWICBitmapSource_AddRef(pISource);
1205 This->src_format = srcinfo;
1206 This->dst_format = dstinfo;
1207 This->dither = dither;
1208 This->alpha_threshold = alphaThresholdPercent;
1209 This->palette_type = paletteTranslate;
1210 This->source = pISource;
1212 else
1214 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1215 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1218 end:
1220 LeaveCriticalSection(&This->lock);
1222 return res;
1225 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1226 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1227 BOOL *pfCanConvert)
1229 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1230 const struct pixelformatinfo *srcinfo, *dstinfo;
1232 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1233 debugstr_guid(dstPixelFormat), pfCanConvert);
1235 srcinfo = get_formatinfo(srcPixelFormat);
1236 if (!srcinfo)
1238 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1239 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1242 dstinfo = get_formatinfo(dstPixelFormat);
1243 if (!dstinfo)
1245 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1246 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1249 if (dstinfo->copy_function &&
1250 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1251 *pfCanConvert = TRUE;
1252 else
1254 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1255 *pfCanConvert = FALSE;
1258 return S_OK;
1261 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1262 FormatConverter_QueryInterface,
1263 FormatConverter_AddRef,
1264 FormatConverter_Release,
1265 FormatConverter_GetSize,
1266 FormatConverter_GetPixelFormat,
1267 FormatConverter_GetResolution,
1268 FormatConverter_CopyPalette,
1269 FormatConverter_CopyPixels,
1270 FormatConverter_Initialize,
1271 FormatConverter_CanConvert
1274 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1276 FormatConverter *This;
1277 HRESULT ret;
1279 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1281 *ppv = NULL;
1283 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1284 if (!This) return E_OUTOFMEMORY;
1286 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1287 This->ref = 1;
1288 This->source = NULL;
1289 InitializeCriticalSection(&This->lock);
1290 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1292 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1293 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1295 return ret;