[PSDK] Update wincodecsdk.idl. CORE-13362
[reactos.git] / reactos / dll / win32 / windowscodecs / converter.c
1 /*
2 * Copyright 2009 Vincent Povirk
3 * Copyright 2016 Dmitry Timoshkov
4 *
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.
9 *
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.
14 *
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
18 */
19
20 #include "wincodecs_private.h"
21
22 #include <math.h>
23
24 struct FormatConverter;
25
26 enum pixelformat {
27 format_1bppIndexed,
28 format_2bppIndexed,
29 format_4bppIndexed,
30 format_8bppIndexed,
31 format_BlackWhite,
32 format_2bppGray,
33 format_4bppGray,
34 format_8bppGray,
35 format_16bppGray,
36 format_16bppBGR555,
37 format_16bppBGR565,
38 format_16bppBGRA5551,
39 format_24bppBGR,
40 format_24bppRGB,
41 format_32bppGrayFloat,
42 format_32bppBGR,
43 format_32bppRGB,
44 format_32bppBGRA,
45 format_32bppRGBA,
46 format_32bppPBGRA,
47 format_32bppPRGBA,
48 format_48bppRGB,
49 format_64bppRGBA,
50 format_32bppCMYK,
51 };
52
53 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
54 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
55
56 struct pixelformatinfo {
57 enum pixelformat format;
58 const WICPixelFormatGUID *guid;
59 copyfunc copy_function;
60 };
61
62 typedef struct FormatConverter {
63 IWICFormatConverter IWICFormatConverter_iface;
64 LONG ref;
65 IWICBitmapSource *source;
66 const struct pixelformatinfo *dst_format, *src_format;
67 WICBitmapDitherType dither;
68 double alpha_threshold;
69 IWICPalette *palette;
70 CRITICAL_SECTION lock; /* must be held when initialized */
71 } FormatConverter;
72
73 /* https://www.w3.org/Graphics/Color/srgb */
74 static inline float from_sRGB_component(float f)
75 {
76 if (f <= 0.04045f) return f / 12.92f;
77 return powf((f + 0.055f) / 1.055f, 2.4f);
78 }
79
80 static inline float to_sRGB_component(float f)
81 {
82 if (f <= 0.0031308f) return 12.92f * f;
83 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f;
84 }
85
86 #if 0 /* FIXME: enable once needed */
87 static void from_sRGB(BYTE *bgr)
88 {
89 float r, g, b;
90
91 r = bgr[2] / 255.0f;
92 g = bgr[1] / 255.0f;
93 b = bgr[0] / 255.0f;
94
95 r = from_sRGB_component(r);
96 g = from_sRGB_component(g);
97 b = from_sRGB_component(b);
98
99 bgr[2] = (BYTE)(r * 255.0f);
100 bgr[1] = (BYTE)(g * 255.0f);
101 bgr[0] = (BYTE)(b * 255.0f);
102 }
103
104 static void to_sRGB(BYTE *bgr)
105 {
106 float r, g, b;
107
108 r = bgr[2] / 255.0f;
109 g = bgr[1] / 255.0f;
110 b = bgr[0] / 255.0f;
111
112 r = to_sRGB_component(r);
113 g = to_sRGB_component(g);
114 b = to_sRGB_component(b);
115
116 bgr[2] = (BYTE)(r * 255.0f);
117 bgr[1] = (BYTE)(g * 255.0f);
118 bgr[0] = (BYTE)(b * 255.0f);
119 }
120 #endif
121
122 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
123 {
124 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
125 }
126
127 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
128 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
129 {
130 switch (source_format)
131 {
132 case format_1bppIndexed:
133 case format_BlackWhite:
134 if (prc)
135 {
136 HRESULT res;
137 INT x, y;
138 BYTE *srcdata;
139 UINT srcstride, srcdatasize;
140 const BYTE *srcrow;
141 const BYTE *srcbyte;
142 BYTE *dstrow;
143 DWORD *dstpixel;
144 WICColor colors[2];
145 IWICPalette *palette;
146 UINT actualcolors;
147
148 res = PaletteImpl_Create(&palette);
149 if (FAILED(res)) return res;
150
151 if (source_format == format_1bppIndexed)
152 res = IWICBitmapSource_CopyPalette(This->source, palette);
153 else
154 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
155
156 if (SUCCEEDED(res))
157 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
158
159 IWICPalette_Release(palette);
160 if (FAILED(res)) return res;
161
162 srcstride = (prc->Width+7)/8;
163 srcdatasize = srcstride * prc->Height;
164
165 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
166 if (!srcdata) return E_OUTOFMEMORY;
167
168 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
169
170 if (SUCCEEDED(res))
171 {
172 srcrow = srcdata;
173 dstrow = pbBuffer;
174 for (y=0; y<prc->Height; y++) {
175 srcbyte = srcrow;
176 dstpixel=(DWORD*)dstrow;
177 for (x=0; x<prc->Width; x+=8) {
178 BYTE srcval;
179 srcval=*srcbyte++;
180 *dstpixel++ = colors[srcval>>7&1];
181 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
182 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
183 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
184 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
185 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
186 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
187 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
188 }
189 srcrow += srcstride;
190 dstrow += cbStride;
191 }
192 }
193
194 HeapFree(GetProcessHeap(), 0, srcdata);
195
196 return res;
197 }
198 return S_OK;
199 case format_2bppIndexed:
200 case format_2bppGray:
201 if (prc)
202 {
203 HRESULT res;
204 INT x, y;
205 BYTE *srcdata;
206 UINT srcstride, srcdatasize;
207 const BYTE *srcrow;
208 const BYTE *srcbyte;
209 BYTE *dstrow;
210 DWORD *dstpixel;
211 WICColor colors[4];
212 IWICPalette *palette;
213 UINT actualcolors;
214
215 res = PaletteImpl_Create(&palette);
216 if (FAILED(res)) return res;
217
218 if (source_format == format_2bppIndexed)
219 res = IWICBitmapSource_CopyPalette(This->source, palette);
220 else
221 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
222
223 if (SUCCEEDED(res))
224 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
225
226 IWICPalette_Release(palette);
227 if (FAILED(res)) return res;
228
229 srcstride = (prc->Width+3)/4;
230 srcdatasize = srcstride * prc->Height;
231
232 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
233 if (!srcdata) return E_OUTOFMEMORY;
234
235 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
236
237 if (SUCCEEDED(res))
238 {
239 srcrow = srcdata;
240 dstrow = pbBuffer;
241 for (y=0; y<prc->Height; y++) {
242 srcbyte = srcrow;
243 dstpixel=(DWORD*)dstrow;
244 for (x=0; x<prc->Width; x+=4) {
245 BYTE srcval;
246 srcval=*srcbyte++;
247 *dstpixel++ = colors[srcval>>6];
248 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
249 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
250 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3];
251 }
252 srcrow += srcstride;
253 dstrow += cbStride;
254 }
255 }
256
257 HeapFree(GetProcessHeap(), 0, srcdata);
258
259 return res;
260 }
261 return S_OK;
262 case format_4bppIndexed:
263 case format_4bppGray:
264 if (prc)
265 {
266 HRESULT res;
267 INT x, y;
268 BYTE *srcdata;
269 UINT srcstride, srcdatasize;
270 const BYTE *srcrow;
271 const BYTE *srcbyte;
272 BYTE *dstrow;
273 DWORD *dstpixel;
274 WICColor colors[16];
275 IWICPalette *palette;
276 UINT actualcolors;
277
278 res = PaletteImpl_Create(&palette);
279 if (FAILED(res)) return res;
280
281 if (source_format == format_4bppIndexed)
282 res = IWICBitmapSource_CopyPalette(This->source, palette);
283 else
284 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
285
286 if (SUCCEEDED(res))
287 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
288
289 IWICPalette_Release(palette);
290 if (FAILED(res)) return res;
291
292 srcstride = (prc->Width+1)/2;
293 srcdatasize = srcstride * prc->Height;
294
295 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
296 if (!srcdata) return E_OUTOFMEMORY;
297
298 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
299
300 if (SUCCEEDED(res))
301 {
302 srcrow = srcdata;
303 dstrow = pbBuffer;
304 for (y=0; y<prc->Height; y++) {
305 srcbyte = srcrow;
306 dstpixel=(DWORD*)dstrow;
307 for (x=0; x<prc->Width; x+=2) {
308 BYTE srcval;
309 srcval=*srcbyte++;
310 *dstpixel++ = colors[srcval>>4];
311 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
312 }
313 srcrow += srcstride;
314 dstrow += cbStride;
315 }
316 }
317
318 HeapFree(GetProcessHeap(), 0, srcdata);
319
320 return res;
321 }
322 return S_OK;
323 case format_8bppGray:
324 if (prc)
325 {
326 HRESULT res;
327 INT x, y;
328 BYTE *srcdata;
329 UINT srcstride, srcdatasize;
330 const BYTE *srcrow;
331 const BYTE *srcbyte;
332 BYTE *dstrow;
333 DWORD *dstpixel;
334
335 srcstride = prc->Width;
336 srcdatasize = srcstride * prc->Height;
337
338 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
339 if (!srcdata) return E_OUTOFMEMORY;
340
341 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
342
343 if (SUCCEEDED(res))
344 {
345 srcrow = srcdata;
346 dstrow = pbBuffer;
347 for (y=0; y<prc->Height; y++) {
348 srcbyte = srcrow;
349 dstpixel=(DWORD*)dstrow;
350 for (x=0; x<prc->Width; x++)
351 {
352 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
353 srcbyte++;
354 }
355 srcrow += srcstride;
356 dstrow += cbStride;
357 }
358 }
359
360 HeapFree(GetProcessHeap(), 0, srcdata);
361
362 return res;
363 }
364 return S_OK;
365 case format_8bppIndexed:
366 if (prc)
367 {
368 HRESULT res;
369 INT x, y;
370 BYTE *srcdata;
371 UINT srcstride, srcdatasize;
372 const BYTE *srcrow;
373 const BYTE *srcbyte;
374 BYTE *dstrow;
375 DWORD *dstpixel;
376 WICColor colors[256];
377 IWICPalette *palette;
378 UINT actualcolors;
379
380 res = PaletteImpl_Create(&palette);
381 if (FAILED(res)) return res;
382
383 res = IWICBitmapSource_CopyPalette(This->source, palette);
384 if (SUCCEEDED(res))
385 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
386
387 IWICPalette_Release(palette);
388
389 if (FAILED(res)) return res;
390
391 srcstride = prc->Width;
392 srcdatasize = srcstride * prc->Height;
393
394 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
395 if (!srcdata) return E_OUTOFMEMORY;
396
397 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
398
399 if (SUCCEEDED(res))
400 {
401 srcrow = srcdata;
402 dstrow = pbBuffer;
403 for (y=0; y<prc->Height; y++) {
404 srcbyte = srcrow;
405 dstpixel=(DWORD*)dstrow;
406 for (x=0; x<prc->Width; x++)
407 *dstpixel++ = colors[*srcbyte++];
408 srcrow += srcstride;
409 dstrow += cbStride;
410 }
411 }
412
413 HeapFree(GetProcessHeap(), 0, srcdata);
414
415 return res;
416 }
417 return S_OK;
418 case format_16bppGray:
419 if (prc)
420 {
421 HRESULT res;
422 INT x, y;
423 BYTE *srcdata;
424 UINT srcstride, srcdatasize;
425 const BYTE *srcrow;
426 const BYTE *srcbyte;
427 BYTE *dstrow;
428 DWORD *dstpixel;
429
430 srcstride = prc->Width * 2;
431 srcdatasize = srcstride * prc->Height;
432
433 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
434 if (!srcdata) return E_OUTOFMEMORY;
435
436 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
437
438 if (SUCCEEDED(res))
439 {
440 srcrow = srcdata;
441 dstrow = pbBuffer;
442 for (y=0; y<prc->Height; y++) {
443 srcbyte = srcrow;
444 dstpixel=(DWORD*)dstrow;
445 for (x=0; x<prc->Width; x++)
446 {
447 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
448 srcbyte+=2;
449 }
450 srcrow += srcstride;
451 dstrow += cbStride;
452 }
453 }
454
455 HeapFree(GetProcessHeap(), 0, srcdata);
456
457 return res;
458 }
459 return S_OK;
460 case format_16bppBGR555:
461 if (prc)
462 {
463 HRESULT res;
464 INT x, y;
465 BYTE *srcdata;
466 UINT srcstride, srcdatasize;
467 const BYTE *srcrow;
468 const WORD *srcpixel;
469 BYTE *dstrow;
470 DWORD *dstpixel;
471
472 srcstride = 2 * prc->Width;
473 srcdatasize = srcstride * prc->Height;
474
475 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
476 if (!srcdata) return E_OUTOFMEMORY;
477
478 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
479
480 if (SUCCEEDED(res))
481 {
482 srcrow = srcdata;
483 dstrow = pbBuffer;
484 for (y=0; y<prc->Height; y++) {
485 srcpixel=(const WORD*)srcrow;
486 dstpixel=(DWORD*)dstrow;
487 for (x=0; x<prc->Width; x++) {
488 WORD srcval;
489 srcval=*srcpixel++;
490 *dstpixel++=0xff000000 | /* constant 255 alpha */
491 ((srcval << 9) & 0xf80000) | /* r */
492 ((srcval << 4) & 0x070000) | /* r - 3 bits */
493 ((srcval << 6) & 0x00f800) | /* g */
494 ((srcval << 1) & 0x000700) | /* g - 3 bits */
495 ((srcval << 3) & 0x0000f8) | /* b */
496 ((srcval >> 2) & 0x000007); /* b - 3 bits */
497 }
498 srcrow += srcstride;
499 dstrow += cbStride;
500 }
501 }
502
503 HeapFree(GetProcessHeap(), 0, srcdata);
504
505 return res;
506 }
507 return S_OK;
508 case format_16bppBGR565:
509 if (prc)
510 {
511 HRESULT res;
512 INT x, y;
513 BYTE *srcdata;
514 UINT srcstride, srcdatasize;
515 const BYTE *srcrow;
516 const WORD *srcpixel;
517 BYTE *dstrow;
518 DWORD *dstpixel;
519
520 srcstride = 2 * prc->Width;
521 srcdatasize = srcstride * prc->Height;
522
523 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
524 if (!srcdata) return E_OUTOFMEMORY;
525
526 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
527
528 if (SUCCEEDED(res))
529 {
530 srcrow = srcdata;
531 dstrow = pbBuffer;
532 for (y=0; y<prc->Height; y++) {
533 srcpixel=(const WORD*)srcrow;
534 dstpixel=(DWORD*)dstrow;
535 for (x=0; x<prc->Width; x++) {
536 WORD srcval;
537 srcval=*srcpixel++;
538 *dstpixel++=0xff000000 | /* constant 255 alpha */
539 ((srcval << 8) & 0xf80000) | /* r */
540 ((srcval << 3) & 0x070000) | /* r - 3 bits */
541 ((srcval << 5) & 0x00fc00) | /* g */
542 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
543 ((srcval << 3) & 0x0000f8) | /* b */
544 ((srcval >> 2) & 0x000007); /* b - 3 bits */
545 }
546 srcrow += srcstride;
547 dstrow += cbStride;
548 }
549 }
550
551 HeapFree(GetProcessHeap(), 0, srcdata);
552
553 return res;
554 }
555 return S_OK;
556 case format_16bppBGRA5551:
557 if (prc)
558 {
559 HRESULT res;
560 INT x, y;
561 BYTE *srcdata;
562 UINT srcstride, srcdatasize;
563 const BYTE *srcrow;
564 const WORD *srcpixel;
565 BYTE *dstrow;
566 DWORD *dstpixel;
567
568 srcstride = 2 * prc->Width;
569 srcdatasize = srcstride * prc->Height;
570
571 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
572 if (!srcdata) return E_OUTOFMEMORY;
573
574 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
575
576 if (SUCCEEDED(res))
577 {
578 srcrow = srcdata;
579 dstrow = pbBuffer;
580 for (y=0; y<prc->Height; y++) {
581 srcpixel=(const WORD*)srcrow;
582 dstpixel=(DWORD*)dstrow;
583 for (x=0; x<prc->Width; x++) {
584 WORD srcval;
585 srcval=*srcpixel++;
586 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
587 ((srcval << 9) & 0xf80000) | /* r */
588 ((srcval << 4) & 0x070000) | /* r - 3 bits */
589 ((srcval << 6) & 0x00f800) | /* g */
590 ((srcval << 1) & 0x000700) | /* g - 3 bits */
591 ((srcval << 3) & 0x0000f8) | /* b */
592 ((srcval >> 2) & 0x000007); /* b - 3 bits */
593 }
594 srcrow += srcstride;
595 dstrow += cbStride;
596 }
597 }
598
599 HeapFree(GetProcessHeap(), 0, srcdata);
600
601 return res;
602 }
603 return S_OK;
604 case format_24bppBGR:
605 if (prc)
606 {
607 HRESULT res;
608 INT x, y;
609 BYTE *srcdata;
610 UINT srcstride, srcdatasize;
611 const BYTE *srcrow;
612 const BYTE *srcpixel;
613 BYTE *dstrow;
614 BYTE *dstpixel;
615
616 srcstride = 3 * prc->Width;
617 srcdatasize = srcstride * prc->Height;
618
619 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
620 if (!srcdata) return E_OUTOFMEMORY;
621
622 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
623
624 if (SUCCEEDED(res))
625 {
626 srcrow = srcdata;
627 dstrow = pbBuffer;
628 for (y=0; y<prc->Height; y++) {
629 srcpixel=srcrow;
630 dstpixel=dstrow;
631 for (x=0; x<prc->Width; x++) {
632 *dstpixel++=*srcpixel++; /* blue */
633 *dstpixel++=*srcpixel++; /* green */
634 *dstpixel++=*srcpixel++; /* red */
635 *dstpixel++=255; /* alpha */
636 }
637 srcrow += srcstride;
638 dstrow += cbStride;
639 }
640 }
641
642 HeapFree(GetProcessHeap(), 0, srcdata);
643
644 return res;
645 }
646 return S_OK;
647 case format_24bppRGB:
648 if (prc)
649 {
650 HRESULT res;
651 INT x, y;
652 BYTE *srcdata;
653 UINT srcstride, srcdatasize;
654 const BYTE *srcrow;
655 const BYTE *srcpixel;
656 BYTE *dstrow;
657 BYTE *dstpixel;
658 BYTE tmppixel[3];
659
660 srcstride = 3 * prc->Width;
661 srcdatasize = srcstride * prc->Height;
662
663 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
664 if (!srcdata) return E_OUTOFMEMORY;
665
666 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
667
668 if (SUCCEEDED(res))
669 {
670 srcrow = srcdata;
671 dstrow = pbBuffer;
672 for (y=0; y<prc->Height; y++) {
673 srcpixel=srcrow;
674 dstpixel=dstrow;
675 for (x=0; x<prc->Width; x++) {
676 tmppixel[0]=*srcpixel++; /* red */
677 tmppixel[1]=*srcpixel++; /* green */
678 tmppixel[2]=*srcpixel++; /* blue */
679
680 *dstpixel++=tmppixel[2]; /* blue */
681 *dstpixel++=tmppixel[1]; /* green */
682 *dstpixel++=tmppixel[0]; /* red */
683 *dstpixel++=255; /* alpha */
684 }
685 srcrow += srcstride;
686 dstrow += cbStride;
687 }
688 }
689
690 HeapFree(GetProcessHeap(), 0, srcdata);
691
692 return res;
693 }
694 return S_OK;
695 case format_32bppBGR:
696 if (prc)
697 {
698 HRESULT res;
699 INT x, y;
700
701 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
702 if (FAILED(res)) return res;
703
704 /* set all alpha values to 255 */
705 for (y=0; y<prc->Height; y++)
706 for (x=0; x<prc->Width; x++)
707 pbBuffer[cbStride*y+4*x+3] = 0xff;
708 }
709 return S_OK;
710 case format_32bppBGRA:
711 if (prc)
712 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
713 return S_OK;
714 case format_32bppPBGRA:
715 if (prc)
716 {
717 HRESULT res;
718 INT x, y;
719
720 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
721 if (FAILED(res)) return res;
722
723 for (y=0; y<prc->Height; y++)
724 for (x=0; x<prc->Width; x++)
725 {
726 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
727 if (alpha != 0 && alpha != 255)
728 {
729 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
730 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
731 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
732 }
733 }
734 }
735 return S_OK;
736 case format_48bppRGB:
737 if (prc)
738 {
739 HRESULT res;
740 INT x, y;
741 BYTE *srcdata;
742 UINT srcstride, srcdatasize;
743 const BYTE *srcrow;
744 const BYTE *srcpixel;
745 BYTE *dstrow;
746 DWORD *dstpixel;
747
748 srcstride = 6 * prc->Width;
749 srcdatasize = srcstride * prc->Height;
750
751 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
752 if (!srcdata) return E_OUTOFMEMORY;
753
754 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
755
756 if (SUCCEEDED(res))
757 {
758 srcrow = srcdata;
759 dstrow = pbBuffer;
760 for (y=0; y<prc->Height; y++) {
761 srcpixel=srcrow;
762 dstpixel=(DWORD*)dstrow;
763 for (x=0; x<prc->Width; x++) {
764 BYTE red, green, blue;
765 red = *srcpixel++; srcpixel++;
766 green = *srcpixel++; srcpixel++;
767 blue = *srcpixel++; srcpixel++;
768 *dstpixel++=0xff000000|red<<16|green<<8|blue;
769 }
770 srcrow += srcstride;
771 dstrow += cbStride;
772 }
773 }
774
775 HeapFree(GetProcessHeap(), 0, srcdata);
776
777 return res;
778 }
779 return S_OK;
780 case format_64bppRGBA:
781 if (prc)
782 {
783 HRESULT res;
784 INT x, y;
785 BYTE *srcdata;
786 UINT srcstride, srcdatasize;
787 const BYTE *srcrow;
788 const BYTE *srcpixel;
789 BYTE *dstrow;
790 DWORD *dstpixel;
791
792 srcstride = 8 * prc->Width;
793 srcdatasize = srcstride * prc->Height;
794
795 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
796 if (!srcdata) return E_OUTOFMEMORY;
797
798 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
799
800 if (SUCCEEDED(res))
801 {
802 srcrow = srcdata;
803 dstrow = pbBuffer;
804 for (y=0; y<prc->Height; y++) {
805 srcpixel=srcrow;
806 dstpixel=(DWORD*)dstrow;
807 for (x=0; x<prc->Width; x++) {
808 BYTE red, green, blue, alpha;
809 red = *srcpixel++; srcpixel++;
810 green = *srcpixel++; srcpixel++;
811 blue = *srcpixel++; srcpixel++;
812 alpha = *srcpixel++; srcpixel++;
813 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
814 }
815 srcrow += srcstride;
816 dstrow += cbStride;
817 }
818 }
819
820 HeapFree(GetProcessHeap(), 0, srcdata);
821
822 return res;
823 }
824 return S_OK;
825 case format_32bppCMYK:
826 if (prc)
827 {
828 HRESULT res;
829 UINT x, y;
830
831 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
832 if (FAILED(res)) return res;
833
834 for (y=0; y<prc->Height; y++)
835 for (x=0; x<prc->Width; x++)
836 {
837 BYTE *pixel = pbBuffer+cbStride*y+4*x;
838 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
839 pixel[0] = (255-y)*(255-k)/255; /* blue */
840 pixel[1] = (255-m)*(255-k)/255; /* green */
841 pixel[2] = (255-c)*(255-k)/255; /* red */
842 pixel[3] = 255; /* alpha */
843 }
844 }
845 return S_OK;
846 default:
847 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
848 }
849 }
850
851 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
852 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
853 {
854 HRESULT hr;
855
856 switch (source_format)
857 {
858 case format_32bppRGB:
859 case format_32bppRGBA:
860 case format_32bppPRGBA:
861 if (prc)
862 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
863 return S_OK;
864 default:
865 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
866 if (SUCCEEDED(hr) && prc)
867 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
868 return hr;
869 }
870 }
871
872 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
873 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
874 {
875 switch (source_format)
876 {
877 case format_32bppBGR:
878 case format_32bppBGRA:
879 case format_32bppPBGRA:
880 if (prc)
881 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
882 return S_OK;
883 default:
884 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
885 }
886 }
887
888 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
889 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
890 {
891 switch (source_format)
892 {
893 case format_32bppRGB:
894 case format_32bppRGBA:
895 case format_32bppPRGBA:
896 if (prc)
897 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
898 return S_OK;
899 default:
900 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
901 }
902 }
903
904 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
905 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
906 {
907 HRESULT hr;
908
909 switch (source_format)
910 {
911 case format_32bppPBGRA:
912 if (prc)
913 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
914 return S_OK;
915 default:
916 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
917 if (SUCCEEDED(hr) && prc)
918 {
919 INT x, y;
920
921 for (y=0; y<prc->Height; y++)
922 for (x=0; x<prc->Width; x++)
923 {
924 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
925 if (alpha != 255)
926 {
927 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
928 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
929 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
930 }
931 }
932 }
933 return hr;
934 }
935 }
936
937 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
938 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
939 {
940 HRESULT hr;
941
942 switch (source_format)
943 {
944 case format_32bppPRGBA:
945 if (prc)
946 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
947 return S_OK;
948 default:
949 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
950 if (SUCCEEDED(hr) && prc)
951 {
952 INT x, y;
953
954 for (y=0; y<prc->Height; y++)
955 for (x=0; x<prc->Width; x++)
956 {
957 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
958 if (alpha != 255)
959 {
960 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
961 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
962 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
963 }
964 }
965 }
966 return hr;
967 }
968 }
969
970 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
971 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
972 {
973 HRESULT hr;
974
975 switch (source_format)
976 {
977 case format_24bppBGR:
978 case format_24bppRGB:
979 if (prc)
980 {
981 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
982 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
983 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
984 return hr;
985 }
986 return S_OK;
987 case format_32bppBGR:
988 case format_32bppBGRA:
989 case format_32bppPBGRA:
990 if (prc)
991 {
992 HRESULT res;
993 INT x, y;
994 BYTE *srcdata;
995 UINT srcstride, srcdatasize;
996 const BYTE *srcrow;
997 const BYTE *srcpixel;
998 BYTE *dstrow;
999 BYTE *dstpixel;
1000
1001 srcstride = 4 * prc->Width;
1002 srcdatasize = srcstride * prc->Height;
1003
1004 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1005 if (!srcdata) return E_OUTOFMEMORY;
1006
1007 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1008
1009 if (SUCCEEDED(res))
1010 {
1011 srcrow = srcdata;
1012 dstrow = pbBuffer;
1013 for (y=0; y<prc->Height; y++) {
1014 srcpixel=srcrow;
1015 dstpixel=dstrow;
1016 for (x=0; x<prc->Width; x++) {
1017 *dstpixel++=*srcpixel++; /* blue */
1018 *dstpixel++=*srcpixel++; /* green */
1019 *dstpixel++=*srcpixel++; /* red */
1020 srcpixel++; /* alpha */
1021 }
1022 srcrow += srcstride;
1023 dstrow += cbStride;
1024 }
1025 }
1026
1027 HeapFree(GetProcessHeap(), 0, srcdata);
1028
1029 return res;
1030 }
1031 return S_OK;
1032
1033 case format_32bppGrayFloat:
1034 if (prc)
1035 {
1036 BYTE *srcdata;
1037 UINT srcstride, srcdatasize;
1038
1039 srcstride = 4 * prc->Width;
1040 srcdatasize = srcstride * prc->Height;
1041
1042 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1043 if (!srcdata) return E_OUTOFMEMORY;
1044
1045 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1046
1047 if (SUCCEEDED(hr))
1048 {
1049 INT x, y;
1050 BYTE *src = srcdata, *dst = pbBuffer;
1051
1052 for (y = 0; y < prc->Height; y++)
1053 {
1054 float *gray_float = (float *)src;
1055 BYTE *bgr = dst;
1056
1057 for (x = 0; x < prc->Width; x++)
1058 {
1059 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1060 *bgr++ = gray;
1061 *bgr++ = gray;
1062 *bgr++ = gray;
1063 }
1064 src += srcstride;
1065 dst += cbStride;
1066 }
1067 }
1068
1069 HeapFree(GetProcessHeap(), 0, srcdata);
1070
1071 return hr;
1072 }
1073 return S_OK;
1074
1075 default:
1076 FIXME("Unimplemented conversion path!\n");
1077 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1078 }
1079 }
1080
1081 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1082 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1083 {
1084 HRESULT hr;
1085
1086 switch (source_format)
1087 {
1088 case format_24bppBGR:
1089 case format_24bppRGB:
1090 if (prc)
1091 {
1092 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1093 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1094 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1095 return hr;
1096 }
1097 return S_OK;
1098 case format_32bppBGR:
1099 case format_32bppBGRA:
1100 case format_32bppPBGRA:
1101 if (prc)
1102 {
1103 HRESULT res;
1104 INT x, y;
1105 BYTE *srcdata;
1106 UINT srcstride, srcdatasize;
1107 const BYTE *srcrow;
1108 const BYTE *srcpixel;
1109 BYTE *dstrow;
1110 BYTE *dstpixel;
1111 BYTE tmppixel[3];
1112
1113 srcstride = 4 * prc->Width;
1114 srcdatasize = srcstride * prc->Height;
1115
1116 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1117 if (!srcdata) return E_OUTOFMEMORY;
1118
1119 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1120
1121 if (SUCCEEDED(res))
1122 {
1123 srcrow = srcdata;
1124 dstrow = pbBuffer;
1125 for (y=0; y<prc->Height; y++) {
1126 srcpixel=srcrow;
1127 dstpixel=dstrow;
1128 for (x=0; x<prc->Width; x++) {
1129 tmppixel[0]=*srcpixel++; /* blue */
1130 tmppixel[1]=*srcpixel++; /* green */
1131 tmppixel[2]=*srcpixel++; /* red */
1132 srcpixel++; /* alpha */
1133
1134 *dstpixel++=tmppixel[2]; /* red */
1135 *dstpixel++=tmppixel[1]; /* green */
1136 *dstpixel++=tmppixel[0]; /* blue */
1137 }
1138 srcrow += srcstride;
1139 dstrow += cbStride;
1140 }
1141 }
1142
1143 HeapFree(GetProcessHeap(), 0, srcdata);
1144
1145 return res;
1146 }
1147 return S_OK;
1148 default:
1149 FIXME("Unimplemented conversion path!\n");
1150 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1151 }
1152 }
1153
1154 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1155 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1156 {
1157 HRESULT hr;
1158
1159 switch (source_format)
1160 {
1161 case format_32bppBGR:
1162 case format_32bppBGRA:
1163 case format_32bppPBGRA:
1164 case format_32bppGrayFloat:
1165 if (prc)
1166 {
1167 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1168 break;
1169 }
1170 return S_OK;
1171
1172 default:
1173 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1174 break;
1175 }
1176
1177 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1178 {
1179 INT x, y;
1180 BYTE *p = pbBuffer;
1181
1182 for (y = 0; y < prc->Height; y++)
1183 {
1184 BYTE *bgr = p;
1185 for (x = 0; x < prc->Width; x++)
1186 {
1187 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1188 *(float *)bgr = gray;
1189 bgr += 4;
1190 }
1191 p += cbStride;
1192 }
1193 }
1194 return hr;
1195 }
1196
1197 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1198 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1199 {
1200 HRESULT hr;
1201 BYTE *srcdata;
1202 UINT srcstride, srcdatasize;
1203
1204 if (source_format == format_8bppGray)
1205 {
1206 if (prc)
1207 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1208
1209 return S_OK;
1210 }
1211
1212 srcstride = 3 * prc->Width;
1213 srcdatasize = srcstride * prc->Height;
1214
1215 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1216 if (!srcdata) return E_OUTOFMEMORY;
1217
1218 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1219 if (SUCCEEDED(hr) && prc)
1220 {
1221 INT x, y;
1222 BYTE *src = srcdata, *dst = pbBuffer;
1223
1224 for (y = 0; y < prc->Height; y++)
1225 {
1226 BYTE *bgr = src;
1227
1228 for (x = 0; x < prc->Width; x++)
1229 {
1230 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1231
1232 /* conversion from 32bppGrayFloat to 24bppBGR has already applied sRGB gamma */
1233 if (source_format == format_32bppGrayFloat)
1234 gray *= 255.0f;
1235 else
1236 gray = to_sRGB_component(gray) * 255.0f;
1237
1238 dst[x] = (BYTE)floorf(gray + 0.51f);
1239 bgr += 3;
1240 }
1241 src += srcstride;
1242 dst += cbStride;
1243 }
1244 }
1245
1246 HeapFree(GetProcessHeap(), 0, srcdata);
1247 return hr;
1248 }
1249
1250 static UINT rgb_to_palette_index(BYTE r, BYTE g, BYTE b, WICColor *colors, UINT count)
1251 {
1252 UINT best_diff, best_index, i;
1253
1254 best_diff = ~0;
1255 best_index = 0;
1256
1257 for (i = 0; i < count; i++)
1258 {
1259 BYTE pal_r, pal_g, pal_b;
1260 DWORD diff_r, diff_g, diff_b, diff;
1261
1262 pal_r = colors[i] >> 16;
1263 pal_g = colors[i] >> 8;
1264 pal_b = colors[i];
1265
1266 diff_r = r - pal_r;
1267 diff_g = g - pal_g;
1268 diff_b = b - pal_b;
1269
1270 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1271 if (diff == 0) return i;
1272
1273 if (diff < best_diff)
1274 {
1275 best_diff = diff;
1276 best_index = i;
1277 }
1278 }
1279
1280 return best_index;
1281 }
1282
1283 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1284 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1285 {
1286 HRESULT hr;
1287 BYTE *srcdata;
1288 WICColor colors[256];
1289 UINT srcstride, srcdatasize, count;
1290
1291 if (source_format == format_8bppIndexed)
1292 {
1293 if (prc)
1294 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1295
1296 return S_OK;
1297 }
1298
1299 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1300
1301 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1302 if (hr != S_OK) return hr;
1303
1304 srcstride = 3 * prc->Width;
1305 srcdatasize = srcstride * prc->Height;
1306
1307 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1308 if (!srcdata) return E_OUTOFMEMORY;
1309
1310 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1311 if (SUCCEEDED(hr) && prc)
1312 {
1313 INT x, y;
1314 BYTE *src = srcdata, *dst = pbBuffer;
1315
1316 for (y = 0; y < prc->Height; y++)
1317 {
1318 BYTE *bgr = src;
1319
1320 for (x = 0; x < prc->Width; x++)
1321 {
1322 dst[x] = rgb_to_palette_index(bgr[2], bgr[1], bgr[0], colors, count);
1323 bgr += 3;
1324 }
1325 src += srcstride;
1326 dst += cbStride;
1327 }
1328 }
1329
1330 HeapFree(GetProcessHeap(), 0, srcdata);
1331 return hr;
1332 }
1333
1334 static const struct pixelformatinfo supported_formats[] = {
1335 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1336 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1337 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1338 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1339 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1340 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1341 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1342 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1343 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1344 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1345 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1346 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1347 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1348 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1349 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1350 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1351 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1352 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1353 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1354 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1355 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1356 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1357 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1358 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1359 {0}
1360 };
1361
1362 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1363 {
1364 UINT i;
1365
1366 for (i=0; supported_formats[i].guid; i++)
1367 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1368
1369 return NULL;
1370 }
1371
1372 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1373 void **ppv)
1374 {
1375 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1376 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1377
1378 if (!ppv) return E_INVALIDARG;
1379
1380 if (IsEqualIID(&IID_IUnknown, iid) ||
1381 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1382 IsEqualIID(&IID_IWICFormatConverter, iid))
1383 {
1384 *ppv = &This->IWICFormatConverter_iface;
1385 }
1386 else
1387 {
1388 *ppv = NULL;
1389 return E_NOINTERFACE;
1390 }
1391
1392 IUnknown_AddRef((IUnknown*)*ppv);
1393 return S_OK;
1394 }
1395
1396 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1397 {
1398 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1399 ULONG ref = InterlockedIncrement(&This->ref);
1400
1401 TRACE("(%p) refcount=%u\n", iface, ref);
1402
1403 return ref;
1404 }
1405
1406 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1407 {
1408 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1409 ULONG ref = InterlockedDecrement(&This->ref);
1410
1411 TRACE("(%p) refcount=%u\n", iface, ref);
1412
1413 if (ref == 0)
1414 {
1415 This->lock.DebugInfo->Spare[0] = 0;
1416 DeleteCriticalSection(&This->lock);
1417 if (This->source) IWICBitmapSource_Release(This->source);
1418 if (This->palette) IWICPalette_Release(This->palette);
1419 HeapFree(GetProcessHeap(), 0, This);
1420 }
1421
1422 return ref;
1423 }
1424
1425 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1426 UINT *puiWidth, UINT *puiHeight)
1427 {
1428 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1429
1430 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1431
1432 if (This->source)
1433 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1434 else
1435 return WINCODEC_ERR_NOTINITIALIZED;
1436 }
1437
1438 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1439 WICPixelFormatGUID *pPixelFormat)
1440 {
1441 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1442
1443 TRACE("(%p,%p)\n", iface, pPixelFormat);
1444
1445 if (This->source)
1446 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1447 else
1448 return WINCODEC_ERR_NOTINITIALIZED;
1449
1450 return S_OK;
1451 }
1452
1453 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1454 double *pDpiX, double *pDpiY)
1455 {
1456 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1457
1458 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1459
1460 if (This->source)
1461 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1462 else
1463 return WINCODEC_ERR_NOTINITIALIZED;
1464 }
1465
1466 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1467 IWICPalette *palette)
1468 {
1469 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1470
1471 TRACE("(%p,%p)\n", iface, palette);
1472
1473 if (!palette) return E_INVALIDARG;
1474 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1475
1476 if (!This->palette)
1477 {
1478 HRESULT hr;
1479 UINT bpp;
1480
1481 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1482 if (hr != S_OK) return hr;
1483 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1484 return IWICBitmapSource_CopyPalette(This->source, palette);
1485 }
1486
1487 return IWICPalette_InitializeFromPalette(palette, This->palette);
1488 }
1489
1490 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1491 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1492 {
1493 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1494 WICRect rc;
1495 HRESULT hr;
1496 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1497
1498 if (This->source)
1499 {
1500 if (!prc)
1501 {
1502 UINT width, height;
1503 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1504 if (FAILED(hr)) return hr;
1505 rc.X = 0;
1506 rc.Y = 0;
1507 rc.Width = width;
1508 rc.Height = height;
1509 prc = &rc;
1510 }
1511
1512 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1513 pbBuffer, This->src_format->format);
1514 }
1515 else
1516 return WINCODEC_ERR_WRONGSTATE;
1517 }
1518
1519 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1520 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1521 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1522 {
1523 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1524 const struct pixelformatinfo *srcinfo, *dstinfo;
1525 GUID srcFormat;
1526 HRESULT res;
1527
1528 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1529 dither, palette, alpha_threshold, palette_type);
1530
1531 if (!palette)
1532 {
1533 UINT bpp;
1534 res = get_pixelformat_bpp(dstFormat, &bpp);
1535 if (res != S_OK) return res;
1536
1537 res = PaletteImpl_Create(&palette);
1538 if (res != S_OK) return res;
1539
1540 switch (palette_type)
1541 {
1542 case WICBitmapPaletteTypeCustom:
1543 IWICPalette_Release(palette);
1544 palette = NULL;
1545 if (bpp <= 8) return E_INVALIDARG;
1546 break;
1547
1548 case WICBitmapPaletteTypeMedianCut:
1549 {
1550 if (bpp <= 8)
1551 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1552 break;
1553 }
1554
1555 default:
1556 if (bpp <= 8)
1557 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1558 break;
1559 }
1560
1561 if (res != S_OK)
1562 {
1563 IWICPalette_Release(palette);
1564 return res;
1565 }
1566 }
1567 else
1568 IWICPalette_AddRef(palette);
1569
1570 EnterCriticalSection(&This->lock);
1571
1572 if (This->source)
1573 {
1574 res = WINCODEC_ERR_WRONGSTATE;
1575 goto end;
1576 }
1577
1578 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1579 if (FAILED(res)) goto end;
1580
1581 srcinfo = get_formatinfo(&srcFormat);
1582 if (!srcinfo)
1583 {
1584 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1585 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1586 goto end;
1587 }
1588
1589 dstinfo = get_formatinfo(dstFormat);
1590 if (!dstinfo)
1591 {
1592 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1593 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1594 goto end;
1595 }
1596
1597 if (dstinfo->copy_function)
1598 {
1599 IWICBitmapSource_AddRef(source);
1600 This->src_format = srcinfo;
1601 This->dst_format = dstinfo;
1602 This->dither = dither;
1603 This->alpha_threshold = alpha_threshold;
1604 This->palette = palette;
1605 This->source = source;
1606 }
1607 else
1608 {
1609 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1610 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1611 }
1612
1613 end:
1614
1615 LeaveCriticalSection(&This->lock);
1616
1617 if (res != S_OK && palette)
1618 IWICPalette_Release(palette);
1619
1620 return res;
1621 }
1622
1623 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1624 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1625 BOOL *pfCanConvert)
1626 {
1627 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1628 const struct pixelformatinfo *srcinfo, *dstinfo;
1629
1630 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1631 debugstr_guid(dstPixelFormat), pfCanConvert);
1632
1633 srcinfo = get_formatinfo(srcPixelFormat);
1634 if (!srcinfo)
1635 {
1636 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1637 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1638 }
1639
1640 dstinfo = get_formatinfo(dstPixelFormat);
1641 if (!dstinfo)
1642 {
1643 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1644 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1645 }
1646
1647 if (dstinfo->copy_function &&
1648 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1649 *pfCanConvert = TRUE;
1650 else
1651 {
1652 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1653 *pfCanConvert = FALSE;
1654 }
1655
1656 return S_OK;
1657 }
1658
1659 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1660 FormatConverter_QueryInterface,
1661 FormatConverter_AddRef,
1662 FormatConverter_Release,
1663 FormatConverter_GetSize,
1664 FormatConverter_GetPixelFormat,
1665 FormatConverter_GetResolution,
1666 FormatConverter_CopyPalette,
1667 FormatConverter_CopyPixels,
1668 FormatConverter_Initialize,
1669 FormatConverter_CanConvert
1670 };
1671
1672 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1673 {
1674 FormatConverter *This;
1675 HRESULT ret;
1676
1677 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1678
1679 *ppv = NULL;
1680
1681 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1682 if (!This) return E_OUTOFMEMORY;
1683
1684 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1685 This->ref = 1;
1686 This->source = NULL;
1687 This->palette = NULL;
1688 InitializeCriticalSection(&This->lock);
1689 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1690
1691 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1692 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1693
1694 return ret;
1695 }