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