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