quartz/tests: Add some more tests for IMediaSeeking return value handling.
[wine.git] / dlls / windowscodecs / converter.c
blobbc10a9eccc451eca9372c9c6136610dc326d7bd9
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_32bppRGBA:
726 if (prc)
728 HRESULT res;
729 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
730 if (FAILED(res)) return res;
731 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
733 return S_OK;
734 case format_32bppBGRA:
735 if (prc)
736 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
737 return S_OK;
738 case format_32bppPBGRA:
739 if (prc)
741 HRESULT res;
742 INT x, y;
744 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
745 if (FAILED(res)) return res;
747 for (y=0; y<prc->Height; y++)
748 for (x=0; x<prc->Width; x++)
750 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
751 if (alpha != 0 && alpha != 255)
753 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
754 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
755 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
759 return S_OK;
760 case format_48bppRGB:
761 if (prc)
763 HRESULT res;
764 INT x, y;
765 BYTE *srcdata;
766 UINT srcstride, srcdatasize;
767 const BYTE *srcrow;
768 const BYTE *srcpixel;
769 BYTE *dstrow;
770 DWORD *dstpixel;
772 srcstride = 6 * prc->Width;
773 srcdatasize = srcstride * prc->Height;
775 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
776 if (!srcdata) return E_OUTOFMEMORY;
778 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
780 if (SUCCEEDED(res))
782 srcrow = srcdata;
783 dstrow = pbBuffer;
784 for (y=0; y<prc->Height; y++) {
785 srcpixel=srcrow;
786 dstpixel=(DWORD*)dstrow;
787 for (x=0; x<prc->Width; x++) {
788 BYTE red, green, blue;
789 srcpixel++; red = *srcpixel++;
790 srcpixel++; green = *srcpixel++;
791 srcpixel++; blue = *srcpixel++;
792 *dstpixel++=0xff000000|red<<16|green<<8|blue;
794 srcrow += srcstride;
795 dstrow += cbStride;
799 HeapFree(GetProcessHeap(), 0, srcdata);
801 return res;
803 return S_OK;
804 case format_64bppRGBA:
805 if (prc)
807 HRESULT res;
808 INT x, y;
809 BYTE *srcdata;
810 UINT srcstride, srcdatasize;
811 const BYTE *srcrow;
812 const BYTE *srcpixel;
813 BYTE *dstrow;
814 DWORD *dstpixel;
816 srcstride = 8 * prc->Width;
817 srcdatasize = srcstride * prc->Height;
819 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
820 if (!srcdata) return E_OUTOFMEMORY;
822 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
824 if (SUCCEEDED(res))
826 srcrow = srcdata;
827 dstrow = pbBuffer;
828 for (y=0; y<prc->Height; y++) {
829 srcpixel=srcrow;
830 dstpixel=(DWORD*)dstrow;
831 for (x=0; x<prc->Width; x++) {
832 BYTE red, green, blue, alpha;
833 srcpixel++; red = *srcpixel++;
834 srcpixel++; green = *srcpixel++;
835 srcpixel++; blue = *srcpixel++;
836 srcpixel++; alpha = *srcpixel++;
837 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
839 srcrow += srcstride;
840 dstrow += cbStride;
844 HeapFree(GetProcessHeap(), 0, srcdata);
846 return res;
848 return S_OK;
849 case format_32bppCMYK:
850 if (prc)
852 HRESULT res;
853 UINT x, y;
855 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
856 if (FAILED(res)) return res;
858 for (y=0; y<prc->Height; y++)
859 for (x=0; x<prc->Width; x++)
861 BYTE *pixel = pbBuffer+cbStride*y+4*x;
862 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
863 pixel[0] = (255-y)*(255-k)/255; /* blue */
864 pixel[1] = (255-m)*(255-k)/255; /* green */
865 pixel[2] = (255-c)*(255-k)/255; /* red */
866 pixel[3] = 255; /* alpha */
869 return S_OK;
870 default:
871 FIXME("Unimplemented conversion path!\n");
872 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
876 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
877 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
879 HRESULT hr;
881 switch (source_format)
883 case format_32bppRGB:
884 if (prc)
886 INT x, y;
888 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
889 if (FAILED(hr)) return hr;
891 /* set all alpha values to 255 */
892 for (y=0; y<prc->Height; y++)
893 for (x=0; x<prc->Width; x++)
894 pbBuffer[cbStride*y+4*x+3] = 0xff;
896 return S_OK;
898 case format_32bppRGBA:
899 if (prc)
900 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
901 return S_OK;
903 case format_32bppPRGBA:
904 if (prc)
906 INT x, y;
908 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
909 if (FAILED(hr)) return hr;
911 for (y=0; y<prc->Height; y++)
912 for (x=0; x<prc->Width; x++)
914 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
915 if (alpha != 0 && alpha != 255)
917 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
918 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
919 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
923 return S_OK;
925 default:
926 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
927 if (SUCCEEDED(hr) && prc)
928 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
929 return hr;
933 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
934 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
936 switch (source_format)
938 case format_32bppBGR:
939 case format_32bppBGRA:
940 case format_32bppPBGRA:
941 if (prc)
942 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
943 return S_OK;
944 default:
945 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
949 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
950 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
952 switch (source_format)
954 case format_32bppRGB:
955 case format_32bppRGBA:
956 case format_32bppPRGBA:
957 if (prc)
958 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
959 return S_OK;
960 default:
961 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
965 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
966 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
968 HRESULT hr;
970 switch (source_format)
972 case format_32bppPBGRA:
973 if (prc)
974 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
975 return S_OK;
976 default:
977 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
978 if (SUCCEEDED(hr) && prc)
980 INT x, y;
982 for (y=0; y<prc->Height; y++)
983 for (x=0; x<prc->Width; x++)
985 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
986 if (alpha != 255)
988 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
989 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
990 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
994 return hr;
998 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
999 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1001 HRESULT hr;
1003 switch (source_format)
1005 case format_32bppPRGBA:
1006 if (prc)
1007 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1008 return S_OK;
1009 default:
1010 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1011 if (SUCCEEDED(hr) && prc)
1013 INT x, y;
1015 for (y=0; y<prc->Height; y++)
1016 for (x=0; x<prc->Width; x++)
1018 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1019 if (alpha != 255)
1021 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
1022 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1023 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
1027 return hr;
1031 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1032 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1034 HRESULT hr;
1036 switch (source_format)
1038 case format_24bppBGR:
1039 case format_24bppRGB:
1040 if (prc)
1042 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1043 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1044 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1045 return hr;
1047 return S_OK;
1048 case format_32bppBGR:
1049 case format_32bppBGRA:
1050 case format_32bppPBGRA:
1051 case format_32bppRGBA:
1052 if (prc)
1054 HRESULT res;
1055 INT x, y;
1056 BYTE *srcdata;
1057 UINT srcstride, srcdatasize;
1058 const BYTE *srcrow;
1059 const BYTE *srcpixel;
1060 BYTE *dstrow;
1061 BYTE *dstpixel;
1063 srcstride = 4 * prc->Width;
1064 srcdatasize = srcstride * prc->Height;
1066 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1067 if (!srcdata) return E_OUTOFMEMORY;
1069 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1071 if (SUCCEEDED(res))
1073 srcrow = srcdata;
1074 dstrow = pbBuffer;
1076 if (source_format == format_32bppRGBA)
1078 for (y = 0; y < prc->Height; y++)
1080 srcpixel = srcrow;
1081 dstpixel = dstrow;
1082 for (x = 0; x < prc->Width; x++) {
1083 *dstpixel++ = srcpixel[2]; /* blue */
1084 *dstpixel++ = srcpixel[1]; /* green */
1085 *dstpixel++ = srcpixel[0]; /* red */
1086 srcpixel += 4;
1088 srcrow += srcstride;
1089 dstrow += cbStride;
1092 else
1094 for (y = 0; y < prc->Height; y++)
1096 srcpixel = srcrow;
1097 dstpixel = dstrow;
1098 for (x = 0; x < prc->Width; x++) {
1099 *dstpixel++ = *srcpixel++; /* blue */
1100 *dstpixel++ = *srcpixel++; /* green */
1101 *dstpixel++ = *srcpixel++; /* red */
1102 srcpixel++; /* alpha */
1104 srcrow += srcstride;
1105 dstrow += cbStride;
1110 HeapFree(GetProcessHeap(), 0, srcdata);
1112 return res;
1114 return S_OK;
1116 case format_32bppGrayFloat:
1117 if (prc)
1119 BYTE *srcdata;
1120 UINT srcstride, srcdatasize;
1122 srcstride = 4 * prc->Width;
1123 srcdatasize = srcstride * prc->Height;
1125 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1126 if (!srcdata) return E_OUTOFMEMORY;
1128 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1130 if (SUCCEEDED(hr))
1132 INT x, y;
1133 BYTE *src = srcdata, *dst = pbBuffer;
1135 for (y = 0; y < prc->Height; y++)
1137 float *gray_float = (float *)src;
1138 BYTE *bgr = dst;
1140 for (x = 0; x < prc->Width; x++)
1142 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1143 *bgr++ = gray;
1144 *bgr++ = gray;
1145 *bgr++ = gray;
1147 src += srcstride;
1148 dst += cbStride;
1152 HeapFree(GetProcessHeap(), 0, srcdata);
1154 return hr;
1156 return S_OK;
1158 case format_32bppCMYK:
1159 if (prc)
1161 BYTE *srcdata;
1162 UINT srcstride, srcdatasize;
1164 srcstride = 4 * prc->Width;
1165 srcdatasize = srcstride * prc->Height;
1167 srcdata = heap_alloc(srcdatasize);
1168 if (!srcdata) return E_OUTOFMEMORY;
1170 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1171 if (SUCCEEDED(hr))
1173 INT x, y;
1174 BYTE *src = srcdata, *dst = pbBuffer;
1176 for (y = 0; y < prc->Height; y++)
1178 BYTE *cmyk = src;
1179 BYTE *bgr = dst;
1181 for (x = 0; x < prc->Width; x++)
1183 BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
1184 bgr[0] = (255 - y) * (255 - k) / 255; /* B */
1185 bgr[1] = (255 - m) * (255 - k) / 255; /* G */
1186 bgr[2] = (255 - c) * (255 - k) / 255; /* R */
1187 cmyk += 4;
1188 bgr += 3;
1190 src += srcstride;
1191 dst += cbStride;
1195 heap_free(srcdata);
1196 return hr;
1198 return S_OK;
1200 default:
1201 FIXME("Unimplemented conversion path!\n");
1202 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1206 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1207 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1209 HRESULT hr;
1211 switch (source_format)
1213 case format_24bppBGR:
1214 case format_24bppRGB:
1215 if (prc)
1217 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1218 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1219 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1220 return hr;
1222 return S_OK;
1223 case format_32bppBGR:
1224 case format_32bppBGRA:
1225 case format_32bppPBGRA:
1226 if (prc)
1228 HRESULT res;
1229 INT x, y;
1230 BYTE *srcdata;
1231 UINT srcstride, srcdatasize;
1232 const BYTE *srcrow;
1233 const BYTE *srcpixel;
1234 BYTE *dstrow;
1235 BYTE *dstpixel;
1236 BYTE tmppixel[3];
1238 srcstride = 4 * prc->Width;
1239 srcdatasize = srcstride * prc->Height;
1241 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1242 if (!srcdata) return E_OUTOFMEMORY;
1244 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1246 if (SUCCEEDED(res))
1248 srcrow = srcdata;
1249 dstrow = pbBuffer;
1250 for (y=0; y<prc->Height; y++) {
1251 srcpixel=srcrow;
1252 dstpixel=dstrow;
1253 for (x=0; x<prc->Width; x++) {
1254 tmppixel[0]=*srcpixel++; /* blue */
1255 tmppixel[1]=*srcpixel++; /* green */
1256 tmppixel[2]=*srcpixel++; /* red */
1257 srcpixel++; /* alpha */
1259 *dstpixel++=tmppixel[2]; /* red */
1260 *dstpixel++=tmppixel[1]; /* green */
1261 *dstpixel++=tmppixel[0]; /* blue */
1263 srcrow += srcstride;
1264 dstrow += cbStride;
1268 HeapFree(GetProcessHeap(), 0, srcdata);
1270 return res;
1272 return S_OK;
1273 default:
1274 FIXME("Unimplemented conversion path!\n");
1275 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1279 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1280 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1282 HRESULT hr;
1284 switch (source_format)
1286 case format_32bppBGR:
1287 case format_32bppBGRA:
1288 case format_32bppPBGRA:
1289 case format_32bppGrayFloat:
1290 if (prc)
1292 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1293 break;
1295 return S_OK;
1297 default:
1298 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1299 break;
1302 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1304 INT x, y;
1305 BYTE *p = pbBuffer;
1307 for (y = 0; y < prc->Height; y++)
1309 BYTE *bgr = p;
1310 for (x = 0; x < prc->Width; x++)
1312 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1313 *(float *)bgr = gray;
1314 bgr += 4;
1316 p += cbStride;
1319 return hr;
1322 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1323 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1325 HRESULT hr;
1326 BYTE *srcdata;
1327 UINT srcstride, srcdatasize;
1329 if (source_format == format_8bppGray)
1331 if (prc)
1332 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1334 return S_OK;
1337 if (source_format == format_32bppGrayFloat)
1339 hr = S_OK;
1341 if (prc)
1343 srcstride = 4 * prc->Width;
1344 srcdatasize = srcstride * prc->Height;
1346 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1347 if (!srcdata) return E_OUTOFMEMORY;
1349 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1350 if (SUCCEEDED(hr))
1352 INT x, y;
1353 BYTE *src = srcdata, *dst = pbBuffer;
1355 for (y=0; y < prc->Height; y++)
1357 float *srcpixel = (float*)src;
1358 BYTE *dstpixel = dst;
1360 for (x=0; x < prc->Width; x++)
1361 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1363 src += srcstride;
1364 dst += cbStride;
1368 HeapFree(GetProcessHeap(), 0, srcdata);
1371 return hr;
1374 if (!prc)
1375 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1377 srcstride = 3 * prc->Width;
1378 srcdatasize = srcstride * prc->Height;
1380 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1381 if (!srcdata) return E_OUTOFMEMORY;
1383 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1384 if (SUCCEEDED(hr))
1386 INT x, y;
1387 BYTE *src = srcdata, *dst = pbBuffer;
1389 for (y = 0; y < prc->Height; y++)
1391 BYTE *bgr = src;
1393 for (x = 0; x < prc->Width; x++)
1395 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1397 gray = to_sRGB_component(gray) * 255.0f;
1398 dst[x] = (BYTE)floorf(gray + 0.51f);
1399 bgr += 3;
1401 src += srcstride;
1402 dst += cbStride;
1406 HeapFree(GetProcessHeap(), 0, srcdata);
1407 return hr;
1410 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1412 UINT best_diff, best_index, i;
1414 best_diff = ~0;
1415 best_index = 0;
1417 for (i = 0; i < count; i++)
1419 BYTE pal_r, pal_g, pal_b;
1420 UINT diff_r, diff_g, diff_b, diff;
1422 pal_r = colors[i] >> 16;
1423 pal_g = colors[i] >> 8;
1424 pal_b = colors[i];
1426 diff_r = bgr[2] - pal_r;
1427 diff_g = bgr[1] - pal_g;
1428 diff_b = bgr[0] - pal_b;
1430 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1431 if (diff == 0) return i;
1433 if (diff < best_diff)
1435 best_diff = diff;
1436 best_index = i;
1440 return best_index;
1443 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1444 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1446 HRESULT hr;
1447 BYTE *srcdata;
1448 WICColor colors[256];
1449 UINT srcstride, srcdatasize, count;
1451 if (source_format == format_8bppIndexed)
1453 if (prc)
1454 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1456 return S_OK;
1459 if (!prc)
1460 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1462 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1464 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1465 if (hr != S_OK) return hr;
1467 srcstride = 3 * prc->Width;
1468 srcdatasize = srcstride * prc->Height;
1470 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1471 if (!srcdata) return E_OUTOFMEMORY;
1473 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1474 if (SUCCEEDED(hr))
1476 INT x, y;
1477 BYTE *src = srcdata, *dst = pbBuffer;
1479 for (y = 0; y < prc->Height; y++)
1481 BYTE *bgr = src;
1483 for (x = 0; x < prc->Width; x++)
1485 dst[x] = rgb_to_palette_index(bgr, colors, count);
1486 bgr += 3;
1488 src += srcstride;
1489 dst += cbStride;
1493 HeapFree(GetProcessHeap(), 0, srcdata);
1494 return hr;
1497 static const struct pixelformatinfo supported_formats[] = {
1498 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1499 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1500 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1501 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1502 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1503 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1504 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1505 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1506 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1507 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1508 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1509 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1510 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1511 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1512 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1513 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1514 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1515 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1516 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1517 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1518 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1519 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1520 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1521 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1525 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1527 UINT i;
1529 for (i=0; supported_formats[i].guid; i++)
1530 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1532 return NULL;
1535 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1536 void **ppv)
1538 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1539 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1541 if (!ppv) return E_INVALIDARG;
1543 if (IsEqualIID(&IID_IUnknown, iid) ||
1544 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1545 IsEqualIID(&IID_IWICFormatConverter, iid))
1547 *ppv = &This->IWICFormatConverter_iface;
1549 else
1551 *ppv = NULL;
1552 return E_NOINTERFACE;
1555 IUnknown_AddRef((IUnknown*)*ppv);
1556 return S_OK;
1559 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1561 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1562 ULONG ref = InterlockedIncrement(&This->ref);
1564 TRACE("(%p) refcount=%u\n", iface, ref);
1566 return ref;
1569 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1571 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1572 ULONG ref = InterlockedDecrement(&This->ref);
1574 TRACE("(%p) refcount=%u\n", iface, ref);
1576 if (ref == 0)
1578 This->lock.DebugInfo->Spare[0] = 0;
1579 DeleteCriticalSection(&This->lock);
1580 if (This->source) IWICBitmapSource_Release(This->source);
1581 if (This->palette) IWICPalette_Release(This->palette);
1582 HeapFree(GetProcessHeap(), 0, This);
1585 return ref;
1588 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1589 UINT *puiWidth, UINT *puiHeight)
1591 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1593 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1595 if (This->source)
1596 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1597 else
1598 return WINCODEC_ERR_NOTINITIALIZED;
1601 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1602 WICPixelFormatGUID *pPixelFormat)
1604 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1606 TRACE("(%p,%p)\n", iface, pPixelFormat);
1608 if (This->source)
1609 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1610 else
1611 return WINCODEC_ERR_NOTINITIALIZED;
1613 return S_OK;
1616 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1617 double *pDpiX, double *pDpiY)
1619 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1621 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1623 if (This->source)
1624 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1625 else
1626 return WINCODEC_ERR_NOTINITIALIZED;
1629 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1630 IWICPalette *palette)
1632 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1634 TRACE("(%p,%p)\n", iface, palette);
1636 if (!palette) return E_INVALIDARG;
1637 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1639 if (!This->palette)
1641 HRESULT hr;
1642 UINT bpp;
1644 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1645 if (hr != S_OK) return hr;
1646 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1647 return IWICBitmapSource_CopyPalette(This->source, palette);
1650 return IWICPalette_InitializeFromPalette(palette, This->palette);
1653 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1654 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1656 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1657 WICRect rc;
1658 HRESULT hr;
1659 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1661 if (This->source)
1663 if (!prc)
1665 UINT width, height;
1666 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1667 if (FAILED(hr)) return hr;
1668 rc.X = 0;
1669 rc.Y = 0;
1670 rc.Width = width;
1671 rc.Height = height;
1672 prc = &rc;
1675 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1676 pbBuffer, This->src_format->format);
1678 else
1679 return WINCODEC_ERR_WRONGSTATE;
1682 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1683 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1684 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1686 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1687 const struct pixelformatinfo *srcinfo, *dstinfo;
1688 GUID srcFormat;
1689 HRESULT res;
1691 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1692 dither, palette, alpha_threshold, palette_type);
1694 if (!palette)
1696 UINT bpp;
1697 res = get_pixelformat_bpp(dstFormat, &bpp);
1698 if (res != S_OK) return res;
1700 res = PaletteImpl_Create(&palette);
1701 if (res != S_OK) return res;
1703 switch (palette_type)
1705 case WICBitmapPaletteTypeCustom:
1706 IWICPalette_Release(palette);
1707 palette = NULL;
1708 if (bpp <= 8) return E_INVALIDARG;
1709 break;
1711 case WICBitmapPaletteTypeMedianCut:
1713 if (bpp <= 8)
1714 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1715 break;
1718 default:
1719 if (bpp <= 8)
1720 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1721 break;
1724 if (res != S_OK)
1726 IWICPalette_Release(palette);
1727 return res;
1730 else
1731 IWICPalette_AddRef(palette);
1733 EnterCriticalSection(&This->lock);
1735 if (This->source)
1737 res = WINCODEC_ERR_WRONGSTATE;
1738 goto end;
1741 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1742 if (FAILED(res)) goto end;
1744 srcinfo = get_formatinfo(&srcFormat);
1745 if (!srcinfo)
1747 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1748 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1749 goto end;
1752 dstinfo = get_formatinfo(dstFormat);
1753 if (!dstinfo)
1755 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1756 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1757 goto end;
1760 if (dstinfo->copy_function)
1762 IWICBitmapSource_AddRef(source);
1763 This->src_format = srcinfo;
1764 This->dst_format = dstinfo;
1765 This->dither = dither;
1766 This->alpha_threshold = alpha_threshold;
1767 This->palette = palette;
1768 This->source = source;
1770 else
1772 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1773 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1776 end:
1778 LeaveCriticalSection(&This->lock);
1780 if (res != S_OK && palette)
1781 IWICPalette_Release(palette);
1783 return res;
1786 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1787 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1788 BOOL *pfCanConvert)
1790 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1791 const struct pixelformatinfo *srcinfo, *dstinfo;
1793 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1794 debugstr_guid(dstPixelFormat), pfCanConvert);
1796 srcinfo = get_formatinfo(srcPixelFormat);
1797 if (!srcinfo)
1799 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1800 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1803 dstinfo = get_formatinfo(dstPixelFormat);
1804 if (!dstinfo)
1806 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1807 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1810 if (dstinfo->copy_function &&
1811 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1812 *pfCanConvert = TRUE;
1813 else
1815 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1816 *pfCanConvert = FALSE;
1819 return S_OK;
1822 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1823 FormatConverter_QueryInterface,
1824 FormatConverter_AddRef,
1825 FormatConverter_Release,
1826 FormatConverter_GetSize,
1827 FormatConverter_GetPixelFormat,
1828 FormatConverter_GetResolution,
1829 FormatConverter_CopyPalette,
1830 FormatConverter_CopyPixels,
1831 FormatConverter_Initialize,
1832 FormatConverter_CanConvert
1835 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1837 FormatConverter *This;
1838 HRESULT ret;
1840 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1842 *ppv = NULL;
1844 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1845 if (!This) return E_OUTOFMEMORY;
1847 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1848 This->ref = 1;
1849 This->source = NULL;
1850 This->palette = NULL;
1851 InitializeCriticalSection(&This->lock);
1852 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1854 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1855 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1857 return ret;