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