Create a branch for Aleksandar Andrejevic for his work on NTVDM. See http://jira...
[reactos.git] / dll / win32 / windowscodecs / converter.c
1 /*
2 * Copyright 2009 Vincent Povirk
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #define WIN32_NO_STATUS
20 #define _INC_WINDOWS
21 #define COM_NO_WINDOWS_H
22
23 #include <config.h>
24
25 #include <stdarg.h>
26
27 #define COBJMACROS
28
29 #include <windef.h>
30 #include <winbase.h>
31 #include <objbase.h>
32 #include <wincodec.h>
33
34 #include "wincodecs_private.h"
35
36 #include <wine/debug.h>
37
38 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
39
40 struct FormatConverter;
41
42 enum pixelformat {
43 format_1bppIndexed,
44 format_2bppIndexed,
45 format_4bppIndexed,
46 format_8bppIndexed,
47 format_BlackWhite,
48 format_2bppGray,
49 format_4bppGray,
50 format_8bppGray,
51 format_16bppGray,
52 format_16bppBGR555,
53 format_16bppBGR565,
54 format_16bppBGRA5551,
55 format_24bppBGR,
56 format_24bppRGB,
57 format_32bppBGR,
58 format_32bppBGRA,
59 format_32bppPBGRA,
60 format_48bppRGB,
61 format_64bppRGBA,
62 format_32bppCMYK,
63 };
64
65 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
66 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format);
67
68 struct pixelformatinfo {
69 enum pixelformat format;
70 const WICPixelFormatGUID *guid;
71 copyfunc copy_function;
72 };
73
74 typedef struct FormatConverter {
75 IWICFormatConverter IWICFormatConverter_iface;
76 LONG ref;
77 IWICBitmapSource *source;
78 const struct pixelformatinfo *dst_format, *src_format;
79 WICBitmapDitherType dither;
80 double alpha_threshold;
81 WICBitmapPaletteType palette_type;
82 CRITICAL_SECTION lock; /* must be held when initialized */
83 } FormatConverter;
84
85 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
86 {
87 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
88 }
89
90 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
91 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
92 {
93 switch (source_format)
94 {
95 case format_1bppIndexed:
96 case format_BlackWhite:
97 if (prc)
98 {
99 HRESULT res;
100 INT x, y;
101 BYTE *srcdata;
102 UINT srcstride, srcdatasize;
103 const BYTE *srcrow;
104 const BYTE *srcbyte;
105 BYTE *dstrow;
106 DWORD *dstpixel;
107 WICColor colors[2];
108 IWICPalette *palette;
109 UINT actualcolors;
110
111 res = PaletteImpl_Create(&palette);
112 if (FAILED(res)) return res;
113
114 if (source_format == format_1bppIndexed)
115 res = IWICBitmapSource_CopyPalette(This->source, palette);
116 else
117 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
118
119 if (SUCCEEDED(res))
120 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
121
122 IWICPalette_Release(palette);
123 if (FAILED(res)) return res;
124
125 srcstride = (prc->Width+7)/8;
126 srcdatasize = srcstride * prc->Height;
127
128 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
129 if (!srcdata) return E_OUTOFMEMORY;
130
131 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
132
133 if (SUCCEEDED(res))
134 {
135 srcrow = srcdata;
136 dstrow = pbBuffer;
137 for (y=0; y<prc->Height; y++) {
138 srcbyte = srcrow;
139 dstpixel=(DWORD*)dstrow;
140 for (x=0; x<prc->Width; x+=8) {
141 BYTE srcval;
142 srcval=*srcbyte++;
143 *dstpixel++ = colors[srcval>>7&1];
144 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1];
145 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1];
146 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1];
147 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1];
148 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1];
149 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1];
150 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1];
151 }
152 srcrow += srcstride;
153 dstrow += cbStride;
154 }
155 }
156
157 HeapFree(GetProcessHeap(), 0, srcdata);
158
159 return res;
160 }
161 return S_OK;
162 case format_2bppIndexed:
163 case format_2bppGray:
164 if (prc)
165 {
166 HRESULT res;
167 INT x, y;
168 BYTE *srcdata;
169 UINT srcstride, srcdatasize;
170 const BYTE *srcrow;
171 const BYTE *srcbyte;
172 BYTE *dstrow;
173 DWORD *dstpixel;
174 WICColor colors[4];
175 IWICPalette *palette;
176 UINT actualcolors;
177
178 res = PaletteImpl_Create(&palette);
179 if (FAILED(res)) return res;
180
181 if (source_format == format_2bppIndexed)
182 res = IWICBitmapSource_CopyPalette(This->source, palette);
183 else
184 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
185
186 if (SUCCEEDED(res))
187 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
188
189 IWICPalette_Release(palette);
190 if (FAILED(res)) return res;
191
192 srcstride = (prc->Width+3)/4;
193 srcdatasize = srcstride * prc->Height;
194
195 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
196 if (!srcdata) return E_OUTOFMEMORY;
197
198 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
199
200 if (SUCCEEDED(res))
201 {
202 srcrow = srcdata;
203 dstrow = pbBuffer;
204 for (y=0; y<prc->Height; y++) {
205 srcbyte = srcrow;
206 dstpixel=(DWORD*)dstrow;
207 for (x=0; x<prc->Width; x+=4) {
208 BYTE srcval;
209 srcval=*srcbyte++;
210 *dstpixel++ = colors[srcval>>6];
211 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3];
212 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3];
213 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0x3];
214 }
215 srcrow += srcstride;
216 dstrow += cbStride;
217 }
218 }
219
220 HeapFree(GetProcessHeap(), 0, srcdata);
221
222 return res;
223 }
224 return S_OK;
225 case format_4bppIndexed:
226 case format_4bppGray:
227 if (prc)
228 {
229 HRESULT res;
230 INT x, y;
231 BYTE *srcdata;
232 UINT srcstride, srcdatasize;
233 const BYTE *srcrow;
234 const BYTE *srcbyte;
235 BYTE *dstrow;
236 DWORD *dstpixel;
237 WICColor colors[16];
238 IWICPalette *palette;
239 UINT actualcolors;
240
241 res = PaletteImpl_Create(&palette);
242 if (FAILED(res)) return res;
243
244 if (source_format == format_4bppIndexed)
245 res = IWICBitmapSource_CopyPalette(This->source, palette);
246 else
247 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
248
249 if (SUCCEEDED(res))
250 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
251
252 IWICPalette_Release(palette);
253 if (FAILED(res)) return res;
254
255 srcstride = (prc->Width+1)/2;
256 srcdatasize = srcstride * prc->Height;
257
258 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
259 if (!srcdata) return E_OUTOFMEMORY;
260
261 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
262
263 if (SUCCEEDED(res))
264 {
265 srcrow = srcdata;
266 dstrow = pbBuffer;
267 for (y=0; y<prc->Height; y++) {
268 srcbyte = srcrow;
269 dstpixel=(DWORD*)dstrow;
270 for (x=0; x<prc->Width; x+=2) {
271 BYTE srcval;
272 srcval=*srcbyte++;
273 *dstpixel++ = colors[srcval>>4];
274 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf];
275 }
276 srcrow += srcstride;
277 dstrow += cbStride;
278 }
279 }
280
281 HeapFree(GetProcessHeap(), 0, srcdata);
282
283 return res;
284 }
285 return S_OK;
286 case format_8bppGray:
287 if (prc)
288 {
289 HRESULT res;
290 INT x, y;
291 BYTE *srcdata;
292 UINT srcstride, srcdatasize;
293 const BYTE *srcrow;
294 const BYTE *srcbyte;
295 BYTE *dstrow;
296 DWORD *dstpixel;
297
298 srcstride = prc->Width;
299 srcdatasize = srcstride * prc->Height;
300
301 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
302 if (!srcdata) return E_OUTOFMEMORY;
303
304 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
305
306 if (SUCCEEDED(res))
307 {
308 srcrow = srcdata;
309 dstrow = pbBuffer;
310 for (y=0; y<prc->Height; y++) {
311 srcbyte = srcrow;
312 dstpixel=(DWORD*)dstrow;
313 for (x=0; x<prc->Width; x++)
314 {
315 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
316 srcbyte++;
317 }
318 srcrow += srcstride;
319 dstrow += cbStride;
320 }
321 }
322
323 HeapFree(GetProcessHeap(), 0, srcdata);
324
325 return res;
326 }
327 return S_OK;
328 case format_8bppIndexed:
329 if (prc)
330 {
331 HRESULT res;
332 INT x, y;
333 BYTE *srcdata;
334 UINT srcstride, srcdatasize;
335 const BYTE *srcrow;
336 const BYTE *srcbyte;
337 BYTE *dstrow;
338 DWORD *dstpixel;
339 WICColor colors[256];
340 IWICPalette *palette;
341 UINT actualcolors;
342
343 res = PaletteImpl_Create(&palette);
344 if (FAILED(res)) return res;
345
346 res = IWICBitmapSource_CopyPalette(This->source, palette);
347 if (SUCCEEDED(res))
348 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors);
349
350 IWICPalette_Release(palette);
351
352 if (FAILED(res)) return res;
353
354 srcstride = prc->Width;
355 srcdatasize = srcstride * prc->Height;
356
357 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
358 if (!srcdata) return E_OUTOFMEMORY;
359
360 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
361
362 if (SUCCEEDED(res))
363 {
364 srcrow = srcdata;
365 dstrow = pbBuffer;
366 for (y=0; y<prc->Height; y++) {
367 srcbyte = srcrow;
368 dstpixel=(DWORD*)dstrow;
369 for (x=0; x<prc->Width; x++)
370 *dstpixel++ = colors[*srcbyte++];
371 srcrow += srcstride;
372 dstrow += cbStride;
373 }
374 }
375
376 HeapFree(GetProcessHeap(), 0, srcdata);
377
378 return res;
379 }
380 return S_OK;
381 case format_16bppGray:
382 if (prc)
383 {
384 HRESULT res;
385 INT x, y;
386 BYTE *srcdata;
387 UINT srcstride, srcdatasize;
388 const BYTE *srcrow;
389 const BYTE *srcbyte;
390 BYTE *dstrow;
391 DWORD *dstpixel;
392
393 srcstride = prc->Width * 2;
394 srcdatasize = srcstride * prc->Height;
395
396 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
397 if (!srcdata) return E_OUTOFMEMORY;
398
399 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
400
401 if (SUCCEEDED(res))
402 {
403 srcrow = srcdata;
404 dstrow = pbBuffer;
405 for (y=0; y<prc->Height; y++) {
406 srcbyte = srcrow;
407 dstpixel=(DWORD*)dstrow;
408 for (x=0; x<prc->Width; x++)
409 {
410 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte;
411 srcbyte+=2;
412 }
413 srcrow += srcstride;
414 dstrow += cbStride;
415 }
416 }
417
418 HeapFree(GetProcessHeap(), 0, srcdata);
419
420 return res;
421 }
422 return S_OK;
423 case format_16bppBGR555:
424 if (prc)
425 {
426 HRESULT res;
427 INT x, y;
428 BYTE *srcdata;
429 UINT srcstride, srcdatasize;
430 const BYTE *srcrow;
431 const WORD *srcpixel;
432 BYTE *dstrow;
433 DWORD *dstpixel;
434
435 srcstride = 2 * prc->Width;
436 srcdatasize = srcstride * prc->Height;
437
438 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
439 if (!srcdata) return E_OUTOFMEMORY;
440
441 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
442
443 if (SUCCEEDED(res))
444 {
445 srcrow = srcdata;
446 dstrow = pbBuffer;
447 for (y=0; y<prc->Height; y++) {
448 srcpixel=(const WORD*)srcrow;
449 dstpixel=(DWORD*)dstrow;
450 for (x=0; x<prc->Width; x++) {
451 WORD srcval;
452 srcval=*srcpixel++;
453 *dstpixel++=0xff000000 | /* constant 255 alpha */
454 ((srcval << 9) & 0xf80000) | /* r */
455 ((srcval << 4) & 0x070000) | /* r - 3 bits */
456 ((srcval << 6) & 0x00f800) | /* g */
457 ((srcval << 1) & 0x000700) | /* g - 3 bits */
458 ((srcval << 3) & 0x0000f8) | /* b */
459 ((srcval >> 2) & 0x000007); /* b - 3 bits */
460 }
461 srcrow += srcstride;
462 dstrow += cbStride;
463 }
464 }
465
466 HeapFree(GetProcessHeap(), 0, srcdata);
467
468 return res;
469 }
470 return S_OK;
471 case format_16bppBGR565:
472 if (prc)
473 {
474 HRESULT res;
475 INT x, y;
476 BYTE *srcdata;
477 UINT srcstride, srcdatasize;
478 const BYTE *srcrow;
479 const WORD *srcpixel;
480 BYTE *dstrow;
481 DWORD *dstpixel;
482
483 srcstride = 2 * prc->Width;
484 srcdatasize = srcstride * prc->Height;
485
486 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
487 if (!srcdata) return E_OUTOFMEMORY;
488
489 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
490
491 if (SUCCEEDED(res))
492 {
493 srcrow = srcdata;
494 dstrow = pbBuffer;
495 for (y=0; y<prc->Height; y++) {
496 srcpixel=(const WORD*)srcrow;
497 dstpixel=(DWORD*)dstrow;
498 for (x=0; x<prc->Width; x++) {
499 WORD srcval;
500 srcval=*srcpixel++;
501 *dstpixel++=0xff000000 | /* constant 255 alpha */
502 ((srcval << 8) & 0xf80000) | /* r */
503 ((srcval << 3) & 0x070000) | /* r - 3 bits */
504 ((srcval << 5) & 0x00fc00) | /* g */
505 ((srcval >> 1) & 0x000300) | /* g - 2 bits */
506 ((srcval << 3) & 0x0000f8) | /* b */
507 ((srcval >> 2) & 0x000007); /* b - 3 bits */
508 }
509 srcrow += srcstride;
510 dstrow += cbStride;
511 }
512 }
513
514 HeapFree(GetProcessHeap(), 0, srcdata);
515
516 return res;
517 }
518 return S_OK;
519 case format_16bppBGRA5551:
520 if (prc)
521 {
522 HRESULT res;
523 INT x, y;
524 BYTE *srcdata;
525 UINT srcstride, srcdatasize;
526 const BYTE *srcrow;
527 const WORD *srcpixel;
528 BYTE *dstrow;
529 DWORD *dstpixel;
530
531 srcstride = 2 * prc->Width;
532 srcdatasize = srcstride * prc->Height;
533
534 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
535 if (!srcdata) return E_OUTOFMEMORY;
536
537 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
538
539 if (SUCCEEDED(res))
540 {
541 srcrow = srcdata;
542 dstrow = pbBuffer;
543 for (y=0; y<prc->Height; y++) {
544 srcpixel=(const WORD*)srcrow;
545 dstpixel=(DWORD*)dstrow;
546 for (x=0; x<prc->Width; x++) {
547 WORD srcval;
548 srcval=*srcpixel++;
549 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
550 ((srcval << 9) & 0xf80000) | /* r */
551 ((srcval << 4) & 0x070000) | /* r - 3 bits */
552 ((srcval << 6) & 0x00f800) | /* g */
553 ((srcval << 1) & 0x000700) | /* g - 3 bits */
554 ((srcval << 3) & 0x0000f8) | /* b */
555 ((srcval >> 2) & 0x000007); /* b - 3 bits */
556 }
557 srcrow += srcstride;
558 dstrow += cbStride;
559 }
560 }
561
562 HeapFree(GetProcessHeap(), 0, srcdata);
563
564 return res;
565 }
566 return S_OK;
567 case format_24bppBGR:
568 if (prc)
569 {
570 HRESULT res;
571 INT x, y;
572 BYTE *srcdata;
573 UINT srcstride, srcdatasize;
574 const BYTE *srcrow;
575 const BYTE *srcpixel;
576 BYTE *dstrow;
577 BYTE *dstpixel;
578
579 srcstride = 3 * prc->Width;
580 srcdatasize = srcstride * prc->Height;
581
582 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
583 if (!srcdata) return E_OUTOFMEMORY;
584
585 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
586
587 if (SUCCEEDED(res))
588 {
589 srcrow = srcdata;
590 dstrow = pbBuffer;
591 for (y=0; y<prc->Height; y++) {
592 srcpixel=srcrow;
593 dstpixel=dstrow;
594 for (x=0; x<prc->Width; x++) {
595 *dstpixel++=*srcpixel++; /* blue */
596 *dstpixel++=*srcpixel++; /* green */
597 *dstpixel++=*srcpixel++; /* red */
598 *dstpixel++=255; /* alpha */
599 }
600 srcrow += srcstride;
601 dstrow += cbStride;
602 }
603 }
604
605 HeapFree(GetProcessHeap(), 0, srcdata);
606
607 return res;
608 }
609 return S_OK;
610 case format_24bppRGB:
611 if (prc)
612 {
613 HRESULT res;
614 INT x, y;
615 BYTE *srcdata;
616 UINT srcstride, srcdatasize;
617 const BYTE *srcrow;
618 const BYTE *srcpixel;
619 BYTE *dstrow;
620 BYTE *dstpixel;
621 BYTE tmppixel[3];
622
623 srcstride = 3 * prc->Width;
624 srcdatasize = srcstride * prc->Height;
625
626 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
627 if (!srcdata) return E_OUTOFMEMORY;
628
629 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
630
631 if (SUCCEEDED(res))
632 {
633 srcrow = srcdata;
634 dstrow = pbBuffer;
635 for (y=0; y<prc->Height; y++) {
636 srcpixel=srcrow;
637 dstpixel=dstrow;
638 for (x=0; x<prc->Width; x++) {
639 tmppixel[0]=*srcpixel++; /* red */
640 tmppixel[1]=*srcpixel++; /* green */
641 tmppixel[2]=*srcpixel++; /* blue */
642
643 *dstpixel++=tmppixel[2]; /* blue */
644 *dstpixel++=tmppixel[1]; /* green */
645 *dstpixel++=tmppixel[0]; /* red */
646 *dstpixel++=255; /* alpha */
647 }
648 srcrow += srcstride;
649 dstrow += cbStride;
650 }
651 }
652
653 HeapFree(GetProcessHeap(), 0, srcdata);
654
655 return res;
656 }
657 return S_OK;
658 case format_32bppBGR:
659 if (prc)
660 {
661 HRESULT res;
662 INT x, y;
663
664 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
665 if (FAILED(res)) return res;
666
667 /* set all alpha values to 255 */
668 for (y=0; y<prc->Height; y++)
669 for (x=0; x<prc->Width; x++)
670 pbBuffer[cbStride*y+4*x+3] = 0xff;
671 }
672 return S_OK;
673 case format_32bppBGRA:
674 if (prc)
675 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
676 return S_OK;
677 case format_32bppPBGRA:
678 if (prc)
679 {
680 HRESULT res;
681 INT x, y;
682
683 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
684 if (FAILED(res)) return res;
685
686 for (y=0; y<prc->Height; y++)
687 for (x=0; x<prc->Width; x++)
688 {
689 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
690 if (alpha != 0 && alpha != 255)
691 {
692 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
693 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
694 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
695 }
696 }
697 }
698 return S_OK;
699 case format_48bppRGB:
700 if (prc)
701 {
702 HRESULT res;
703 INT x, y;
704 BYTE *srcdata;
705 UINT srcstride, srcdatasize;
706 const BYTE *srcrow;
707 const BYTE *srcpixel;
708 BYTE *dstrow;
709 DWORD *dstpixel;
710
711 srcstride = 6 * prc->Width;
712 srcdatasize = srcstride * prc->Height;
713
714 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
715 if (!srcdata) return E_OUTOFMEMORY;
716
717 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
718
719 if (SUCCEEDED(res))
720 {
721 srcrow = srcdata;
722 dstrow = pbBuffer;
723 for (y=0; y<prc->Height; y++) {
724 srcpixel=srcrow;
725 dstpixel=(DWORD*)dstrow;
726 for (x=0; x<prc->Width; x++) {
727 BYTE red, green, blue;
728 red = *srcpixel++; srcpixel++;
729 green = *srcpixel++; srcpixel++;
730 blue = *srcpixel++; srcpixel++;
731 *dstpixel++=0xff000000|red<<16|green<<8|blue;
732 }
733 srcrow += srcstride;
734 dstrow += cbStride;
735 }
736 }
737
738 HeapFree(GetProcessHeap(), 0, srcdata);
739
740 return res;
741 }
742 return S_OK;
743 case format_64bppRGBA:
744 if (prc)
745 {
746 HRESULT res;
747 INT x, y;
748 BYTE *srcdata;
749 UINT srcstride, srcdatasize;
750 const BYTE *srcrow;
751 const BYTE *srcpixel;
752 BYTE *dstrow;
753 DWORD *dstpixel;
754
755 srcstride = 8 * prc->Width;
756 srcdatasize = srcstride * prc->Height;
757
758 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
759 if (!srcdata) return E_OUTOFMEMORY;
760
761 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
762
763 if (SUCCEEDED(res))
764 {
765 srcrow = srcdata;
766 dstrow = pbBuffer;
767 for (y=0; y<prc->Height; y++) {
768 srcpixel=srcrow;
769 dstpixel=(DWORD*)dstrow;
770 for (x=0; x<prc->Width; x++) {
771 BYTE red, green, blue, alpha;
772 red = *srcpixel++; srcpixel++;
773 green = *srcpixel++; srcpixel++;
774 blue = *srcpixel++; srcpixel++;
775 alpha = *srcpixel++; srcpixel++;
776 *dstpixel++=alpha<<24|red<<16|green<<8|blue;
777 }
778 srcrow += srcstride;
779 dstrow += cbStride;
780 }
781 }
782
783 HeapFree(GetProcessHeap(), 0, srcdata);
784
785 return res;
786 }
787 return S_OK;
788 case format_32bppCMYK:
789 if (prc)
790 {
791 HRESULT res;
792 UINT x, y;
793
794 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
795 if (FAILED(res)) return res;
796
797 for (y=0; y<prc->Height; y++)
798 for (x=0; x<prc->Width; x++)
799 {
800 BYTE *pixel = pbBuffer+cbStride*y+4*x;
801 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
802 pixel[0] = (255-y)*(255-k)/255; /* blue */
803 pixel[1] = (255-m)*(255-k)/255; /* green */
804 pixel[2] = (255-c)*(255-k)/255; /* red */
805 pixel[3] = 255; /* alpha */
806 }
807 }
808 return S_OK;
809 default:
810 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
811 }
812 }
813
814 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc,
815 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
816 {
817 switch (source_format)
818 {
819 case format_32bppBGR:
820 case format_32bppBGRA:
821 case format_32bppPBGRA:
822 if (prc)
823 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
824 return S_OK;
825 default:
826 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
827 }
828 }
829
830 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
831 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
832 {
833 HRESULT hr;
834
835 switch (source_format)
836 {
837 case format_32bppPBGRA:
838 if (prc)
839 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
840 return S_OK;
841 default:
842 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
843 if (SUCCEEDED(hr) && prc)
844 {
845 INT x, y;
846
847 for (y=0; y<prc->Height; y++)
848 for (x=0; x<prc->Width; x++)
849 {
850 BYTE alpha = pbBuffer[cbStride*y+4*x+3];
851 if (alpha != 255)
852 {
853 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
854 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
855 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
856 }
857 }
858 }
859 return hr;
860 }
861 }
862
863 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc,
864 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
865 {
866 HRESULT hr;
867
868 switch (source_format)
869 {
870 case format_24bppBGR:
871 case format_24bppRGB:
872 if (prc)
873 {
874 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
875 if (SUCCEEDED(hr) && source_format == format_24bppRGB)
876 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
877 return hr;
878 }
879 return S_OK;
880 case format_32bppBGR:
881 case format_32bppBGRA:
882 case format_32bppPBGRA:
883 if (prc)
884 {
885 HRESULT res;
886 INT x, y;
887 BYTE *srcdata;
888 UINT srcstride, srcdatasize;
889 const BYTE *srcrow;
890 const BYTE *srcpixel;
891 BYTE *dstrow;
892 BYTE *dstpixel;
893
894 srcstride = 4 * prc->Width;
895 srcdatasize = srcstride * prc->Height;
896
897 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
898 if (!srcdata) return E_OUTOFMEMORY;
899
900 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
901
902 if (SUCCEEDED(res))
903 {
904 srcrow = srcdata;
905 dstrow = pbBuffer;
906 for (y=0; y<prc->Height; y++) {
907 srcpixel=srcrow;
908 dstpixel=dstrow;
909 for (x=0; x<prc->Width; x++) {
910 *dstpixel++=*srcpixel++; /* blue */
911 *dstpixel++=*srcpixel++; /* green */
912 *dstpixel++=*srcpixel++; /* red */
913 srcpixel++; /* alpha */
914 }
915 srcrow += srcstride;
916 dstrow += cbStride;
917 }
918 }
919
920 HeapFree(GetProcessHeap(), 0, srcdata);
921
922 return res;
923 }
924 return S_OK;
925 default:
926 FIXME("Unimplemented conversion path!\n");
927 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
928 }
929 }
930
931 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc,
932 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
933 {
934 HRESULT hr;
935
936 switch (source_format)
937 {
938 case format_24bppBGR:
939 case format_24bppRGB:
940 if (prc)
941 {
942 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
943 if (SUCCEEDED(hr) && source_format == format_24bppBGR)
944 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
945 return hr;
946 }
947 return S_OK;
948 case format_32bppBGR:
949 case format_32bppBGRA:
950 case format_32bppPBGRA:
951 if (prc)
952 {
953 HRESULT res;
954 INT x, y;
955 BYTE *srcdata;
956 UINT srcstride, srcdatasize;
957 const BYTE *srcrow;
958 const BYTE *srcpixel;
959 BYTE *dstrow;
960 BYTE *dstpixel;
961
962 srcstride = 4 * prc->Width;
963 srcdatasize = srcstride * prc->Height;
964
965 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
966 if (!srcdata) return E_OUTOFMEMORY;
967
968 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
969
970 if (SUCCEEDED(res))
971 {
972 srcrow = srcdata;
973 dstrow = pbBuffer;
974 for (y=0; y<prc->Height; y++) {
975 srcpixel=srcrow;
976 dstpixel=dstrow;
977 for (x=0; x<prc->Width; x++) {
978 *dstpixel++=*srcpixel++; /* blue */
979 *dstpixel++=*srcpixel++; /* green */
980 *dstpixel++=*srcpixel++; /* red */
981 srcpixel++; /* alpha */
982 }
983 srcrow += srcstride;
984 dstrow += cbStride;
985 }
986
987 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride);
988 }
989
990 HeapFree(GetProcessHeap(), 0, srcdata);
991
992 return res;
993 }
994 return S_OK;
995 default:
996 FIXME("Unimplemented conversion path!\n");
997 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
998 }
999 }
1000
1001 static const struct pixelformatinfo supported_formats[] = {
1002 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
1003 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
1004 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL},
1005 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL},
1006 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL},
1007 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL},
1008 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL},
1009 {format_8bppGray, &GUID_WICPixelFormat8bppGray, NULL},
1010 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
1011 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
1012 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
1013 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
1014 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR},
1015 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB},
1016 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
1017 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
1018 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
1019 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
1020 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
1021 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
1022 {0}
1023 };
1024
1025 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format)
1026 {
1027 UINT i;
1028
1029 for (i=0; supported_formats[i].guid; i++)
1030 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i];
1031
1032 return NULL;
1033 }
1034
1035 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
1036 void **ppv)
1037 {
1038 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1039 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1040
1041 if (!ppv) return E_INVALIDARG;
1042
1043 if (IsEqualIID(&IID_IUnknown, iid) ||
1044 IsEqualIID(&IID_IWICBitmapSource, iid) ||
1045 IsEqualIID(&IID_IWICFormatConverter, iid))
1046 {
1047 *ppv = &This->IWICFormatConverter_iface;
1048 }
1049 else
1050 {
1051 *ppv = NULL;
1052 return E_NOINTERFACE;
1053 }
1054
1055 IUnknown_AddRef((IUnknown*)*ppv);
1056 return S_OK;
1057 }
1058
1059 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
1060 {
1061 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1062 ULONG ref = InterlockedIncrement(&This->ref);
1063
1064 TRACE("(%p) refcount=%u\n", iface, ref);
1065
1066 return ref;
1067 }
1068
1069 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
1070 {
1071 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1072 ULONG ref = InterlockedDecrement(&This->ref);
1073
1074 TRACE("(%p) refcount=%u\n", iface, ref);
1075
1076 if (ref == 0)
1077 {
1078 This->lock.DebugInfo->Spare[0] = 0;
1079 DeleteCriticalSection(&This->lock);
1080 if (This->source) IWICBitmapSource_Release(This->source);
1081 HeapFree(GetProcessHeap(), 0, This);
1082 }
1083
1084 return ref;
1085 }
1086
1087 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
1088 UINT *puiWidth, UINT *puiHeight)
1089 {
1090 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1091
1092 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
1093
1094 if (This->source)
1095 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight);
1096 else
1097 return WINCODEC_ERR_NOTINITIALIZED;
1098 }
1099
1100 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
1101 WICPixelFormatGUID *pPixelFormat)
1102 {
1103 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1104
1105 TRACE("(%p,%p): stub\n", iface, pPixelFormat);
1106
1107 if (This->source)
1108 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID));
1109 else
1110 return WINCODEC_ERR_NOTINITIALIZED;
1111
1112 return S_OK;
1113 }
1114
1115 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
1116 double *pDpiX, double *pDpiY)
1117 {
1118 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1119
1120 TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
1121
1122 if (This->source)
1123 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
1124 else
1125 return WINCODEC_ERR_NOTINITIALIZED;
1126 }
1127
1128 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
1129 IWICPalette *pIPalette)
1130 {
1131 FIXME("(%p,%p): stub\n", iface, pIPalette);
1132 return E_NOTIMPL;
1133 }
1134
1135 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
1136 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
1137 {
1138 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1139 WICRect rc;
1140 HRESULT hr;
1141 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
1142
1143 if (This->source)
1144 {
1145 if (!prc)
1146 {
1147 UINT width, height;
1148 hr = IWICBitmapSource_GetSize(This->source, &width, &height);
1149 if (FAILED(hr)) return hr;
1150 rc.X = 0;
1151 rc.Y = 0;
1152 rc.Width = width;
1153 rc.Height = height;
1154 prc = &rc;
1155 }
1156
1157 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
1158 pbBuffer, This->src_format->format);
1159 }
1160 else
1161 return WINCODEC_ERR_NOTINITIALIZED;
1162 }
1163
1164 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
1165 IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
1166 IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
1167 {
1168 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1169 const struct pixelformatinfo *srcinfo, *dstinfo;
1170 static INT fixme=0;
1171 GUID srcFormat;
1172 HRESULT res=S_OK;
1173
1174 TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat),
1175 dither, pIPalette, alphaThresholdPercent, paletteTranslate);
1176
1177 if (pIPalette && !fixme++) FIXME("ignoring palette\n");
1178
1179 EnterCriticalSection(&This->lock);
1180
1181 if (This->source)
1182 {
1183 res = WINCODEC_ERR_WRONGSTATE;
1184 goto end;
1185 }
1186
1187 res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat);
1188 if (FAILED(res)) goto end;
1189
1190 srcinfo = get_formatinfo(&srcFormat);
1191 if (!srcinfo)
1192 {
1193 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1194 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
1195 goto end;
1196 }
1197
1198 dstinfo = get_formatinfo(dstFormat);
1199 if (!dstinfo)
1200 {
1201 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1202 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
1203 goto end;
1204 }
1205
1206 if (dstinfo->copy_function)
1207 {
1208 IWICBitmapSource_AddRef(pISource);
1209 This->src_format = srcinfo;
1210 This->dst_format = dstinfo;
1211 This->dither = dither;
1212 This->alpha_threshold = alphaThresholdPercent;
1213 This->palette_type = paletteTranslate;
1214 This->source = pISource;
1215 }
1216 else
1217 {
1218 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
1219 res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
1220 }
1221
1222 end:
1223
1224 LeaveCriticalSection(&This->lock);
1225
1226 return res;
1227 }
1228
1229 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
1230 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
1231 BOOL *pfCanConvert)
1232 {
1233 FormatConverter *This = impl_from_IWICFormatConverter(iface);
1234 const struct pixelformatinfo *srcinfo, *dstinfo;
1235
1236 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
1237 debugstr_guid(dstPixelFormat), pfCanConvert);
1238
1239 srcinfo = get_formatinfo(srcPixelFormat);
1240 if (!srcinfo)
1241 {
1242 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
1243 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1244 }
1245
1246 dstinfo = get_formatinfo(dstPixelFormat);
1247 if (!dstinfo)
1248 {
1249 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
1250 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
1251 }
1252
1253 if (dstinfo->copy_function &&
1254 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
1255 *pfCanConvert = TRUE;
1256 else
1257 {
1258 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
1259 *pfCanConvert = FALSE;
1260 }
1261
1262 return S_OK;
1263 }
1264
1265 static const IWICFormatConverterVtbl FormatConverter_Vtbl = {
1266 FormatConverter_QueryInterface,
1267 FormatConverter_AddRef,
1268 FormatConverter_Release,
1269 FormatConverter_GetSize,
1270 FormatConverter_GetPixelFormat,
1271 FormatConverter_GetResolution,
1272 FormatConverter_CopyPalette,
1273 FormatConverter_CopyPixels,
1274 FormatConverter_Initialize,
1275 FormatConverter_CanConvert
1276 };
1277
1278 HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
1279 {
1280 FormatConverter *This;
1281 HRESULT ret;
1282
1283 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
1284
1285 *ppv = NULL;
1286
1287 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
1288
1289 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
1290 if (!This) return E_OUTOFMEMORY;
1291
1292 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
1293 This->ref = 1;
1294 This->source = NULL;
1295 InitializeCriticalSection(&This->lock);
1296 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
1297
1298 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
1299 IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
1300
1301 return ret;
1302 }