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