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