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 */
to_sRGB_component(float f)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
impl_from_IWICFormatConverter(IWICFormatConverter * iface)136 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
137 {
138 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
139 }
140
copypixels_to_32bppBGRA(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)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_32bppRGBA:
726 if (prc)
727 {
728 HRESULT res;
729 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
730 if (FAILED(res)) return res;
731 convert_rgba_to_bgra(4, pbBuffer, prc->Width, prc->Height, cbStride);
732 }
733 return S_OK;
734 case format_32bppBGRA:
735 if (prc)
736 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
737 return S_OK;
738 case format_32bppPBGRA:
739 if (prc)
740 {
741 HRESULT res;
742 INT x, y;
743
744 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
745 if (FAILED(res)) return res;
746
747 for (y=0; y<prc->Height; y++)
748 for (x=0; x<prc->Width; x++)
749 {
750 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
751 if (alpha != 0 && alpha != 255)
752 {
753 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
754 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
755 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
756 }
757 }
758 }
759 return S_OK;
760 case format_48bppRGB:
761 if (prc)
762 {
763 HRESULT res;
764 INT x, y;
765 BYTE *srcdata;
766 UINT srcstride, srcdatasize;
767 const BYTE *srcrow;
768 const BYTE *srcpixel;
769 BYTE *dstrow;
770 DWORD *dstpixel;
771
772 srcstride = 6 * prc->Width;
773 srcdatasize = srcstride * prc->Height;
774
775 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
776 if (!srcdata) return E_OUTOFMEMORY;
777
778 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
779
780 if (SUCCEEDED(res))
781 {
782 srcrow = srcdata;
783 dstrow = pbBuffer;
784 for (y=0; y<prc->Height; y++) {
785 srcpixel=srcrow;
786 dstpixel=(DWORD*)dstrow;
787 for (x=0; x<prc->Width; x++) {
788 BYTE red, green, blue;
789 srcpixel++; red = *srcpixel++;
790 srcpixel++; green = *srcpixel++;
791 srcpixel++; blue = *srcpixel++;
792 *dstpixel++=0xff000000|red<<16|green<<8|blue;
793 }
794 srcrow += srcstride;
795 dstrow += cbStride;
796 }
797 }
798
799 HeapFree(GetProcessHeap(), 0, srcdata);
800
801 return res;
802 }
803 return S_OK;
804 case format_64bppRGBA:
805 if (prc)
806 {
807 HRESULT res;
808 INT x, y;
809 BYTE *srcdata;
810 UINT srcstride, srcdatasize;
811 const BYTE *srcrow;
812 const BYTE *srcpixel;
813 BYTE *dstrow;
814 DWORD *dstpixel;
815
816 srcstride = 8 * prc->Width;
817 srcdatasize = srcstride * prc->Height;
818
819 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
820 if (!srcdata) return E_OUTOFMEMORY;
821
822 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
823
824 if (SUCCEEDED(res))
825 {
826 srcrow = srcdata;
827 dstrow = pbBuffer;
828 for (y=0; y<prc->Height; y++) {
829 srcpixel=srcrow;
830 dstpixel=(DWORD*)dstrow;
831 for (x=0; x<prc->Width; x++) {
832 BYTE red, green, blue, alpha;
833 srcpixel++; red = *srcpixel++;
834 srcpixel++; green = *srcpixel++;
835 srcpixel++; blue = *srcpixel++;
836 srcpixel++; alpha = *srcpixel++;
837 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
838 }
839 srcrow += srcstride;
840 dstrow += cbStride;
841 }
842 }
843
844 HeapFree(GetProcessHeap(), 0, srcdata);
845
846 return res;
847 }
848 return S_OK;
849 case format_32bppCMYK:
850 if (prc)
851 {
852 HRESULT res;
853 UINT x, y;
854
855 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
856 if (FAILED(res)) return res;
857
858 for (y=0; y<prc->Height; y++)
859 for (x=0; x<prc->Width; x++)
860 {
861 BYTE *pixel = pbBuffer+cbStride*y+4*x;
862 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
863 pixel[0] = (255-y)*(255-k)/255; /* blue */
864 pixel[1] = (255-m)*(255-k)/255; /* green */
865 pixel[2] = (255-c)*(255-k)/255; /* red */
866 pixel[3] = 255; /* alpha */
867 }
868 }
869 return S_OK;
870 default:
871 FIXME("Unimplemented conversion path!\n");
872 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
873 }
874 }
875
copypixels_to_32bppRGBA(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)876 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc,
877 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
878 {
879 HRESULT hr;
880
881 switch (source_format)
882 {
883 case format_32bppRGB:
884 if (prc)
885 {
886 INT x, y;
887
888 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
889 if (FAILED(hr)) return hr;
890
891 /* set all alpha values to 255 */
892 for (y=0; y<prc->Height; y++)
893 for (x=0; x<prc->Width; x++)
894 pbBuffer[cbStride*y+4*x+3] = 0xff;
895 }
896 return S_OK;
897
898 case format_32bppRGBA:
899 if (prc)
900 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
901 return S_OK;
902
903 case format_32bppPRGBA:
904 if (prc)
905 {
906 INT x, y;
907
908 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
909 if (FAILED(hr)) return hr;
910
911 for (y=0; y<prc->Height; y++)
912 for (x=0; x<prc->Width; x++)
913 {
914 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
915 if (alpha != 0 && alpha != 255)
916 {
917 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
918 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
919 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
920 }
921 }
922 }
923 return S_OK;
924
925 default:
926 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
927 if (SUCCEEDED(hr) && prc)
928 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride);
929 return hr;
930 }
931 }
932
copypixels_to_32bppBGR(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)933 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
934 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
935 {
936 switch (source_format)
937 {
938 case format_32bppBGR:
939 case format_32bppBGRA:
940 case format_32bppPBGRA:
941 if (prc)
942 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
943 return S_OK;
944 default:
945 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
946 }
947 }
948
copypixels_to_32bppRGB(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)949 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc,
950 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
951 {
952 switch (source_format)
953 {
954 case format_32bppRGB:
955 case format_32bppRGBA:
956 case format_32bppPRGBA:
957 if (prc)
958 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
959 return S_OK;
960 default:
961 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
962 }
963 }
964
copypixels_to_32bppPBGRA(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)965 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
966 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
967 {
968 HRESULT hr;
969
970 switch (source_format)
971 {
972 case format_32bppPBGRA:
973 if (prc)
974 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
975 return S_OK;
976 default:
977 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
978 if (SUCCEEDED(hr) && prc)
979 {
980 INT x, y;
981
982 for (y=0; y<prc->Height; y++)
983 for (x=0; x<prc->Width; x++)
984 {
985 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
986 if (alpha != 255)
987 {
988 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
989 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
990 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
991 }
992 }
993 }
994 return hr;
995 }
996 }
997
copypixels_to_32bppPRGBA(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)998 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc,
999 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1000 {
1001 HRESULT hr;
1002
1003 switch (source_format)
1004 {
1005 case format_32bppPRGBA:
1006 if (prc)
1007 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1008 return S_OK;
1009 default:
1010 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1011 if (SUCCEEDED(hr) && prc)
1012 {
1013 INT x, y;
1014
1015 for (y=0; y<prc->Height; y++)
1016 for (x=0; x<prc->Width; x++)
1017 {
1018 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
1019 if (alpha != 255)
1020 {
1021 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
1022 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
1023 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
1024 }
1025 }
1026 }
1027 return hr;
1028 }
1029 }
1030
copypixels_to_24bppBGR(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)1031 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
1032 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1033 {
1034 HRESULT hr;
1035
1036 switch (source_format)
1037 {
1038 case format_24bppBGR:
1039 case format_24bppRGB:
1040 if (prc)
1041 {
1042 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1043 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
1044 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1045 return hr;
1046 }
1047 return S_OK;
1048 case format_32bppBGR:
1049 case format_32bppBGRA:
1050 case format_32bppPBGRA:
1051 case format_32bppRGBA:
1052 if (prc)
1053 {
1054 HRESULT res;
1055 INT x, y;
1056 BYTE *srcdata;
1057 UINT srcstride, srcdatasize;
1058 const BYTE *srcrow;
1059 const BYTE *srcpixel;
1060 BYTE *dstrow;
1061 BYTE *dstpixel;
1062
1063 srcstride = 4 * prc->Width;
1064 srcdatasize = srcstride * prc->Height;
1065
1066 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1067 if (!srcdata) return E_OUTOFMEMORY;
1068
1069 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1070
1071 if (SUCCEEDED(res))
1072 {
1073 srcrow = srcdata;
1074 dstrow = pbBuffer;
1075
1076 if (source_format == format_32bppRGBA)
1077 {
1078 for (y = 0; y < prc->Height; y++)
1079 {
1080 srcpixel = srcrow;
1081 dstpixel = dstrow;
1082 for (x = 0; x < prc->Width; x++) {
1083 *dstpixel++ = srcpixel[2]; /* blue */
1084 *dstpixel++ = srcpixel[1]; /* green */
1085 *dstpixel++ = srcpixel[0]; /* red */
1086 srcpixel += 4;
1087 }
1088 srcrow += srcstride;
1089 dstrow += cbStride;
1090 }
1091 }
1092 else
1093 {
1094 for (y = 0; y < prc->Height; y++)
1095 {
1096 srcpixel = srcrow;
1097 dstpixel = dstrow;
1098 for (x = 0; x < prc->Width; x++) {
1099 *dstpixel++ = *srcpixel++; /* blue */
1100 *dstpixel++ = *srcpixel++; /* green */
1101 *dstpixel++ = *srcpixel++; /* red */
1102 srcpixel++; /* alpha */
1103 }
1104 srcrow += srcstride;
1105 dstrow += cbStride;
1106 }
1107 }
1108 }
1109
1110 HeapFree(GetProcessHeap(), 0, srcdata);
1111
1112 return res;
1113 }
1114 return S_OK;
1115
1116 case format_32bppGrayFloat:
1117 if (prc)
1118 {
1119 BYTE *srcdata;
1120 UINT srcstride, srcdatasize;
1121
1122 srcstride = 4 * prc->Width;
1123 srcdatasize = srcstride * prc->Height;
1124
1125 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1126 if (!srcdata) return E_OUTOFMEMORY;
1127
1128 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1129
1130 if (SUCCEEDED(hr))
1131 {
1132 INT x, y;
1133 BYTE *src = srcdata, *dst = pbBuffer;
1134
1135 for (y = 0; y < prc->Height; y++)
1136 {
1137 float *gray_float = (float *)src;
1138 BYTE *bgr = dst;
1139
1140 for (x = 0; x < prc->Width; x++)
1141 {
1142 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f);
1143 *bgr++ = gray;
1144 *bgr++ = gray;
1145 *bgr++ = gray;
1146 }
1147 src += srcstride;
1148 dst += cbStride;
1149 }
1150 }
1151
1152 HeapFree(GetProcessHeap(), 0, srcdata);
1153
1154 return hr;
1155 }
1156 return S_OK;
1157
1158 case format_32bppCMYK:
1159 if (prc)
1160 {
1161 BYTE *srcdata;
1162 UINT srcstride, srcdatasize;
1163
1164 srcstride = 4 * prc->Width;
1165 srcdatasize = srcstride * prc->Height;
1166
1167 srcdata = heap_alloc(srcdatasize);
1168 if (!srcdata) return E_OUTOFMEMORY;
1169
1170 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1171 if (SUCCEEDED(hr))
1172 {
1173 INT x, y;
1174 BYTE *src = srcdata, *dst = pbBuffer;
1175
1176 for (y = 0; y < prc->Height; y++)
1177 {
1178 BYTE *cmyk = src;
1179 BYTE *bgr = dst;
1180
1181 for (x = 0; x < prc->Width; x++)
1182 {
1183 BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3];
1184 bgr[0] = (255 - y) * (255 - k) / 255; /* B */
1185 bgr[1] = (255 - m) * (255 - k) / 255; /* G */
1186 bgr[2] = (255 - c) * (255 - k) / 255; /* R */
1187 cmyk += 4;
1188 bgr += 3;
1189 }
1190 src += srcstride;
1191 dst += cbStride;
1192 }
1193 }
1194
1195 heap_free(srcdata);
1196 return hr;
1197 }
1198 return S_OK;
1199
1200 default:
1201 FIXME("Unimplemented conversion path!\n");
1202 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1203 }
1204 }
1205
copypixels_to_24bppRGB(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)1206 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
1207 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1208 {
1209 HRESULT hr;
1210
1211 switch (source_format)
1212 {
1213 case format_24bppBGR:
1214 case format_24bppRGB:
1215 if (prc)
1216 {
1217 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1218 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
1219 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
1220 return hr;
1221 }
1222 return S_OK;
1223 case format_32bppBGR:
1224 case format_32bppBGRA:
1225 case format_32bppPBGRA:
1226 if (prc)
1227 {
1228 HRESULT res;
1229 INT x, y;
1230 BYTE *srcdata;
1231 UINT srcstride, srcdatasize;
1232 const BYTE *srcrow;
1233 const BYTE *srcpixel;
1234 BYTE *dstrow;
1235 BYTE *dstpixel;
1236 BYTE tmppixel[3];
1237
1238 srcstride = 4 * prc->Width;
1239 srcdatasize = srcstride * prc->Height;
1240
1241 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1242 if (!srcdata) return E_OUTOFMEMORY;
1243
1244 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1245
1246 if (SUCCEEDED(res))
1247 {
1248 srcrow = srcdata;
1249 dstrow = pbBuffer;
1250 for (y=0; y<prc->Height; y++) {
1251 srcpixel=srcrow;
1252 dstpixel=dstrow;
1253 for (x=0; x<prc->Width; x++) {
1254 tmppixel[0]=*srcpixel++; /* blue */
1255 tmppixel[1]=*srcpixel++; /* green */
1256 tmppixel[2]=*srcpixel++; /* red */
1257 srcpixel++; /* alpha */
1258
1259 *dstpixel++=tmppixel[2]; /* red */
1260 *dstpixel++=tmppixel[1]; /* green */
1261 *dstpixel++=tmppixel[0]; /* blue */
1262 }
1263 srcrow += srcstride;
1264 dstrow += cbStride;
1265 }
1266 }
1267
1268 HeapFree(GetProcessHeap(), 0, srcdata);
1269
1270 return res;
1271 }
1272 return S_OK;
1273 default:
1274 FIXME("Unimplemented conversion path!\n");
1275 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1276 }
1277 }
1278
copypixels_to_32bppGrayFloat(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)1279 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc,
1280 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1281 {
1282 HRESULT hr;
1283
1284 switch (source_format)
1285 {
1286 case format_32bppBGR:
1287 case format_32bppBGRA:
1288 case format_32bppPBGRA:
1289 case format_32bppGrayFloat:
1290 if (prc)
1291 {
1292 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1293 break;
1294 }
1295 return S_OK;
1296
1297 default:
1298 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
1299 break;
1300 }
1301
1302 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat)
1303 {
1304 INT x, y;
1305 BYTE *p = pbBuffer;
1306
1307 for (y = 0; y < prc->Height; y++)
1308 {
1309 BYTE *bgr = p;
1310 for (x = 0; x < prc->Width; x++)
1311 {
1312 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1313 *(float *)bgr = gray;
1314 bgr += 4;
1315 }
1316 p += cbStride;
1317 }
1318 }
1319 return hr;
1320 }
1321
copypixels_to_8bppGray(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)1322 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc,
1323 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1324 {
1325 HRESULT hr;
1326 BYTE *srcdata;
1327 UINT srcstride, srcdatasize;
1328
1329 if (source_format == format_8bppGray)
1330 {
1331 if (prc)
1332 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1333
1334 return S_OK;
1335 }
1336
1337 if (source_format == format_32bppGrayFloat)
1338 {
1339 hr = S_OK;
1340
1341 if (prc)
1342 {
1343 srcstride = 4 * prc->Width;
1344 srcdatasize = srcstride * prc->Height;
1345
1346 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1347 if (!srcdata) return E_OUTOFMEMORY;
1348
1349 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
1350 if (SUCCEEDED(hr))
1351 {
1352 INT x, y;
1353 BYTE *src = srcdata, *dst = pbBuffer;
1354
1355 for (y=0; y < prc->Height; y++)
1356 {
1357 float *srcpixel = (float*)src;
1358 BYTE *dstpixel = dst;
1359
1360 for (x=0; x < prc->Width; x++)
1361 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f);
1362
1363 src += srcstride;
1364 dst += cbStride;
1365 }
1366 }
1367
1368 HeapFree(GetProcessHeap(), 0, srcdata);
1369 }
1370
1371 return hr;
1372 }
1373
1374 if (!prc)
1375 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1376
1377 srcstride = 3 * prc->Width;
1378 srcdatasize = srcstride * prc->Height;
1379
1380 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1381 if (!srcdata) return E_OUTOFMEMORY;
1382
1383 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1384 if (SUCCEEDED(hr))
1385 {
1386 INT x, y;
1387 BYTE *src = srcdata, *dst = pbBuffer;
1388
1389 for (y = 0; y < prc->Height; y++)
1390 {
1391 BYTE *bgr = src;
1392
1393 for (x = 0; x < prc->Width; x++)
1394 {
1395 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f;
1396
1397 gray = to_sRGB_component(gray) * 255.0f;
1398 dst[x] = (BYTE)floorf(gray + 0.51f);
1399 bgr += 3;
1400 }
1401 src += srcstride;
1402 dst += cbStride;
1403 }
1404 }
1405
1406 HeapFree(GetProcessHeap(), 0, srcdata);
1407 return hr;
1408 }
1409
rgb_to_palette_index(BYTE bgr[3],WICColor * colors,UINT count)1410 static UINT rgb_to_palette_index(BYTE bgr[3], WICColor *colors, UINT count)
1411 {
1412 UINT best_diff, best_index, i;
1413
1414 best_diff = ~0;
1415 best_index = 0;
1416
1417 for (i = 0; i < count; i++)
1418 {
1419 BYTE pal_r, pal_g, pal_b;
1420 UINT diff_r, diff_g, diff_b, diff;
1421
1422 pal_r = colors[i] >> 16;
1423 pal_g = colors[i] >> 8;
1424 pal_b = colors[i];
1425
1426 diff_r = bgr[2] - pal_r;
1427 diff_g = bgr[1] - pal_g;
1428 diff_b = bgr[0] - pal_b;
1429
1430 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b;
1431 if (diff == 0) return i;
1432
1433 if (diff < best_diff)
1434 {
1435 best_diff = diff;
1436 best_index = i;
1437 }
1438 }
1439
1440 return best_index;
1441 }
1442
copypixels_to_8bppIndexed(struct FormatConverter * This,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer,enum pixelformat source_format)1443 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc,
1444 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
1445 {
1446 HRESULT hr;
1447 BYTE *srcdata;
1448 WICColor colors[256];
1449 UINT srcstride, srcdatasize, count;
1450
1451 if (source_format == format_8bppIndexed)
1452 {
1453 if (prc)
1454 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
1455
1456 return S_OK;
1457 }
1458
1459 if (!prc)
1460 return copypixels_to_24bppBGR(This, NULL, cbStride, cbBufferSize, pbBuffer, source_format);
1461
1462 if (!This->palette) return WINCODEC_ERR_WRONGSTATE;
1463
1464 hr = IWICPalette_GetColors(This->palette, 256, colors, &count);
1465 if (hr != S_OK) return hr;
1466
1467 srcstride = 3 * prc->Width;
1468 srcdatasize = srcstride * prc->Height;
1469
1470 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
1471 if (!srcdata) return E_OUTOFMEMORY;
1472
1473 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format);
1474 if (SUCCEEDED(hr))
1475 {
1476 INT x, y;
1477 BYTE *src = srcdata, *dst = pbBuffer;
1478
1479 for (y = 0; y < prc->Height; y++)
1480 {
1481 BYTE *bgr = src;
1482
1483 for (x = 0; x < prc->Width; x++)
1484 {
1485 dst[x] = rgb_to_palette_index(bgr, colors, count);
1486 bgr += 3;
1487 }
1488 src += srcstride;
1489 dst += cbStride;
1490 }
1491 }
1492
1493 HeapFree(GetProcessHeap(), 0, srcdata);
1494 return hr;
1495 }
1496
1497 static const struct pixelformatinfo supported_formats[] = {
1498 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1499 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1500 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1501 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed},
1502 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1503 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1504 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1505 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray},
1506 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1507 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1508 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1509 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1510 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1511 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1512 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat},
1513 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1514 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB},
1515 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1516 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA},
1517 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1518 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA},
1519 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1520 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1521 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1522 {0}
1523 };
1524
get_formatinfo(const WICPixelFormatGUID * format)1525 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1526 {
1527 UINT i;
1528
1529 for (i=0; supported_formats[i].guid; i++)
1530 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1531
1532 return NULL;
1533 }
1534
FormatConverter_QueryInterface(IWICFormatConverter * iface,REFIID iid,void ** ppv)1535 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1536 void **ppv)
1537 {
1538 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1539 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1540
1541 if (!ppv) return E_INVALIDARG;
1542
1543 if (IsEqualIID(&IID_IUnknown, iid) ||
1544 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1545 IsEqualIID(&IID_IWICFormatConverter, iid))
1546 {
1547 *ppv = &This->IWICFormatConverter_iface;
1548 }
1549 else
1550 {
1551 *ppv = NULL;
1552 return E_NOINTERFACE;
1553 }
1554
1555 IUnknown_AddRef((IUnknown*)*ppv);
1556 return S_OK;
1557 }
1558
FormatConverter_AddRef(IWICFormatConverter * iface)1559 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1560 {
1561 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1562 ULONG ref = InterlockedIncrement(&This->ref);
1563
1564 TRACE("(%p) refcount=%u\n", iface, ref);
1565
1566 return ref;
1567 }
1568
FormatConverter_Release(IWICFormatConverter * iface)1569 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1570 {
1571 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1572 ULONG ref = InterlockedDecrement(&This->ref);
1573
1574 TRACE("(%p) refcount=%u\n", iface, ref);
1575
1576 if (ref == 0)
1577 {
1578 This->lock.DebugInfo->Spare[0] = 0;
1579 DeleteCriticalSection(&This->lock);
1580 if (This->source) IWICBitmapSource_Release(This->source);
1581 if (This->palette) IWICPalette_Release(This->palette);
1582 HeapFree(GetProcessHeap(), 0, This);
1583 }
1584
1585 return ref;
1586 }
1587
FormatConverter_GetSize(IWICFormatConverter * iface,UINT * puiWidth,UINT * puiHeight)1588 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1589 UINT *puiWidth, UINT *puiHeight)
1590 {
1591 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1592
1593 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1594
1595 if (This->source)
1596 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1597 else
1598 return WINCODEC_ERR_NOTINITIALIZED;
1599 }
1600
FormatConverter_GetPixelFormat(IWICFormatConverter * iface,WICPixelFormatGUID * pPixelFormat)1601 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1602 WICPixelFormatGUID *pPixelFormat)
1603 {
1604 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1605
1606 TRACE("(%p,%p)\n", iface, pPixelFormat);
1607
1608 if (This->source)
1609 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1610 else
1611 return WINCODEC_ERR_NOTINITIALIZED;
1612
1613 return S_OK;
1614 }
1615
FormatConverter_GetResolution(IWICFormatConverter * iface,double * pDpiX,double * pDpiY)1616 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1617 double *pDpiX, double *pDpiY)
1618 {
1619 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1620
1621 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
1622
1623 if (This->source)
1624 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1625 else
1626 return WINCODEC_ERR_NOTINITIALIZED;
1627 }
1628
FormatConverter_CopyPalette(IWICFormatConverter * iface,IWICPalette * palette)1629 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1630 IWICPalette *palette)
1631 {
1632 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1633
1634 TRACE("(%p,%p)\n", iface, palette);
1635
1636 if (!palette) return E_INVALIDARG;
1637 if (!This->source) return WINCODEC_ERR_WRONGSTATE;
1638
1639 if (!This->palette)
1640 {
1641 HRESULT hr;
1642 UINT bpp;
1643
1644 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp);
1645 if (hr != S_OK) return hr;
1646 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE;
1647 return IWICBitmapSource_CopyPalette(This->source, palette);
1648 }
1649
1650 return IWICPalette_InitializeFromPalette(palette, This->palette);
1651 }
1652
FormatConverter_CopyPixels(IWICFormatConverter * iface,const WICRect * prc,UINT cbStride,UINT cbBufferSize,BYTE * pbBuffer)1653 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1654 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1655 {
1656 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1657 WICRect rc;
1658 HRESULT hr;
1659 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
1660
1661 if (This->source)
1662 {
1663 if (!prc)
1664 {
1665 UINT width, height;
1666 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1667 if (FAILED(hr)) return hr;
1668 rc.X = 0;
1669 rc.Y = 0;
1670 rc.Width = width;
1671 rc.Height = height;
1672 prc = &rc;
1673 }
1674
1675 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1676 pbBuffer, This->src_format->format);
1677 }
1678 else
1679 return WINCODEC_ERR_WRONGSTATE;
1680 }
1681
FormatConverter_Initialize(IWICFormatConverter * iface,IWICBitmapSource * source,REFWICPixelFormatGUID dstFormat,WICBitmapDitherType dither,IWICPalette * palette,double alpha_threshold,WICBitmapPaletteType palette_type)1682 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1683 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1684 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type)
1685 {
1686 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1687 const struct pixelformatinfo *srcinfo, *dstinfo;
1688 GUID srcFormat;
1689 HRESULT res;
1690
1691 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat),
1692 dither, palette, alpha_threshold, palette_type);
1693
1694 if (!palette)
1695 {
1696 UINT bpp;
1697 res = get_pixelformat_bpp(dstFormat, &bpp);
1698 if (res != S_OK) return res;
1699
1700 res = PaletteImpl_Create(&palette);
1701 if (res != S_OK) return res;
1702
1703 switch (palette_type)
1704 {
1705 case WICBitmapPaletteTypeCustom:
1706 IWICPalette_Release(palette);
1707 palette = NULL;
1708 if (bpp <= 8) return E_INVALIDARG;
1709 break;
1710
1711 case WICBitmapPaletteTypeMedianCut:
1712 {
1713 if (bpp <= 8)
1714 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE);
1715 break;
1716 }
1717
1718 default:
1719 if (bpp <= 8)
1720 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE);
1721 break;
1722 }
1723
1724 if (res != S_OK)
1725 {
1726 IWICPalette_Release(palette);
1727 return res;
1728 }
1729 }
1730 else
1731 IWICPalette_AddRef(palette);
1732
1733 EnterCriticalSection(&This->lock);
1734
1735 if (This->source)
1736 {
1737 res = WINCODEC_ERR_WRONGSTATE;
1738 goto end;
1739 }
1740
1741 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat);
1742 if (FAILED(res)) goto end;
1743
1744 srcinfo = get_formatinfo(&srcFormat);
1745 if (!srcinfo)
1746 {
1747 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1748 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1749 goto end;
1750 }
1751
1752 dstinfo = get_formatinfo(dstFormat);
1753 if (!dstinfo)
1754 {
1755 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1756 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1757 goto end;
1758 }
1759
1760 if (dstinfo->copy_function)
1761 {
1762 IWICBitmapSource_AddRef(source);
1763 This->src_format = srcinfo;
1764 This->dst_format = dstinfo;
1765 This->dither = dither;
1766 This->alpha_threshold = alpha_threshold;
1767 This->palette = palette;
1768 This->source = source;
1769 }
1770 else
1771 {
1772 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1773 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1774 }
1775
1776 end:
1777
1778 LeaveCriticalSection(&This->lock);
1779
1780 if (res != S_OK && palette)
1781 IWICPalette_Release(palette);
1782
1783 return res;
1784 }
1785
FormatConverter_CanConvert(IWICFormatConverter * iface,REFWICPixelFormatGUID srcPixelFormat,REFWICPixelFormatGUID dstPixelFormat,BOOL * pfCanConvert)1786 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1787 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1788 BOOL *pfCanConvert)
1789 {
1790 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1791 const struct pixelformatinfo *srcinfo, *dstinfo;
1792
1793 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1794 debugstr_guid(dstPixelFormat), pfCanConvert);
1795
1796 srcinfo = get_formatinfo(srcPixelFormat);
1797 if (!srcinfo)
1798 {
1799 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1800 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1801 }
1802
1803 dstinfo = get_formatinfo(dstPixelFormat);
1804 if (!dstinfo)
1805 {
1806 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1807 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1808 }
1809
1810 if (dstinfo->copy_function &&
1811 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1812 *pfCanConvert = TRUE;
1813 else
1814 {
1815 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1816 *pfCanConvert = FALSE;
1817 }
1818
1819 return S_OK;
1820 }
1821
1822 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1823 FormatConverter_QueryInterface,
1824 FormatConverter_AddRef,
1825 FormatConverter_Release,
1826 FormatConverter_GetSize,
1827 FormatConverter_GetPixelFormat,
1828 FormatConverter_GetResolution,
1829 FormatConverter_CopyPalette,
1830 FormatConverter_CopyPixels,
1831 FormatConverter_Initialize,
1832 FormatConverter_CanConvert
1833 };
1834
FormatConverter_CreateInstance(REFIID iid,void ** ppv)1835 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
1836 {
1837 FormatConverter *This;
1838 HRESULT ret;
1839
1840 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1841
1842 *ppv = NULL;
1843
1844 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1845 if (!This) return E_OUTOFMEMORY;
1846
1847 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1848 This->ref = 1;
1849 This->source = NULL;
1850 This->palette = NULL;
1851 InitializeCriticalSection(&This->lock);
1852 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1853
1854 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1855 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1856
1857 return ret;
1858 }
1859