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