1 /* 2 * Copyright 2009 Vincent Povirk 3 * Copyright 2016 Dmitry Timoshkov 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include "config.h" 21 22 #include <stdarg.h> 23 #include <math.h> 24 25 #define COBJMACROS 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "objbase.h" 30 31 #include "wincodecs_private.h" 32 33 #include "wine/heap.h" 34 #include "wine/debug.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 37 38 struct FormatConverter; 39 40 enum pixelformat { 41 format_1bppIndexed, 42 format_2bppIndexed, 43 format_4bppIndexed, 44 format_8bppIndexed, 45 format_BlackWhite, 46 format_2bppGray, 47 format_4bppGray, 48 format_8bppGray, 49 format_16bppGray, 50 format_16bppBGR555, 51 format_16bppBGR565, 52 format_16bppBGRA5551, 53 format_24bppBGR, 54 format_24bppRGB, 55 format_32bppGrayFloat, 56 format_32bppBGR, 57 format_32bppRGB, 58 format_32bppBGRA, 59 format_32bppRGBA, 60 format_32bppPBGRA, 61 format_32bppPRGBA, 62 format_48bppRGB, 63 format_64bppRGBA, 64 format_32bppCMYK, 65 }; 66 67 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc, 68 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format); 69 70 struct pixelformatinfo { 71 enum pixelformat format; 72 const WICPixelFormatGUID *guid; 73 copyfunc copy_function; 74 }; 75 76 typedef struct FormatConverter { 77 IWICFormatConverter IWICFormatConverter_iface; 78 LONG ref; 79 IWICBitmapSource *source; 80 const struct pixelformatinfo *dst_format, *src_format; 81 WICBitmapDitherType dither; 82 double alpha_threshold; 83 IWICPalette *palette; 84 CRITICAL_SECTION lock; /* must be held when initialized */ 85 } FormatConverter; 86 87 /* https://www.w3.org/Graphics/Color/srgb */ 88 static inline float to_sRGB_component(float f) 89 { 90 if (f <= 0.0031308f) return 12.92f * f; 91 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f; 92 } 93 94 #if 0 /* FIXME: enable once needed */ 95 static inline float from_sRGB_component(float f) 96 { 97 if (f <= 0.04045f) return f / 12.92f; 98 return powf((f + 0.055f) / 1.055f, 2.4f); 99 } 100 101 static void from_sRGB(BYTE *bgr) 102 { 103 float r, g, b; 104 105 r = bgr[2] / 255.0f; 106 g = bgr[1] / 255.0f; 107 b = bgr[0] / 255.0f; 108 109 r = from_sRGB_component(r); 110 g = from_sRGB_component(g); 111 b = from_sRGB_component(b); 112 113 bgr[2] = (BYTE)(r * 255.0f); 114 bgr[1] = (BYTE)(g * 255.0f); 115 bgr[0] = (BYTE)(b * 255.0f); 116 } 117 118 static void to_sRGB(BYTE *bgr) 119 { 120 float r, g, b; 121 122 r = bgr[2] / 255.0f; 123 g = bgr[1] / 255.0f; 124 b = bgr[0] / 255.0f; 125 126 r = to_sRGB_component(r); 127 g = to_sRGB_component(g); 128 b = to_sRGB_component(b); 129 130 bgr[2] = (BYTE)(r * 255.0f); 131 bgr[1] = (BYTE)(g * 255.0f); 132 bgr[0] = (BYTE)(b * 255.0f); 133 } 134 #endif 135 136 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface) 137 { 138 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface); 139 } 140 141 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc, 142 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 143 { 144 switch (source_format) 145 { 146 case format_1bppIndexed: 147 case format_BlackWhite: 148 if (prc) 149 { 150 HRESULT res; 151 INT x, y; 152 BYTE *srcdata; 153 UINT srcstride, srcdatasize; 154 const BYTE *srcrow; 155 const BYTE *srcbyte; 156 BYTE *dstrow; 157 DWORD *dstpixel; 158 WICColor colors[2]; 159 IWICPalette *palette; 160 UINT actualcolors; 161 162 res = PaletteImpl_Create(&palette); 163 if (FAILED(res)) return res; 164 165 if (source_format == format_1bppIndexed) 166 res = IWICBitmapSource_CopyPalette(This->source, palette); 167 else 168 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE); 169 170 if (SUCCEEDED(res)) 171 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors); 172 173 IWICPalette_Release(palette); 174 if (FAILED(res)) return res; 175 176 srcstride = (prc->Width+7)/8; 177 srcdatasize = srcstride * prc->Height; 178 179 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 180 if (!srcdata) return E_OUTOFMEMORY; 181 182 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 183 184 if (SUCCEEDED(res)) 185 { 186 srcrow = srcdata; 187 dstrow = pbBuffer; 188 for (y=0; y<prc->Height; y++) { 189 srcbyte = srcrow; 190 dstpixel=(DWORD*)dstrow; 191 for (x=0; x<prc->Width; x+=8) { 192 BYTE srcval; 193 srcval=*srcbyte++; 194 *dstpixel++ = colors[srcval>>7&1]; 195 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1]; 196 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1]; 197 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1]; 198 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1]; 199 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1]; 200 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1]; 201 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1]; 202 } 203 srcrow += srcstride; 204 dstrow += cbStride; 205 } 206 } 207 208 HeapFree(GetProcessHeap(), 0, srcdata); 209 210 return res; 211 } 212 return S_OK; 213 case format_2bppIndexed: 214 case format_2bppGray: 215 if (prc) 216 { 217 HRESULT res; 218 INT x, y; 219 BYTE *srcdata; 220 UINT srcstride, srcdatasize; 221 const BYTE *srcrow; 222 const BYTE *srcbyte; 223 BYTE *dstrow; 224 DWORD *dstpixel; 225 WICColor colors[4]; 226 IWICPalette *palette; 227 UINT actualcolors; 228 229 res = PaletteImpl_Create(&palette); 230 if (FAILED(res)) return res; 231 232 if (source_format == format_2bppIndexed) 233 res = IWICBitmapSource_CopyPalette(This->source, palette); 234 else 235 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE); 236 237 if (SUCCEEDED(res)) 238 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors); 239 240 IWICPalette_Release(palette); 241 if (FAILED(res)) return res; 242 243 srcstride = (prc->Width+3)/4; 244 srcdatasize = srcstride * prc->Height; 245 246 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 247 if (!srcdata) return E_OUTOFMEMORY; 248 249 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 250 251 if (SUCCEEDED(res)) 252 { 253 srcrow = srcdata; 254 dstrow = pbBuffer; 255 for (y=0; y<prc->Height; y++) { 256 srcbyte = srcrow; 257 dstpixel=(DWORD*)dstrow; 258 for (x=0; x<prc->Width; x+=4) { 259 BYTE srcval; 260 srcval=*srcbyte++; 261 *dstpixel++ = colors[srcval>>6]; 262 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3]; 263 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3]; 264 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3]; 265 } 266 srcrow += srcstride; 267 dstrow += cbStride; 268 } 269 } 270 271 HeapFree(GetProcessHeap(), 0, srcdata); 272 273 return res; 274 } 275 return S_OK; 276 case format_4bppIndexed: 277 case format_4bppGray: 278 if (prc) 279 { 280 HRESULT res; 281 INT x, y; 282 BYTE *srcdata; 283 UINT srcstride, srcdatasize; 284 const BYTE *srcrow; 285 const BYTE *srcbyte; 286 BYTE *dstrow; 287 DWORD *dstpixel; 288 WICColor colors[16]; 289 IWICPalette *palette; 290 UINT actualcolors; 291 292 res = PaletteImpl_Create(&palette); 293 if (FAILED(res)) return res; 294 295 if (source_format == format_4bppIndexed) 296 res = IWICBitmapSource_CopyPalette(This->source, palette); 297 else 298 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE); 299 300 if (SUCCEEDED(res)) 301 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors); 302 303 IWICPalette_Release(palette); 304 if (FAILED(res)) return res; 305 306 srcstride = (prc->Width+1)/2; 307 srcdatasize = srcstride * prc->Height; 308 309 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 310 if (!srcdata) return E_OUTOFMEMORY; 311 312 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 313 314 if (SUCCEEDED(res)) 315 { 316 srcrow = srcdata; 317 dstrow = pbBuffer; 318 for (y=0; y<prc->Height; y++) { 319 srcbyte = srcrow; 320 dstpixel=(DWORD*)dstrow; 321 for (x=0; x<prc->Width; x+=2) { 322 BYTE srcval; 323 srcval=*srcbyte++; 324 *dstpixel++ = colors[srcval>>4]; 325 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf]; 326 } 327 srcrow += srcstride; 328 dstrow += cbStride; 329 } 330 } 331 332 HeapFree(GetProcessHeap(), 0, srcdata); 333 334 return res; 335 } 336 return S_OK; 337 case format_8bppGray: 338 if (prc) 339 { 340 HRESULT res; 341 INT x, y; 342 BYTE *srcdata; 343 UINT srcstride, srcdatasize; 344 const BYTE *srcrow; 345 const BYTE *srcbyte; 346 BYTE *dstrow; 347 DWORD *dstpixel; 348 349 srcstride = prc->Width; 350 srcdatasize = srcstride * prc->Height; 351 352 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 353 if (!srcdata) return E_OUTOFMEMORY; 354 355 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 356 357 if (SUCCEEDED(res)) 358 { 359 srcrow = srcdata; 360 dstrow = pbBuffer; 361 for (y=0; y<prc->Height; y++) { 362 srcbyte = srcrow; 363 dstpixel=(DWORD*)dstrow; 364 for (x=0; x<prc->Width; x++) 365 { 366 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte; 367 srcbyte++; 368 } 369 srcrow += srcstride; 370 dstrow += cbStride; 371 } 372 } 373 374 HeapFree(GetProcessHeap(), 0, srcdata); 375 376 return res; 377 } 378 return S_OK; 379 case format_8bppIndexed: 380 if (prc) 381 { 382 HRESULT res; 383 INT x, y; 384 BYTE *srcdata; 385 UINT srcstride, srcdatasize; 386 const BYTE *srcrow; 387 const BYTE *srcbyte; 388 BYTE *dstrow; 389 DWORD *dstpixel; 390 WICColor colors[256]; 391 IWICPalette *palette; 392 UINT actualcolors; 393 394 res = PaletteImpl_Create(&palette); 395 if (FAILED(res)) return res; 396 397 res = IWICBitmapSource_CopyPalette(This->source, palette); 398 if (SUCCEEDED(res)) 399 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors); 400 401 IWICPalette_Release(palette); 402 403 if (FAILED(res)) return res; 404 405 srcstride = prc->Width; 406 srcdatasize = srcstride * prc->Height; 407 408 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 409 if (!srcdata) return E_OUTOFMEMORY; 410 411 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 412 413 if (SUCCEEDED(res)) 414 { 415 srcrow = srcdata; 416 dstrow = pbBuffer; 417 for (y=0; y<prc->Height; y++) { 418 srcbyte = srcrow; 419 dstpixel=(DWORD*)dstrow; 420 for (x=0; x<prc->Width; x++) 421 *dstpixel++ = colors[*srcbyte++]; 422 srcrow += srcstride; 423 dstrow += cbStride; 424 } 425 } 426 427 HeapFree(GetProcessHeap(), 0, srcdata); 428 429 return res; 430 } 431 return S_OK; 432 case format_16bppGray: 433 if (prc) 434 { 435 HRESULT res; 436 INT x, y; 437 BYTE *srcdata; 438 UINT srcstride, srcdatasize; 439 const BYTE *srcrow; 440 const BYTE *srcbyte; 441 BYTE *dstrow; 442 DWORD *dstpixel; 443 444 srcstride = prc->Width * 2; 445 srcdatasize = srcstride * prc->Height; 446 447 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 448 if (!srcdata) return E_OUTOFMEMORY; 449 450 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 451 452 if (SUCCEEDED(res)) 453 { 454 srcrow = srcdata; 455 dstrow = pbBuffer; 456 for (y=0; y<prc->Height; y++) { 457 srcbyte = srcrow; 458 dstpixel=(DWORD*)dstrow; 459 for (x=0; x<prc->Width; x++) 460 { 461 srcbyte++; 462 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte; 463 srcbyte++; 464 } 465 srcrow += srcstride; 466 dstrow += cbStride; 467 } 468 } 469 470 HeapFree(GetProcessHeap(), 0, srcdata); 471 472 return res; 473 } 474 return S_OK; 475 case format_16bppBGR555: 476 if (prc) 477 { 478 HRESULT res; 479 INT x, y; 480 BYTE *srcdata; 481 UINT srcstride, srcdatasize; 482 const BYTE *srcrow; 483 const WORD *srcpixel; 484 BYTE *dstrow; 485 DWORD *dstpixel; 486 487 srcstride = 2 * prc->Width; 488 srcdatasize = srcstride * prc->Height; 489 490 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 491 if (!srcdata) return E_OUTOFMEMORY; 492 493 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 494 495 if (SUCCEEDED(res)) 496 { 497 srcrow = srcdata; 498 dstrow = pbBuffer; 499 for (y=0; y<prc->Height; y++) { 500 srcpixel=(const WORD*)srcrow; 501 dstpixel=(DWORD*)dstrow; 502 for (x=0; x<prc->Width; x++) { 503 WORD srcval; 504 srcval=*srcpixel++; 505 *dstpixel++=0xff000000 | /* constant 255 alpha */ 506 ((srcval << 9) & 0xf80000) | /* r */ 507 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 508 ((srcval << 6) & 0x00f800) | /* g */ 509 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 510 ((srcval << 3) & 0x0000f8) | /* b */ 511 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 512 } 513 srcrow += srcstride; 514 dstrow += cbStride; 515 } 516 } 517 518 HeapFree(GetProcessHeap(), 0, srcdata); 519 520 return res; 521 } 522 return S_OK; 523 case format_16bppBGR565: 524 if (prc) 525 { 526 HRESULT res; 527 INT x, y; 528 BYTE *srcdata; 529 UINT srcstride, srcdatasize; 530 const BYTE *srcrow; 531 const WORD *srcpixel; 532 BYTE *dstrow; 533 DWORD *dstpixel; 534 535 srcstride = 2 * prc->Width; 536 srcdatasize = srcstride * prc->Height; 537 538 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 539 if (!srcdata) return E_OUTOFMEMORY; 540 541 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 542 543 if (SUCCEEDED(res)) 544 { 545 srcrow = srcdata; 546 dstrow = pbBuffer; 547 for (y=0; y<prc->Height; y++) { 548 srcpixel=(const WORD*)srcrow; 549 dstpixel=(DWORD*)dstrow; 550 for (x=0; x<prc->Width; x++) { 551 WORD srcval; 552 srcval=*srcpixel++; 553 *dstpixel++=0xff000000 | /* constant 255 alpha */ 554 ((srcval << 8) & 0xf80000) | /* r */ 555 ((srcval << 3) & 0x070000) | /* r - 3 bits */ 556 ((srcval << 5) & 0x00fc00) | /* g */ 557 ((srcval >> 1) & 0x000300) | /* g - 2 bits */ 558 ((srcval << 3) & 0x0000f8) | /* b */ 559 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 560 } 561 srcrow += srcstride; 562 dstrow += cbStride; 563 } 564 } 565 566 HeapFree(GetProcessHeap(), 0, srcdata); 567 568 return res; 569 } 570 return S_OK; 571 case format_16bppBGRA5551: 572 if (prc) 573 { 574 HRESULT res; 575 INT x, y; 576 BYTE *srcdata; 577 UINT srcstride, srcdatasize; 578 const BYTE *srcrow; 579 const WORD *srcpixel; 580 BYTE *dstrow; 581 DWORD *dstpixel; 582 583 srcstride = 2 * prc->Width; 584 srcdatasize = srcstride * prc->Height; 585 586 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 587 if (!srcdata) return E_OUTOFMEMORY; 588 589 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 590 591 if (SUCCEEDED(res)) 592 { 593 srcrow = srcdata; 594 dstrow = pbBuffer; 595 for (y=0; y<prc->Height; y++) { 596 srcpixel=(const WORD*)srcrow; 597 dstpixel=(DWORD*)dstrow; 598 for (x=0; x<prc->Width; x++) { 599 WORD srcval; 600 srcval=*srcpixel++; 601 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */ 602 ((srcval << 9) & 0xf80000) | /* r */ 603 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 604 ((srcval << 6) & 0x00f800) | /* g */ 605 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 606 ((srcval << 3) & 0x0000f8) | /* b */ 607 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 608 } 609 srcrow += srcstride; 610 dstrow += cbStride; 611 } 612 } 613 614 HeapFree(GetProcessHeap(), 0, srcdata); 615 616 return res; 617 } 618 return S_OK; 619 case format_24bppBGR: 620 if (prc) 621 { 622 HRESULT res; 623 INT x, y; 624 BYTE *srcdata; 625 UINT srcstride, srcdatasize; 626 const BYTE *srcrow; 627 const BYTE *srcpixel; 628 BYTE *dstrow; 629 BYTE *dstpixel; 630 631 srcstride = 3 * prc->Width; 632 srcdatasize = srcstride * prc->Height; 633 634 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 635 if (!srcdata) return E_OUTOFMEMORY; 636 637 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 638 639 if (SUCCEEDED(res)) 640 { 641 srcrow = srcdata; 642 dstrow = pbBuffer; 643 for (y=0; y<prc->Height; y++) { 644 srcpixel=srcrow; 645 dstpixel=dstrow; 646 for (x=0; x<prc->Width; x++) { 647 *dstpixel++=*srcpixel++; /* blue */ 648 *dstpixel++=*srcpixel++; /* green */ 649 *dstpixel++=*srcpixel++; /* red */ 650 *dstpixel++=255; /* alpha */ 651 } 652 srcrow += srcstride; 653 dstrow += cbStride; 654 } 655 } 656 657 HeapFree(GetProcessHeap(), 0, srcdata); 658 659 return res; 660 } 661 return S_OK; 662 case format_24bppRGB: 663 if (prc) 664 { 665 HRESULT res; 666 INT x, y; 667 BYTE *srcdata; 668 UINT srcstride, srcdatasize; 669 const BYTE *srcrow; 670 const BYTE *srcpixel; 671 BYTE *dstrow; 672 BYTE *dstpixel; 673 BYTE tmppixel[3]; 674 675 srcstride = 3 * prc->Width; 676 srcdatasize = srcstride * prc->Height; 677 678 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 679 if (!srcdata) return E_OUTOFMEMORY; 680 681 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 682 683 if (SUCCEEDED(res)) 684 { 685 srcrow = srcdata; 686 dstrow = pbBuffer; 687 for (y=0; y<prc->Height; y++) { 688 srcpixel=srcrow; 689 dstpixel=dstrow; 690 for (x=0; x<prc->Width; x++) { 691 tmppixel[0]=*srcpixel++; /* red */ 692 tmppixel[1]=*srcpixel++; /* green */ 693 tmppixel[2]=*srcpixel++; /* blue */ 694 695 *dstpixel++=tmppixel[2]; /* blue */ 696 *dstpixel++=tmppixel[1]; /* green */ 697 *dstpixel++=tmppixel[0]; /* red */ 698 *dstpixel++=255; /* alpha */ 699 } 700 srcrow += srcstride; 701 dstrow += cbStride; 702 } 703 } 704 705 HeapFree(GetProcessHeap(), 0, srcdata); 706 707 return res; 708 } 709 return S_OK; 710 case format_32bppBGR: 711 if (prc) 712 { 713 HRESULT res; 714 INT x, y; 715 716 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 717 if (FAILED(res)) return res; 718 719 /* set all alpha values to 255 */ 720 for (y=0; y<prc->Height; y++) 721 for (x=0; x<prc->Width; x++) 722 pbBuffer[cbStride*y+4*x+3] = 0xff; 723 } 724 return S_OK; 725 case format_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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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