usp10/tests: A spelling fix in an ok() message.
[wine.git] / dlls / windowscodecs / converter.c
blobdcc2f05693f1f3d5d8f23d541305d992a0d09fc5
1 /*
2 * Copyright 2009 Vincent Povirk
3 * Copyright 2016 Dmitry Timoshkov
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
22 #include <stdarg.h>
23 #include <math.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "objbase.h"
31 #include "wincodecs_private.h"
33 #include "wine/heap.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 struct FormatConverter;
40 enum pixelformat {
41 format_1bppIndexed,
42 format_2bppIndexed,
43 format_4bppIndexed,
44 format_8bppIndexed,
45 format_BlackWhite,
46 format_2bppGray,
47 format_4bppGray,
48 format_8bppGray,
49 format_16bppGray,
50 format_16bppBGR555,
51 format_16bppBGR565,
52 format_16bppBGRA5551,
53 format_24bppBGR,
54 format_24bppRGB,
55 format_32bppGrayFloat,
56 format_32bppBGR,
57 format_32bppRGB,
58 format_32bppBGRA,
59 format_32bppRGBA,
60 format_32bppPBGRA,
61 format_32bppPRGBA,
62 format_48bppRGB,
63 format_64bppRGBA,
64 format_32bppCMYK,
67 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
68 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
70 struct pixelformatinfo {
71 enum pixelformat format;
72 const WICPixelFormatGUID *guid;
73 copyfunc copy_function;
76 typedef struct FormatConverter {
77 IWICFormatConverter IWICFormatConverter_iface;
78 LONG ref;
79 IWICBitmapSource *source;
80 const struct pixelformatinfo *dst_format, *src_format;
81 WICBitmapDitherType dither;
82 double alpha_threshold;
83 IWICPalette *palette;
84 CRITICAL_SECTION lock; /* must be held when initialized */
85 } FormatConverter;
87 /* https://www.w3.org/Graphics/Color/srgb */
88 static inline float to_sRGB_component(float f)
90 if (f <= 0.0031308f) return 12.92f * f;
91 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
94 #if 0 /* FIXME: enable once needed */
95 static inline float from_sRGB_component(float f)
97 if (f <= 0.04045f) return f / 12.92f;
98 return powf((f + 0.055f) / 1.055f, 2.4f);
101 static void from_sRGB(BYTE *bgr)
103 float r, g, b;
105 r = bgr[2] / 255.0f;
106 g = bgr[1] / 255.0f;
107 b = bgr[0] / 255.0f;
109 r = from_sRGB_component(r);
110 g = from_sRGB_component(g);
111 b = from_sRGB_component(b);
113 bgr[2] = (BYTE)(r * 255.0f);
114 bgr[1] = (BYTE)(g * 255.0f);
115 bgr[0] = (BYTE)(b * 255.0f);
118 static void to_sRGB(BYTE *bgr)
120 float r, g, b;
122 r = bgr[2] / 255.0f;
123 g = bgr[1] / 255.0f;
124 b = bgr[0] / 255.0f;
126 r = to_sRGB_component(r);
127 g = to_sRGB_component(g);
128 b = to_sRGB_component(b);
130 bgr[2] = (BYTE)(r * 255.0f);
131 bgr[1] = (BYTE)(g * 255.0f);
132 bgr[0] = (BYTE)(b * 255.0f);
134 #endif
136 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
138 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
141 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
142 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
144 switch (source_format)
146 case format_1bppIndexed:
147 case format_BlackWhite:
148 if (prc)
150 HRESULT res;
151 INT x, y;
152 BYTE *srcdata;
153 UINT srcstride, srcdatasize;
154 const BYTE *srcrow;
155 const BYTE *srcbyte;
156 BYTE *dstrow;
157 DWORD *dstpixel;
158 WICColor colors[2];
159 IWICPalette *palette;
160 UINT actualcolors;
162 res = PaletteImpl_Create(&palette);
163 if (FAILED(res)) return res;
165 if (source_format == format_1bppIndexed)
166 res = IWICBitmapSource_CopyPalette(This->source, palette);
167 else
168 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
170 if (SUCCEEDED(res))
171 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
173 IWICPalette_Release(palette);
174 if (FAILED(res)) return res;
176 srcstride = (prc->Width+7)/8;
177 srcdatasize = srcstride * prc->Height;
179 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
180 if (!srcdata) return E_OUTOFMEMORY;
182 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
184 if (SUCCEEDED(res))
186 srcrow = srcdata;
187 dstrow = pbBuffer;
188 for (y=0; y<prc->Height; y++) {
189 srcbyte = srcrow;
190 dstpixel=(DWORD*)dstrow;
191 for (x=0; x<prc->Width; x+=8) {
192 BYTE srcval;
193 srcval=*srcbyte++;
194 *dstpixel++ = colors[srcval>>7&1];
195 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
196 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
197 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
198 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
199 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
200 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
201 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
203 srcrow += srcstride;
204 dstrow += cbStride;
208 HeapFree(GetProcessHeap(), 0, srcdata);
210 return res;
212 return S_OK;
213 case format_2bppIndexed:
214 case format_2bppGray:
215 if (prc)
217 HRESULT res;
218 INT x, y;
219 BYTE *srcdata;
220 UINT srcstride, srcdatasize;
221 const BYTE *srcrow;
222 const BYTE *srcbyte;
223 BYTE *dstrow;
224 DWORD *dstpixel;
225 WICColor colors[4];
226 IWICPalette *palette;
227 UINT actualcolors;
229 res = PaletteImpl_Create(&palette);
230 if (FAILED(res)) return res;
232 if (source_format == format_2bppIndexed)
233 res = IWICBitmapSource_CopyPalette(This->source, palette);
234 else
235 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
237 if (SUCCEEDED(res))
238 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
240 IWICPalette_Release(palette);
241 if (FAILED(res)) return res;
243 srcstride = (prc->Width+3)/4;
244 srcdatasize = srcstride * prc->Height;
246 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
247 if (!srcdata) return E_OUTOFMEMORY;
249 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
251 if (SUCCEEDED(res))
253 srcrow = srcdata;
254 dstrow = pbBuffer;
255 for (y=0; y<prc->Height; y++) {
256 srcbyte = srcrow;
257 dstpixel=(DWORD*)dstrow;
258 for (x=0; x<prc->Width; x+=4) {
259 BYTE srcval;
260 srcval=*srcbyte++;
261 *dstpixel++ = colors[srcval>>6];
262 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
263 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
264 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
266 srcrow += srcstride;
267 dstrow += cbStride;
271 HeapFree(GetProcessHeap(), 0, srcdata);
273 return res;
275 return S_OK;
276 case format_4bppIndexed:
277 case format_4bppGray:
278 if (prc)
280 HRESULT res;
281 INT x, y;
282 BYTE *srcdata;
283 UINT srcstride, srcdatasize;
284 const BYTE *srcrow;
285 const BYTE *srcbyte;
286 BYTE *dstrow;
287 DWORD *dstpixel;
288 WICColor colors[16];
289 IWICPalette *palette;
290 UINT actualcolors;
292 res = PaletteImpl_Create(&palette);
293 if (FAILED(res)) return res;
295 if (source_format == format_4bppIndexed)
296 res = IWICBitmapSource_CopyPalette(This->source, palette);
297 else
298 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
300 if (SUCCEEDED(res))
301 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
303 IWICPalette_Release(palette);
304 if (FAILED(res)) return res;
306 srcstride = (prc->Width+1)/2;
307 srcdatasize = srcstride * prc->Height;
309 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
310 if (!srcdata) return E_OUTOFMEMORY;
312 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
314 if (SUCCEEDED(res))
316 srcrow = srcdata;
317 dstrow = pbBuffer;
318 for (y=0; y<prc->Height; y++) {
319 srcbyte = srcrow;
320 dstpixel=(DWORD*)dstrow;
321 for (x=0; x<prc->Width; x+=2) {
322 BYTE srcval;
323 srcval=*srcbyte++;
324 *dstpixel++ = colors[srcval>>4];
325 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
327 srcrow += srcstride;
328 dstrow += cbStride;
332 HeapFree(GetProcessHeap(), 0, srcdata);
334 return res;
336 return S_OK;
337 case format_8bppGray:
338 if (prc)
340 HRESULT res;
341 INT x, y;
342 BYTE *srcdata;
343 UINT srcstride, srcdatasize;
344 const BYTE *srcrow;
345 const BYTE *srcbyte;
346 BYTE *dstrow;
347 DWORD *dstpixel;
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++)
366 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
367 srcbyte++;
369 srcrow += srcstride;
370 dstrow += cbStride;
374 HeapFree(GetProcessHeap(), 0, srcdata);
376 return res;
378 return S_OK;
379 case format_8bppIndexed:
380 if (prc)
382 HRESULT res;
383 INT x, y;
384 BYTE *srcdata;
385 UINT srcstride, srcdatasize;
386 const BYTE *srcrow;
387 const BYTE *srcbyte;
388 BYTE *dstrow;
389 DWORD *dstpixel;
390 WICColor colors[256];
391 IWICPalette *palette;
392 UINT actualcolors;
394 res = PaletteImpl_Create(&palette);
395 if (FAILED(res)) return res;
397 res = IWICBitmapSource_CopyPalette(This->source, palette);
398 if (SUCCEEDED(res))
399 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
401 IWICPalette_Release(palette);
403 if (FAILED(res)) return res;
405 srcstride = prc->Width;
406 srcdatasize = srcstride * prc->Height;
408 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
409 if (!srcdata) return E_OUTOFMEMORY;
411 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
413 if (SUCCEEDED(res))
415 srcrow = srcdata;
416 dstrow = pbBuffer;
417 for (y=0; y<prc->Height; y++) {
418 srcbyte = srcrow;
419 dstpixel=(DWORD*)dstrow;
420 for (x=0; x<prc->Width; x++)
421 *dstpixel++ = colors[*srcbyte++];
422 srcrow += srcstride;
423 dstrow += cbStride;
427 HeapFree(GetProcessHeap(), 0, srcdata);
429 return res;
431 return S_OK;
432 case format_16bppGray:
433 if (prc)
435 HRESULT res;
436 INT x, y;
437 BYTE *srcdata;
438 UINT srcstride, srcdatasize;
439 const BYTE *srcrow;
440 const BYTE *srcbyte;
441 BYTE *dstrow;
442 DWORD *dstpixel;
444 srcstride = prc->Width * 2;
445 srcdatasize = srcstride * prc->Height;
447 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
448 if (!srcdata) return E_OUTOFMEMORY;
450 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
452 if (SUCCEEDED(res))
454 srcrow = srcdata;
455 dstrow = pbBuffer;
456 for (y=0; y<prc->Height; y++) {
457 srcbyte = srcrow;
458 dstpixel=(DWORD*)dstrow;
459 for (x=0; x<prc->Width; x++)
461 srcbyte++;
462 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
463 srcbyte++;
465 srcrow += srcstride;
466 dstrow += cbStride;
470 HeapFree(GetProcessHeap(), 0, srcdata);
472 return res;
474 return S_OK;
475 case format_16bppBGR555:
476 if (prc)
478 HRESULT res;
479 INT x, y;
480 BYTE *srcdata;
481 UINT srcstride, srcdatasize;
482 const BYTE *srcrow;
483 const WORD *srcpixel;
484 BYTE *dstrow;
485 DWORD *dstpixel;
487 srcstride = 2 * prc->Width;
488 srcdatasize = srcstride * prc->Height;
490 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
491 if (!srcdata) return E_OUTOFMEMORY;
493 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
495 if (SUCCEEDED(res))
497 srcrow = srcdata;
498 dstrow = pbBuffer;
499 for (y=0; y<prc->Height; y++) {
500 srcpixel=(const WORD*)srcrow;
501 dstpixel=(DWORD*)dstrow;
502 for (x=0; x<prc->Width; x++) {
503 WORD srcval;
504 srcval=*srcpixel++;
505 *dstpixel++=0xff000000 | /* constant 255 alpha */
506 ((srcval << 9) & 0xf80000) | /* r */
507 ((srcval << 4) & 0x070000) | /* r - 3 bits */
508 ((srcval << 6) & 0x00f800) | /* g */
509 ((srcval << 1) & 0x000700) | /* g - 3 bits */
510 ((srcval << 3) & 0x0000f8) | /* b */
511 ((srcval >> 2) & 0x000007); /* b - 3 bits */
513 srcrow += srcstride;
514 dstrow += cbStride;
518 HeapFree(GetProcessHeap(), 0, srcdata);
520 return res;
522 return S_OK;
523 case format_16bppBGR565:
524 if (prc)
526 HRESULT res;
527 INT x, y;
528 BYTE *srcdata;
529 UINT srcstride, srcdatasize;
530 const BYTE *srcrow;
531 const WORD *srcpixel;
532 BYTE *dstrow;
533 DWORD *dstpixel;
535 srcstride = 2 * prc->Width;
536 srcdatasize = srcstride * prc->Height;
538 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
539 if (!srcdata) return E_OUTOFMEMORY;
541 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
543 if (SUCCEEDED(res))
545 srcrow = srcdata;
546 dstrow = pbBuffer;
547 for (y=0; y<prc->Height; y++) {
548 srcpixel=(const WORD*)srcrow;
549 dstpixel=(DWORD*)dstrow;
550 for (x=0; x<prc->Width; x++) {
551 WORD srcval;
552 srcval=*srcpixel++;
553 *dstpixel++=0xff000000 | /* constant 255 alpha */
554 ((srcval << 8) & 0xf80000) | /* r */
555 ((srcval << 3) & 0x070000) | /* r - 3 bits */
556 ((srcval << 5) & 0x00fc00) | /* g */
557 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
558 ((srcval << 3) & 0x0000f8) | /* b */
559 ((srcval >> 2) & 0x000007); /* b - 3 bits */
561 srcrow += srcstride;
562 dstrow += cbStride;
566 HeapFree(GetProcessHeap(), 0, srcdata);
568 return res;
570 return S_OK;
571 case format_16bppBGRA5551:
572 if (prc)
574 HRESULT res;
575 INT x, y;
576 BYTE *srcdata;
577 UINT srcstride, srcdatasize;
578 const BYTE *srcrow;
579 const WORD *srcpixel;
580 BYTE *dstrow;
581 DWORD *dstpixel;
583 srcstride = 2 * prc->Width;
584 srcdatasize = srcstride * prc->Height;
586 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
587 if (!srcdata) return E_OUTOFMEMORY;
589 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
591 if (SUCCEEDED(res))
593 srcrow = srcdata;
594 dstrow = pbBuffer;
595 for (y=0; y<prc->Height; y++) {
596 srcpixel=(const WORD*)srcrow;
597 dstpixel=(DWORD*)dstrow;
598 for (x=0; x<prc->Width; x++) {
599 WORD srcval;
600 srcval=*srcpixel++;
601 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
602 ((srcval << 9) & 0xf80000) | /* r */
603 ((srcval << 4) & 0x070000) | /* r - 3 bits */
604 ((srcval << 6) & 0x00f800) | /* g */
605 ((srcval << 1) & 0x000700) | /* g - 3 bits */
606 ((srcval << 3) & 0x0000f8) | /* b */
607 ((srcval >> 2) & 0x000007); /* b - 3 bits */
609 srcrow += srcstride;
610 dstrow += cbStride;
614 HeapFree(GetProcessHeap(), 0, srcdata);
616 return res;
618 return S_OK;
619 case format_24bppBGR:
620 if (prc)
622 HRESULT res;
623 INT x, y;
624 BYTE *srcdata;
625 UINT srcstride, srcdatasize;
626 const BYTE *srcrow;
627 const BYTE *srcpixel;
628 BYTE *dstrow;
629 BYTE *dstpixel;
631 srcstride = 3 * prc->Width;
632 srcdatasize = srcstride * prc->Height;
634 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
635 if (!srcdata) return E_OUTOFMEMORY;
637 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
639 if (SUCCEEDED(res))
641 srcrow = srcdata;
642 dstrow = pbBuffer;
643 for (y=0; y<prc->Height; y++) {
644 srcpixel=srcrow;
645 dstpixel=dstrow;
646 for (x=0; x<prc->Width; x++) {
647 *dstpixel++=*srcpixel++; /* blue */
648 *dstpixel++=*srcpixel++; /* green */
649 *dstpixel++=*srcpixel++; /* red */
650 *dstpixel++=255; /* alpha */
652 srcrow += srcstride;
653 dstrow += cbStride;
657 HeapFree(GetProcessHeap(), 0, srcdata);
659 return res;
661 return S_OK;
662 case format_24bppRGB:
663 if (prc)
665 HRESULT res;
666 INT x, y;
667 BYTE *srcdata;
668 UINT srcstride, srcdatasize;
669 const BYTE *srcrow;
670 const BYTE *srcpixel;
671 BYTE *dstrow;
672 BYTE *dstpixel;
673 BYTE tmppixel[3];
675 srcstride = 3 * prc->Width;
676 srcdatasize = srcstride * prc->Height;
678 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
679 if (!srcdata) return E_OUTOFMEMORY;
681 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
683 if (SUCCEEDED(res))
685 srcrow = srcdata;
686 dstrow = pbBuffer;
687 for (y=0; y<prc->Height; y++) {
688 srcpixel=srcrow;
689 dstpixel=dstrow;
690 for (x=0; x<prc->Width; x++) {
691 tmppixel[0]=*srcpixel++; /* red */
692 tmppixel[1]=*srcpixel++; /* green */
693 tmppixel[2]=*srcpixel++; /* blue */
695 *dstpixel++=tmppixel[2]; /* blue */
696 *dstpixel++=tmppixel[1]; /* green */
697 *dstpixel++=tmppixel[0]; /* red */
698 *dstpixel++=255; /* alpha */
700 srcrow += srcstride;
701 dstrow += cbStride;
705 HeapFree(GetProcessHeap(), 0, srcdata);
707 return res;
709 return S_OK;
710 case format_32bppBGR:
711 if (prc)
713 HRESULT res;
714 INT x, y;
716 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
717 if (FAILED(res)) return res;
719 /* set all alpha values to 255 */
720 for (y=0; y<prc->Height; y++)
721 for (x=0; x<prc->Width; x++)
722 pbBuffer[cbStride*y+4*x+3] = 0xff;
724 return S_OK;
725 case format_32bppBGRA:
726 if (prc)
727 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
728 return S_OK;
729 case format_32bppPBGRA:
730 if (prc)
732 HRESULT res;
733 INT x, y;
735 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
736 if (FAILED(res)) return res;
738 for (y=0; y<prc->Height; y++)
739 for (x=0; x<prc->Width; x++)
741 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
742 if (alpha != 0 && alpha != 255)
744 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
745 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
746 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
750 return S_OK;
751 case format_48bppRGB:
752 if (prc)
754 HRESULT res;
755 INT x, y;
756 BYTE *srcdata;
757 UINT srcstride, srcdatasize;
758 const BYTE *srcrow;
759 const BYTE *srcpixel;
760 BYTE *dstrow;
761 DWORD *dstpixel;
763 srcstride = 6 * prc->Width;
764 srcdatasize = srcstride * prc->Height;
766 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
767 if (!srcdata) return E_OUTOFMEMORY;
769 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
771 if (SUCCEEDED(res))
773 srcrow = srcdata;
774 dstrow = pbBuffer;
775 for (y=0; y<prc->Height; y++) {
776 srcpixel=srcrow;
777 dstpixel=(DWORD*)dstrow;
778 for (x=0; x<prc->Width; x++) {
779 BYTE red, green, blue;
780 srcpixel++; red = *srcpixel++;
781 srcpixel++; green = *srcpixel++;
782 srcpixel++; blue = *srcpixel++;
783 *dstpixel++=0xff000000|red<<16|green<<8|blue;
785 srcrow += srcstride;
786 dstrow += cbStride;
790 HeapFree(GetProcessHeap(), 0, srcdata);
792 return res;
794 return S_OK;
795 case format_64bppRGBA:
796 if (prc)
798 HRESULT res;
799 INT x, y;
800 BYTE *srcdata;
801 UINT srcstride, srcdatasize;
802 const BYTE *srcrow;
803 const BYTE *srcpixel;
804 BYTE *dstrow;
805 DWORD *dstpixel;
807 srcstride = 8 * prc->Width;
808 srcdatasize = srcstride * prc->Height;
810 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
811 if (!srcdata) return E_OUTOFMEMORY;
813 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
815 if (SUCCEEDED(res))
817 srcrow = srcdata;
818 dstrow = pbBuffer;
819 for (y=0; y<prc->Height; y++) {
820 srcpixel=srcrow;
821 dstpixel=(DWORD*)dstrow;
822 for (x=0; x<prc->Width; x++) {
823 BYTE red, green, blue, alpha;
824 srcpixel++; red = *srcpixel++;
825 srcpixel++; green = *srcpixel++;
826 srcpixel++; blue = *srcpixel++;
827 srcpixel++; alpha = *srcpixel++;
828 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
830 srcrow += srcstride;
831 dstrow += cbStride;
835 HeapFree(GetProcessHeap(), 0, srcdata);
837 return res;
839 return S_OK;
840 case format_32bppCMYK:
841 if (prc)
843 HRESULT res;
844 UINT x, y;
846 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
847 if (FAILED(res)) return res;
849 for (y=0; y<prc->Height; y++)
850 for (x=0; x<prc->Width; x++)
852 BYTE *pixel = pbBuffer+cbStride*y+4*x;
853 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
854 pixel[0] = (255-y)*(255-k)/255; /* blue */
855 pixel[1] = (255-m)*(255-k)/255; /* green */
856 pixel[2] = (255-c)*(255-k)/255; /* red */
857 pixel[3] = 255; /* alpha */
860 return S_OK;
861 default:
862 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
866 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
867 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
869 HRESULT hr;
871 switch (source_format)
873 case format_32bppRGB:
874 if (prc)
876 INT x, y;
878 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
879 if (FAILED(hr)) return hr;
881 /* set all alpha values to 255 */
882 for (y=0; y<prc->Height; y++)
883 for (x=0; x<prc->Width; x++)
884 pbBuffer[cbStride*y+4*x+3] = 0xff;
886 return S_OK;
888 case format_32bppRGBA:
889 if (prc)
890 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
891 return S_OK;
893 case format_32bppPRGBA:
894 if (prc)
896 INT x, y;
898 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
899 if (FAILED(hr)) return hr;
901 for (y=0; y<prc->Height; y++)
902 for (x=0; x<prc->Width; x++)
904 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
905 if (alpha != 0 && alpha != 255)
907 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
908 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
909 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
913 return S_OK;
915 default:
916 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
917 if (SUCCEEDED(hr) && prc)
918 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
919 return hr;
923 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
924 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
926 switch (source_format)
928 case format_32bppBGR:
929 case format_32bppBGRA:
930 case format_32bppPBGRA:
931 if (prc)
932 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
933 return S_OK;
934 default:
935 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
939 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
940 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
942 switch (source_format)
944 case format_32bppRGB:
945 case format_32bppRGBA:
946 case format_32bppPRGBA:
947 if (prc)
948 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
949 return S_OK;
950 default:
951 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
955 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
956 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
958 HRESULT hr;
960 switch (source_format)
962 case format_32bppPBGRA:
963 if (prc)
964 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
965 return S_OK;
966 default:
967 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
968 if (SUCCEEDED(hr) && prc)
970 INT x, y;
972 for (y=0; y<prc->Height; y++)
973 for (x=0; x<prc->Width; x++)
975 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
976 if (alpha != 255)
978 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
979 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
980 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
984 return hr;
988 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
989 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
991 HRESULT hr;
993 switch (source_format)
995 case format_32bppPRGBA:
996 if (prc)
997 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
998 return S_OK;
999 default:
1000 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1001 if (SUCCEEDED(hr) && prc)
1003 INT x, y;
1005 for (y=0; y<prc->Height; y++)
1006 for (x=0; x<prc->Width; x++)
1008 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1009 if (alpha != 255)
1011 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
1012 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1013 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
1017 return hr;
1021 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1022 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1024 HRESULT hr;
1026 switch (source_format)
1028 case format_24bppBGR:
1029 case format_24bppRGB:
1030 if (prc)
1032 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1033 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1034 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1035 return hr;
1037 return S_OK;
1038 case format_32bppBGR:
1039 case format_32bppBGRA:
1040 case format_32bppPBGRA:
1041 if (prc)
1043 HRESULT res;
1044 INT x, y;
1045 BYTE *srcdata;
1046 UINT srcstride, srcdatasize;
1047 const BYTE *srcrow;
1048 const BYTE *srcpixel;
1049 BYTE *dstrow;
1050 BYTE *dstpixel;
1052 srcstride = 4 * prc->Width;
1053 srcdatasize = srcstride * prc->Height;
1055 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1056 if (!srcdata) return E_OUTOFMEMORY;
1058 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1060 if (SUCCEEDED(res))
1062 srcrow = srcdata;
1063 dstrow = pbBuffer;
1064 for (y=0; y<prc->Height; y++) {
1065 srcpixel=srcrow;
1066 dstpixel=dstrow;
1067 for (x=0; x<prc->Width; x++) {
1068 *dstpixel++=*srcpixel++; /* blue */
1069 *dstpixel++=*srcpixel++; /* green */
1070 *dstpixel++=*srcpixel++; /* red */
1071 srcpixel++; /* alpha */
1073 srcrow += srcstride;
1074 dstrow += cbStride;
1078 HeapFree(GetProcessHeap(), 0, srcdata);
1080 return res;
1082 return S_OK;
1084 case format_32bppGrayFloat:
1085 if (prc)
1087 BYTE *srcdata;
1088 UINT srcstride, srcdatasize;
1090 srcstride = 4 * prc->Width;
1091 srcdatasize = srcstride * prc->Height;
1093 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1094 if (!srcdata) return E_OUTOFMEMORY;
1096 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1098 if (SUCCEEDED(hr))
1100 INT x, y;
1101 BYTE *src = srcdata, *dst = pbBuffer;
1103 for (y = 0; y < prc->Height; y++)
1105 float *gray_float = (float *)src;
1106 BYTE *bgr = dst;
1108 for (x = 0; x < prc->Width; x++)
1110 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1111 *bgr++ = gray;
1112 *bgr++ = gray;
1113 *bgr++ = gray;
1115 src += srcstride;
1116 dst += cbStride;
1120 HeapFree(GetProcessHeap(), 0, srcdata);
1122 return hr;
1124 return S_OK;
1126 case format_32bppCMYK:
1127 if (prc)
1129 BYTE *srcdata;
1130 UINT srcstride, srcdatasize;
1132 srcstride = 4 * prc->Width;
1133 srcdatasize = srcstride * prc->Height;
1135 srcdata = heap_alloc(srcdatasize);
1136 if (!srcdata) return E_OUTOFMEMORY;
1138 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1139 if (SUCCEEDED(hr))
1141 INT x, y;
1142 BYTE *src = srcdata, *dst = pbBuffer;
1144 for (y = 0; y < prc->Height; y++)
1146 BYTE *cmyk = src;
1147 BYTE *bgr = dst;
1149 for (x = 0; x < prc->Width; x++)
1151 BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
1152 bgr[0] = (255 - y) * (255 - k) / 255; /* B */
1153 bgr[1] = (255 - m) * (255 - k) / 255; /* G */
1154 bgr[2] = (255 - c) * (255 - k) / 255; /* R */
1155 cmyk += 4;
1156 bgr += 3;
1158 src += srcstride;
1159 dst += cbStride;
1163 heap_free(srcdata);
1164 return hr;
1166 return S_OK;
1168 default:
1169 FIXME("Unimplemented conversion path!\n");
1170 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1174 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1175 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1177 HRESULT hr;
1179 switch (source_format)
1181 case format_24bppBGR:
1182 case format_24bppRGB:
1183 if (prc)
1185 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1186 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1187 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1188 return hr;
1190 return S_OK;
1191 case format_32bppBGR:
1192 case format_32bppBGRA:
1193 case format_32bppPBGRA:
1194 if (prc)
1196 HRESULT res;
1197 INT x, y;
1198 BYTE *srcdata;
1199 UINT srcstride, srcdatasize;
1200 const BYTE *srcrow;
1201 const BYTE *srcpixel;
1202 BYTE *dstrow;
1203 BYTE *dstpixel;
1204 BYTE tmppixel[3];
1206 srcstride = 4 * prc->Width;
1207 srcdatasize = srcstride * prc->Height;
1209 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1210 if (!srcdata) return E_OUTOFMEMORY;
1212 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1214 if (SUCCEEDED(res))
1216 srcrow = srcdata;
1217 dstrow = pbBuffer;
1218 for (y=0; y<prc->Height; y++) {
1219 srcpixel=srcrow;
1220 dstpixel=dstrow;
1221 for (x=0; x<prc->Width; x++) {
1222 tmppixel[0]=*srcpixel++; /* blue */
1223 tmppixel[1]=*srcpixel++; /* green */
1224 tmppixel[2]=*srcpixel++; /* red */
1225 srcpixel++; /* alpha */
1227 *dstpixel++=tmppixel[2]; /* red */
1228 *dstpixel++=tmppixel[1]; /* green */
1229 *dstpixel++=tmppixel[0]; /* blue */
1231 srcrow += srcstride;
1232 dstrow += cbStride;
1236 HeapFree(GetProcessHeap(), 0, srcdata);
1238 return res;
1240 return S_OK;
1241 default:
1242 FIXME("Unimplemented conversion path!\n");
1243 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1247 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1248 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1250 HRESULT hr;
1252 switch (source_format)
1254 case format_32bppBGR:
1255 case format_32bppBGRA:
1256 case format_32bppPBGRA:
1257 case format_32bppGrayFloat:
1258 if (prc)
1260 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1261 break;
1263 return S_OK;
1265 default:
1266 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1267 break;
1270 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1272 INT x, y;
1273 BYTE *p = pbBuffer;
1275 for (y = 0; y < prc->Height; y++)
1277 BYTE *bgr = p;
1278 for (x = 0; x < prc->Width; x++)
1280 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1281 *(float *)bgr = gray;
1282 bgr += 4;
1284 p += cbStride;
1287 return hr;
1290 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1291 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1293 HRESULT hr;
1294 BYTE *srcdata;
1295 UINT srcstride, srcdatasize;
1297 if (source_format == format_8bppGray)
1299 if (prc)
1300 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1302 return S_OK;
1305 if (source_format == format_32bppGrayFloat)
1307 hr = S_OK;
1309 if (prc)
1311 srcstride = 4 * prc->Width;
1312 srcdatasize = srcstride * prc->Height;
1314 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1315 if (!srcdata) return E_OUTOFMEMORY;
1317 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1318 if (SUCCEEDED(hr))
1320 INT x, y;
1321 BYTE *src = srcdata, *dst = pbBuffer;
1323 for (y=0; y < prc->Height; y++)
1325 float *srcpixel = (float*)src;
1326 BYTE *dstpixel = dst;
1328 for (x=0; x < prc->Width; x++)
1329 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1331 src += srcstride;
1332 dst += cbStride;
1336 HeapFree(GetProcessHeap(), 0, srcdata);
1339 return hr;
1342 if (!prc)
1343 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1345 srcstride = 3 * prc->Width;
1346 srcdatasize = srcstride * prc->Height;
1348 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1349 if (!srcdata) return E_OUTOFMEMORY;
1351 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1352 if (SUCCEEDED(hr))
1354 INT x, y;
1355 BYTE *src = srcdata, *dst = pbBuffer;
1357 for (y = 0; y < prc->Height; y++)
1359 BYTE *bgr = src;
1361 for (x = 0; x < prc->Width; x++)
1363 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1365 gray = to_sRGB_component(gray) * 255.0f;
1366 dst[x] = (BYTE)floorf(gray + 0.51f);
1367 bgr += 3;
1369 src += srcstride;
1370 dst += cbStride;
1374 HeapFree(GetProcessHeap(), 0, srcdata);
1375 return hr;
1378 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1380 UINT best_diff, best_index, i;
1382 best_diff = ~0;
1383 best_index = 0;
1385 for (i = 0; i < count; i++)
1387 BYTE pal_r, pal_g, pal_b;
1388 UINT diff_r, diff_g, diff_b, diff;
1390 pal_r = colors[i] >> 16;
1391 pal_g = colors[i] >> 8;
1392 pal_b = colors[i];
1394 diff_r = bgr[2] - pal_r;
1395 diff_g = bgr[1] - pal_g;
1396 diff_b = bgr[0] - pal_b;
1398 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1399 if (diff == 0) return i;
1401 if (diff < best_diff)
1403 best_diff = diff;
1404 best_index = i;
1408 return best_index;
1411 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1412 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1414 HRESULT hr;
1415 BYTE *srcdata;
1416 WICColor colors[256];
1417 UINT srcstride, srcdatasize, count;
1419 if (source_format == format_8bppIndexed)
1421 if (prc)
1422 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1424 return S_OK;
1427 if (!prc)
1428 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1430 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1432 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1433 if (hr != S_OK) return hr;
1435 srcstride = 3 * prc->Width;
1436 srcdatasize = srcstride * prc->Height;
1438 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1439 if (!srcdata) return E_OUTOFMEMORY;
1441 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1442 if (SUCCEEDED(hr))
1444 INT x, y;
1445 BYTE *src = srcdata, *dst = pbBuffer;
1447 for (y = 0; y < prc->Height; y++)
1449 BYTE *bgr = src;
1451 for (x = 0; x < prc->Width; x++)
1453 dst[x] = rgb_to_palette_index(bgr, colors, count);
1454 bgr += 3;
1456 src += srcstride;
1457 dst += cbStride;
1461 HeapFree(GetProcessHeap(), 0, srcdata);
1462 return hr;
1465 static const struct pixelformatinfo supported_formats[] = {
1466 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1467 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1468 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1469 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1470 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1471 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1472 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1473 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1474 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1475 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1476 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1477 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1478 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1479 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1480 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1481 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1482 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1483 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1484 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1485 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1486 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1487 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1488 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1489 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1493 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1495 UINT i;
1497 for (i=0; supported_formats[i].guid; i++)
1498 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1500 return NULL;
1503 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1504 void **ppv)
1506 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1507 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1509 if (!ppv) return E_INVALIDARG;
1511 if (IsEqualIID(&IID_IUnknown, iid) ||
1512 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1513 IsEqualIID(&IID_IWICFormatConverter, iid))
1515 *ppv = &This->IWICFormatConverter_iface;
1517 else
1519 *ppv = NULL;
1520 return E_NOINTERFACE;
1523 IUnknown_AddRef((IUnknown*)*ppv);
1524 return S_OK;
1527 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1529 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1530 ULONG ref = InterlockedIncrement(&This->ref);
1532 TRACE("(%p) refcount=%u\n", iface, ref);
1534 return ref;
1537 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1539 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1540 ULONG ref = InterlockedDecrement(&This->ref);
1542 TRACE("(%p) refcount=%u\n", iface, ref);
1544 if (ref == 0)
1546 This->lock.DebugInfo->Spare[0] = 0;
1547 DeleteCriticalSection(&This->lock);
1548 if (This->source) IWICBitmapSource_Release(This->source);
1549 if (This->palette) IWICPalette_Release(This->palette);
1550 HeapFree(GetProcessHeap(), 0, This);
1553 return ref;
1556 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1557 UINT *puiWidth, UINT *puiHeight)
1559 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1561 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1563 if (This->source)
1564 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1565 else
1566 return WINCODEC_ERR_NOTINITIALIZED;
1569 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1570 WICPixelFormatGUID *pPixelFormat)
1572 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1574 TRACE("(%p,%p)\n", iface, pPixelFormat);
1576 if (This->source)
1577 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1578 else
1579 return WINCODEC_ERR_NOTINITIALIZED;
1581 return S_OK;
1584 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1585 double *pDpiX, double *pDpiY)
1587 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1589 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1591 if (This->source)
1592 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1593 else
1594 return WINCODEC_ERR_NOTINITIALIZED;
1597 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1598 IWICPalette *palette)
1600 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1602 TRACE("(%p,%p)\n", iface, palette);
1604 if (!palette) return E_INVALIDARG;
1605 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1607 if (!This->palette)
1609 HRESULT hr;
1610 UINT bpp;
1612 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1613 if (hr != S_OK) return hr;
1614 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1615 return IWICBitmapSource_CopyPalette(This->source, palette);
1618 return IWICPalette_InitializeFromPalette(palette, This->palette);
1621 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1622 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1624 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1625 WICRect rc;
1626 HRESULT hr;
1627 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1629 if (This->source)
1631 if (!prc)
1633 UINT width, height;
1634 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1635 if (FAILED(hr)) return hr;
1636 rc.X = 0;
1637 rc.Y = 0;
1638 rc.Width = width;
1639 rc.Height = height;
1640 prc = &rc;
1643 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1644 pbBuffer, This->src_format->format);
1646 else
1647 return WINCODEC_ERR_WRONGSTATE;
1650 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1651 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1652 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1654 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1655 const struct pixelformatinfo *srcinfo, *dstinfo;
1656 GUID srcFormat;
1657 HRESULT res;
1659 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1660 dither, palette, alpha_threshold, palette_type);
1662 if (!palette)
1664 UINT bpp;
1665 res = get_pixelformat_bpp(dstFormat, &bpp);
1666 if (res != S_OK) return res;
1668 res = PaletteImpl_Create(&palette);
1669 if (res != S_OK) return res;
1671 switch (palette_type)
1673 case WICBitmapPaletteTypeCustom:
1674 IWICPalette_Release(palette);
1675 palette = NULL;
1676 if (bpp <= 8) return E_INVALIDARG;
1677 break;
1679 case WICBitmapPaletteTypeMedianCut:
1681 if (bpp <= 8)
1682 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1683 break;
1686 default:
1687 if (bpp <= 8)
1688 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1689 break;
1692 if (res != S_OK)
1694 IWICPalette_Release(palette);
1695 return res;
1698 else
1699 IWICPalette_AddRef(palette);
1701 EnterCriticalSection(&This->lock);
1703 if (This->source)
1705 res = WINCODEC_ERR_WRONGSTATE;
1706 goto end;
1709 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1710 if (FAILED(res)) goto end;
1712 srcinfo = get_formatinfo(&srcFormat);
1713 if (!srcinfo)
1715 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1716 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1717 goto end;
1720 dstinfo = get_formatinfo(dstFormat);
1721 if (!dstinfo)
1723 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1724 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1725 goto end;
1728 if (dstinfo->copy_function)
1730 IWICBitmapSource_AddRef(source);
1731 This->src_format = srcinfo;
1732 This->dst_format = dstinfo;
1733 This->dither = dither;
1734 This->alpha_threshold = alpha_threshold;
1735 This->palette = palette;
1736 This->source = source;
1738 else
1740 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1741 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1744 end:
1746 LeaveCriticalSection(&This->lock);
1748 if (res != S_OK && palette)
1749 IWICPalette_Release(palette);
1751 return res;
1754 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1755 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1756 BOOL *pfCanConvert)
1758 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1759 const struct pixelformatinfo *srcinfo, *dstinfo;
1761 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1762 debugstr_guid(dstPixelFormat), pfCanConvert);
1764 srcinfo = get_formatinfo(srcPixelFormat);
1765 if (!srcinfo)
1767 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1768 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1771 dstinfo = get_formatinfo(dstPixelFormat);
1772 if (!dstinfo)
1774 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1775 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1778 if (dstinfo->copy_function &&
1779 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1780 *pfCanConvert = TRUE;
1781 else
1783 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1784 *pfCanConvert = FALSE;
1787 return S_OK;
1790 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1791 FormatConverter_QueryInterface,
1792 FormatConverter_AddRef,
1793 FormatConverter_Release,
1794 FormatConverter_GetSize,
1795 FormatConverter_GetPixelFormat,
1796 FormatConverter_GetResolution,
1797 FormatConverter_CopyPalette,
1798 FormatConverter_CopyPixels,
1799 FormatConverter_Initialize,
1800 FormatConverter_CanConvert
1803 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1805 FormatConverter *This;
1806 HRESULT ret;
1808 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1810 *ppv = NULL;
1812 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1813 if (!This) return E_OUTOFMEMORY;
1815 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1816 This->ref = 1;
1817 This->source = NULL;
1818 This->palette = NULL;
1819 InitializeCriticalSection(&This->lock);
1820 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1822 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1823 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1825 return ret;