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 #ifndef __REACTOS__ 89 static inline float from_sRGB_component(float f) 90 { 91 if (f <= 0.04045f) return f / 12.92f; 92 return powf((f + 0.055f) / 1.055f, 2.4f); 93 } 94 #endif 95 96 static inline float to_sRGB_component(float f) 97 { 98 if (f <= 0.0031308f) return 12.92f * f; 99 return 1.055f * powf(f, 1.0f/2.4f) - 0.055f; 100 } 101 102 #if 0 /* FIXME: enable once needed */ 103 static void from_sRGB(BYTE *bgr) 104 { 105 float r, g, b; 106 107 r = bgr[2] / 255.0f; 108 g = bgr[1] / 255.0f; 109 b = bgr[0] / 255.0f; 110 111 r = from_sRGB_component(r); 112 g = from_sRGB_component(g); 113 b = from_sRGB_component(b); 114 115 bgr[2] = (BYTE)(r * 255.0f); 116 bgr[1] = (BYTE)(g * 255.0f); 117 bgr[0] = (BYTE)(b * 255.0f); 118 } 119 120 static void to_sRGB(BYTE *bgr) 121 { 122 float r, g, b; 123 124 r = bgr[2] / 255.0f; 125 g = bgr[1] / 255.0f; 126 b = bgr[0] / 255.0f; 127 128 r = to_sRGB_component(r); 129 g = to_sRGB_component(g); 130 b = to_sRGB_component(b); 131 132 bgr[2] = (BYTE)(r * 255.0f); 133 bgr[1] = (BYTE)(g * 255.0f); 134 bgr[0] = (BYTE)(b * 255.0f); 135 } 136 #endif 137 138 static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface) 139 { 140 return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface); 141 } 142 143 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc, 144 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 145 { 146 switch (source_format) 147 { 148 case format_1bppIndexed: 149 case format_BlackWhite: 150 if (prc) 151 { 152 HRESULT res; 153 INT x, y; 154 BYTE *srcdata; 155 UINT srcstride, srcdatasize; 156 const BYTE *srcrow; 157 const BYTE *srcbyte; 158 BYTE *dstrow; 159 DWORD *dstpixel; 160 WICColor colors[2]; 161 IWICPalette *palette; 162 UINT actualcolors; 163 164 res = PaletteImpl_Create(&palette); 165 if (FAILED(res)) return res; 166 167 if (source_format == format_1bppIndexed) 168 res = IWICBitmapSource_CopyPalette(This->source, palette); 169 else 170 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE); 171 172 if (SUCCEEDED(res)) 173 res = IWICPalette_GetColors(palette, 2, colors, &actualcolors); 174 175 IWICPalette_Release(palette); 176 if (FAILED(res)) return res; 177 178 srcstride = (prc->Width+7)/8; 179 srcdatasize = srcstride * prc->Height; 180 181 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 182 if (!srcdata) return E_OUTOFMEMORY; 183 184 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 185 186 if (SUCCEEDED(res)) 187 { 188 srcrow = srcdata; 189 dstrow = pbBuffer; 190 for (y=0; y<prc->Height; y++) { 191 srcbyte = srcrow; 192 dstpixel=(DWORD*)dstrow; 193 for (x=0; x<prc->Width; x+=8) { 194 BYTE srcval; 195 srcval=*srcbyte++; 196 *dstpixel++ = colors[srcval>>7&1]; 197 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>6&1]; 198 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>5&1]; 199 if (x+3 < prc->Width) *dstpixel++ = colors[srcval>>4&1]; 200 if (x+4 < prc->Width) *dstpixel++ = colors[srcval>>3&1]; 201 if (x+5 < prc->Width) *dstpixel++ = colors[srcval>>2&1]; 202 if (x+6 < prc->Width) *dstpixel++ = colors[srcval>>1&1]; 203 if (x+7 < prc->Width) *dstpixel++ = colors[srcval&1]; 204 } 205 srcrow += srcstride; 206 dstrow += cbStride; 207 } 208 } 209 210 HeapFree(GetProcessHeap(), 0, srcdata); 211 212 return res; 213 } 214 return S_OK; 215 case format_2bppIndexed: 216 case format_2bppGray: 217 if (prc) 218 { 219 HRESULT res; 220 INT x, y; 221 BYTE *srcdata; 222 UINT srcstride, srcdatasize; 223 const BYTE *srcrow; 224 const BYTE *srcbyte; 225 BYTE *dstrow; 226 DWORD *dstpixel; 227 WICColor colors[4]; 228 IWICPalette *palette; 229 UINT actualcolors; 230 231 res = PaletteImpl_Create(&palette); 232 if (FAILED(res)) return res; 233 234 if (source_format == format_2bppIndexed) 235 res = IWICBitmapSource_CopyPalette(This->source, palette); 236 else 237 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE); 238 239 if (SUCCEEDED(res)) 240 res = IWICPalette_GetColors(palette, 4, colors, &actualcolors); 241 242 IWICPalette_Release(palette); 243 if (FAILED(res)) return res; 244 245 srcstride = (prc->Width+3)/4; 246 srcdatasize = srcstride * prc->Height; 247 248 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 249 if (!srcdata) return E_OUTOFMEMORY; 250 251 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 252 253 if (SUCCEEDED(res)) 254 { 255 srcrow = srcdata; 256 dstrow = pbBuffer; 257 for (y=0; y<prc->Height; y++) { 258 srcbyte = srcrow; 259 dstpixel=(DWORD*)dstrow; 260 for (x=0; x<prc->Width; x+=4) { 261 BYTE srcval; 262 srcval=*srcbyte++; 263 *dstpixel++ = colors[srcval>>6]; 264 if (x+1 < prc->Width) *dstpixel++ = colors[srcval>>4&0x3]; 265 if (x+2 < prc->Width) *dstpixel++ = colors[srcval>>2&0x3]; 266 if (x+3 < prc->Width) *dstpixel++ = colors[srcval&0x3]; 267 } 268 srcrow += srcstride; 269 dstrow += cbStride; 270 } 271 } 272 273 HeapFree(GetProcessHeap(), 0, srcdata); 274 275 return res; 276 } 277 return S_OK; 278 case format_4bppIndexed: 279 case format_4bppGray: 280 if (prc) 281 { 282 HRESULT res; 283 INT x, y; 284 BYTE *srcdata; 285 UINT srcstride, srcdatasize; 286 const BYTE *srcrow; 287 const BYTE *srcbyte; 288 BYTE *dstrow; 289 DWORD *dstpixel; 290 WICColor colors[16]; 291 IWICPalette *palette; 292 UINT actualcolors; 293 294 res = PaletteImpl_Create(&palette); 295 if (FAILED(res)) return res; 296 297 if (source_format == format_4bppIndexed) 298 res = IWICBitmapSource_CopyPalette(This->source, palette); 299 else 300 res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE); 301 302 if (SUCCEEDED(res)) 303 res = IWICPalette_GetColors(palette, 16, colors, &actualcolors); 304 305 IWICPalette_Release(palette); 306 if (FAILED(res)) return res; 307 308 srcstride = (prc->Width+1)/2; 309 srcdatasize = srcstride * prc->Height; 310 311 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 312 if (!srcdata) return E_OUTOFMEMORY; 313 314 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 315 316 if (SUCCEEDED(res)) 317 { 318 srcrow = srcdata; 319 dstrow = pbBuffer; 320 for (y=0; y<prc->Height; y++) { 321 srcbyte = srcrow; 322 dstpixel=(DWORD*)dstrow; 323 for (x=0; x<prc->Width; x+=2) { 324 BYTE srcval; 325 srcval=*srcbyte++; 326 *dstpixel++ = colors[srcval>>4]; 327 if (x+1 < prc->Width) *dstpixel++ = colors[srcval&0xf]; 328 } 329 srcrow += srcstride; 330 dstrow += cbStride; 331 } 332 } 333 334 HeapFree(GetProcessHeap(), 0, srcdata); 335 336 return res; 337 } 338 return S_OK; 339 case format_8bppGray: 340 if (prc) 341 { 342 HRESULT res; 343 INT x, y; 344 BYTE *srcdata; 345 UINT srcstride, srcdatasize; 346 const BYTE *srcrow; 347 const BYTE *srcbyte; 348 BYTE *dstrow; 349 DWORD *dstpixel; 350 351 srcstride = prc->Width; 352 srcdatasize = srcstride * prc->Height; 353 354 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 355 if (!srcdata) return E_OUTOFMEMORY; 356 357 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 358 359 if (SUCCEEDED(res)) 360 { 361 srcrow = srcdata; 362 dstrow = pbBuffer; 363 for (y=0; y<prc->Height; y++) { 364 srcbyte = srcrow; 365 dstpixel=(DWORD*)dstrow; 366 for (x=0; x<prc->Width; x++) 367 { 368 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte; 369 srcbyte++; 370 } 371 srcrow += srcstride; 372 dstrow += cbStride; 373 } 374 } 375 376 HeapFree(GetProcessHeap(), 0, srcdata); 377 378 return res; 379 } 380 return S_OK; 381 case format_8bppIndexed: 382 if (prc) 383 { 384 HRESULT res; 385 INT x, y; 386 BYTE *srcdata; 387 UINT srcstride, srcdatasize; 388 const BYTE *srcrow; 389 const BYTE *srcbyte; 390 BYTE *dstrow; 391 DWORD *dstpixel; 392 WICColor colors[256]; 393 IWICPalette *palette; 394 UINT actualcolors; 395 396 res = PaletteImpl_Create(&palette); 397 if (FAILED(res)) return res; 398 399 res = IWICBitmapSource_CopyPalette(This->source, palette); 400 if (SUCCEEDED(res)) 401 res = IWICPalette_GetColors(palette, 256, colors, &actualcolors); 402 403 IWICPalette_Release(palette); 404 405 if (FAILED(res)) return res; 406 407 srcstride = prc->Width; 408 srcdatasize = srcstride * prc->Height; 409 410 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 411 if (!srcdata) return E_OUTOFMEMORY; 412 413 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 414 415 if (SUCCEEDED(res)) 416 { 417 srcrow = srcdata; 418 dstrow = pbBuffer; 419 for (y=0; y<prc->Height; y++) { 420 srcbyte = srcrow; 421 dstpixel=(DWORD*)dstrow; 422 for (x=0; x<prc->Width; x++) 423 *dstpixel++ = colors[*srcbyte++]; 424 srcrow += srcstride; 425 dstrow += cbStride; 426 } 427 } 428 429 HeapFree(GetProcessHeap(), 0, srcdata); 430 431 return res; 432 } 433 return S_OK; 434 case format_16bppGray: 435 if (prc) 436 { 437 HRESULT res; 438 INT x, y; 439 BYTE *srcdata; 440 UINT srcstride, srcdatasize; 441 const BYTE *srcrow; 442 const BYTE *srcbyte; 443 BYTE *dstrow; 444 DWORD *dstpixel; 445 446 srcstride = prc->Width * 2; 447 srcdatasize = srcstride * prc->Height; 448 449 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 450 if (!srcdata) return E_OUTOFMEMORY; 451 452 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 453 454 if (SUCCEEDED(res)) 455 { 456 srcrow = srcdata; 457 dstrow = pbBuffer; 458 for (y=0; y<prc->Height; y++) { 459 srcbyte = srcrow; 460 dstpixel=(DWORD*)dstrow; 461 for (x=0; x<prc->Width; x++) 462 { 463 *dstpixel++ = 0xff000000|(*srcbyte<<16)|(*srcbyte<<8)|*srcbyte; 464 srcbyte+=2; 465 } 466 srcrow += srcstride; 467 dstrow += cbStride; 468 } 469 } 470 471 HeapFree(GetProcessHeap(), 0, srcdata); 472 473 return res; 474 } 475 return S_OK; 476 case format_16bppBGR555: 477 if (prc) 478 { 479 HRESULT res; 480 INT x, y; 481 BYTE *srcdata; 482 UINT srcstride, srcdatasize; 483 const BYTE *srcrow; 484 const WORD *srcpixel; 485 BYTE *dstrow; 486 DWORD *dstpixel; 487 488 srcstride = 2 * prc->Width; 489 srcdatasize = srcstride * prc->Height; 490 491 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 492 if (!srcdata) return E_OUTOFMEMORY; 493 494 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 495 496 if (SUCCEEDED(res)) 497 { 498 srcrow = srcdata; 499 dstrow = pbBuffer; 500 for (y=0; y<prc->Height; y++) { 501 srcpixel=(const WORD*)srcrow; 502 dstpixel=(DWORD*)dstrow; 503 for (x=0; x<prc->Width; x++) { 504 WORD srcval; 505 srcval=*srcpixel++; 506 *dstpixel++=0xff000000 | /* constant 255 alpha */ 507 ((srcval << 9) & 0xf80000) | /* r */ 508 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 509 ((srcval << 6) & 0x00f800) | /* g */ 510 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 511 ((srcval << 3) & 0x0000f8) | /* b */ 512 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 513 } 514 srcrow += srcstride; 515 dstrow += cbStride; 516 } 517 } 518 519 HeapFree(GetProcessHeap(), 0, srcdata); 520 521 return res; 522 } 523 return S_OK; 524 case format_16bppBGR565: 525 if (prc) 526 { 527 HRESULT res; 528 INT x, y; 529 BYTE *srcdata; 530 UINT srcstride, srcdatasize; 531 const BYTE *srcrow; 532 const WORD *srcpixel; 533 BYTE *dstrow; 534 DWORD *dstpixel; 535 536 srcstride = 2 * prc->Width; 537 srcdatasize = srcstride * prc->Height; 538 539 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 540 if (!srcdata) return E_OUTOFMEMORY; 541 542 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 543 544 if (SUCCEEDED(res)) 545 { 546 srcrow = srcdata; 547 dstrow = pbBuffer; 548 for (y=0; y<prc->Height; y++) { 549 srcpixel=(const WORD*)srcrow; 550 dstpixel=(DWORD*)dstrow; 551 for (x=0; x<prc->Width; x++) { 552 WORD srcval; 553 srcval=*srcpixel++; 554 *dstpixel++=0xff000000 | /* constant 255 alpha */ 555 ((srcval << 8) & 0xf80000) | /* r */ 556 ((srcval << 3) & 0x070000) | /* r - 3 bits */ 557 ((srcval << 5) & 0x00fc00) | /* g */ 558 ((srcval >> 1) & 0x000300) | /* g - 2 bits */ 559 ((srcval << 3) & 0x0000f8) | /* b */ 560 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 561 } 562 srcrow += srcstride; 563 dstrow += cbStride; 564 } 565 } 566 567 HeapFree(GetProcessHeap(), 0, srcdata); 568 569 return res; 570 } 571 return S_OK; 572 case format_16bppBGRA5551: 573 if (prc) 574 { 575 HRESULT res; 576 INT x, y; 577 BYTE *srcdata; 578 UINT srcstride, srcdatasize; 579 const BYTE *srcrow; 580 const WORD *srcpixel; 581 BYTE *dstrow; 582 DWORD *dstpixel; 583 584 srcstride = 2 * prc->Width; 585 srcdatasize = srcstride * prc->Height; 586 587 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 588 if (!srcdata) return E_OUTOFMEMORY; 589 590 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 591 592 if (SUCCEEDED(res)) 593 { 594 srcrow = srcdata; 595 dstrow = pbBuffer; 596 for (y=0; y<prc->Height; y++) { 597 srcpixel=(const WORD*)srcrow; 598 dstpixel=(DWORD*)dstrow; 599 for (x=0; x<prc->Width; x++) { 600 WORD srcval; 601 srcval=*srcpixel++; 602 *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */ 603 ((srcval << 9) & 0xf80000) | /* r */ 604 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 605 ((srcval << 6) & 0x00f800) | /* g */ 606 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 607 ((srcval << 3) & 0x0000f8) | /* b */ 608 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 609 } 610 srcrow += srcstride; 611 dstrow += cbStride; 612 } 613 } 614 615 HeapFree(GetProcessHeap(), 0, srcdata); 616 617 return res; 618 } 619 return S_OK; 620 case format_24bppBGR: 621 if (prc) 622 { 623 HRESULT res; 624 INT x, y; 625 BYTE *srcdata; 626 UINT srcstride, srcdatasize; 627 const BYTE *srcrow; 628 const BYTE *srcpixel; 629 BYTE *dstrow; 630 BYTE *dstpixel; 631 632 srcstride = 3 * prc->Width; 633 srcdatasize = srcstride * prc->Height; 634 635 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 636 if (!srcdata) return E_OUTOFMEMORY; 637 638 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 639 640 if (SUCCEEDED(res)) 641 { 642 srcrow = srcdata; 643 dstrow = pbBuffer; 644 for (y=0; y<prc->Height; y++) { 645 srcpixel=srcrow; 646 dstpixel=dstrow; 647 for (x=0; x<prc->Width; x++) { 648 *dstpixel++=*srcpixel++; /* blue */ 649 *dstpixel++=*srcpixel++; /* green */ 650 *dstpixel++=*srcpixel++; /* red */ 651 *dstpixel++=255; /* alpha */ 652 } 653 srcrow += srcstride; 654 dstrow += cbStride; 655 } 656 } 657 658 HeapFree(GetProcessHeap(), 0, srcdata); 659 660 return res; 661 } 662 return S_OK; 663 case format_24bppRGB: 664 if (prc) 665 { 666 HRESULT res; 667 INT x, y; 668 BYTE *srcdata; 669 UINT srcstride, srcdatasize; 670 const BYTE *srcrow; 671 const BYTE *srcpixel; 672 BYTE *dstrow; 673 BYTE *dstpixel; 674 BYTE tmppixel[3]; 675 676 srcstride = 3 * prc->Width; 677 srcdatasize = srcstride * prc->Height; 678 679 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 680 if (!srcdata) return E_OUTOFMEMORY; 681 682 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 683 684 if (SUCCEEDED(res)) 685 { 686 srcrow = srcdata; 687 dstrow = pbBuffer; 688 for (y=0; y<prc->Height; y++) { 689 srcpixel=srcrow; 690 dstpixel=dstrow; 691 for (x=0; x<prc->Width; x++) { 692 tmppixel[0]=*srcpixel++; /* red */ 693 tmppixel[1]=*srcpixel++; /* green */ 694 tmppixel[2]=*srcpixel++; /* blue */ 695 696 *dstpixel++=tmppixel[2]; /* blue */ 697 *dstpixel++=tmppixel[1]; /* green */ 698 *dstpixel++=tmppixel[0]; /* red */ 699 *dstpixel++=255; /* alpha */ 700 } 701 srcrow += srcstride; 702 dstrow += cbStride; 703 } 704 } 705 706 HeapFree(GetProcessHeap(), 0, srcdata); 707 708 return res; 709 } 710 return S_OK; 711 case format_32bppBGR: 712 if (prc) 713 { 714 HRESULT res; 715 INT x, y; 716 717 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 718 if (FAILED(res)) return res; 719 720 /* set all alpha values to 255 */ 721 for (y=0; y<prc->Height; y++) 722 for (x=0; x<prc->Width; x++) 723 pbBuffer[cbStride*y+4*x+3] = 0xff; 724 } 725 return S_OK; 726 case format_32bppBGRA: 727 if (prc) 728 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 729 return S_OK; 730 case format_32bppPBGRA: 731 if (prc) 732 { 733 HRESULT res; 734 INT x, y; 735 736 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 737 if (FAILED(res)) return res; 738 739 for (y=0; y<prc->Height; y++) 740 for (x=0; x<prc->Width; x++) 741 { 742 BYTE alpha = pbBuffer[cbStride*y+4*x+3]; 743 if (alpha != 0 && alpha != 255) 744 { 745 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha; 746 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha; 747 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha; 748 } 749 } 750 } 751 return S_OK; 752 case format_48bppRGB: 753 if (prc) 754 { 755 HRESULT res; 756 INT x, y; 757 BYTE *srcdata; 758 UINT srcstride, srcdatasize; 759 const BYTE *srcrow; 760 const BYTE *srcpixel; 761 BYTE *dstrow; 762 DWORD *dstpixel; 763 764 srcstride = 6 * prc->Width; 765 srcdatasize = srcstride * prc->Height; 766 767 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 768 if (!srcdata) return E_OUTOFMEMORY; 769 770 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 771 772 if (SUCCEEDED(res)) 773 { 774 srcrow = srcdata; 775 dstrow = pbBuffer; 776 for (y=0; y<prc->Height; y++) { 777 srcpixel=srcrow; 778 dstpixel=(DWORD*)dstrow; 779 for (x=0; x<prc->Width; x++) { 780 BYTE red, green, blue; 781 red = *srcpixel++; srcpixel++; 782 green = *srcpixel++; srcpixel++; 783 blue = *srcpixel++; srcpixel++; 784 *dstpixel++=0xff000000|red<<16|green<<8|blue; 785 } 786 srcrow += srcstride; 787 dstrow += cbStride; 788 } 789 } 790 791 HeapFree(GetProcessHeap(), 0, srcdata); 792 793 return res; 794 } 795 return S_OK; 796 case format_64bppRGBA: 797 if (prc) 798 { 799 HRESULT res; 800 INT x, y; 801 BYTE *srcdata; 802 UINT srcstride, srcdatasize; 803 const BYTE *srcrow; 804 const BYTE *srcpixel; 805 BYTE *dstrow; 806 DWORD *dstpixel; 807 808 srcstride = 8 * prc->Width; 809 srcdatasize = srcstride * prc->Height; 810 811 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 812 if (!srcdata) return E_OUTOFMEMORY; 813 814 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 815 816 if (SUCCEEDED(res)) 817 { 818 srcrow = srcdata; 819 dstrow = pbBuffer; 820 for (y=0; y<prc->Height; y++) { 821 srcpixel=srcrow; 822 dstpixel=(DWORD*)dstrow; 823 for (x=0; x<prc->Width; x++) { 824 BYTE red, green, blue, alpha; 825 red = *srcpixel++; srcpixel++; 826 green = *srcpixel++; srcpixel++; 827 blue = *srcpixel++; srcpixel++; 828 alpha = *srcpixel++; srcpixel++; 829 *dstpixel++=alpha<<24|red<<16|green<<8|blue; 830 } 831 srcrow += srcstride; 832 dstrow += cbStride; 833 } 834 } 835 836 HeapFree(GetProcessHeap(), 0, srcdata); 837 838 return res; 839 } 840 return S_OK; 841 case format_32bppCMYK: 842 if (prc) 843 { 844 HRESULT res; 845 UINT x, y; 846 847 res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 848 if (FAILED(res)) return res; 849 850 for (y=0; y<prc->Height; y++) 851 for (x=0; x<prc->Width; x++) 852 { 853 BYTE *pixel = pbBuffer+cbStride*y+4*x; 854 BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3]; 855 pixel[0] = (255-y)*(255-k)/255; /* blue */ 856 pixel[1] = (255-m)*(255-k)/255; /* green */ 857 pixel[2] = (255-c)*(255-k)/255; /* red */ 858 pixel[3] = 255; /* alpha */ 859 } 860 } 861 return S_OK; 862 default: 863 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 864 } 865 } 866 867 static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc, 868 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 869 { 870 HRESULT hr; 871 872 switch (source_format) 873 { 874 case format_32bppRGB: 875 case format_32bppRGBA: 876 case format_32bppPRGBA: 877 if (prc) 878 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 879 return S_OK; 880 default: 881 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 882 if (SUCCEEDED(hr) && prc) 883 reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride); 884 return hr; 885 } 886 } 887 888 static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc, 889 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 890 { 891 switch (source_format) 892 { 893 case format_32bppBGR: 894 case format_32bppBGRA: 895 case format_32bppPBGRA: 896 if (prc) 897 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 898 return S_OK; 899 default: 900 return copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 901 } 902 } 903 904 static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc, 905 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 906 { 907 switch (source_format) 908 { 909 case format_32bppRGB: 910 case format_32bppRGBA: 911 case format_32bppPRGBA: 912 if (prc) 913 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 914 return S_OK; 915 default: 916 return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 917 } 918 } 919 920 static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc, 921 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 922 { 923 HRESULT hr; 924 925 switch (source_format) 926 { 927 case format_32bppPBGRA: 928 if (prc) 929 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 930 return S_OK; 931 default: 932 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 933 if (SUCCEEDED(hr) && prc) 934 { 935 INT x, y; 936 937 for (y=0; y<prc->Height; y++) 938 for (x=0; x<prc->Width; x++) 939 { 940 BYTE alpha = pbBuffer[cbStride*y+4*x+3]; 941 if (alpha != 255) 942 { 943 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255; 944 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255; 945 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255; 946 } 947 } 948 } 949 return hr; 950 } 951 } 952 953 static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc, 954 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 955 { 956 HRESULT hr; 957 958 switch (source_format) 959 { 960 case format_32bppPRGBA: 961 if (prc) 962 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 963 return S_OK; 964 default: 965 hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 966 if (SUCCEEDED(hr) && prc) 967 { 968 INT x, y; 969 970 for (y=0; y<prc->Height; y++) 971 for (x=0; x<prc->Width; x++) 972 { 973 BYTE alpha = pbBuffer[cbStride*y+4*x+3]; 974 if (alpha != 255) 975 { 976 pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255; 977 pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255; 978 pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255; 979 } 980 } 981 } 982 return hr; 983 } 984 } 985 986 static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc, 987 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 988 { 989 HRESULT hr; 990 991 switch (source_format) 992 { 993 case format_24bppBGR: 994 case format_24bppRGB: 995 if (prc) 996 { 997 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 998 if (SUCCEEDED(hr) && source_format == format_24bppRGB) 999 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride); 1000 return hr; 1001 } 1002 return S_OK; 1003 case format_32bppBGR: 1004 case format_32bppBGRA: 1005 case format_32bppPBGRA: 1006 if (prc) 1007 { 1008 HRESULT res; 1009 INT x, y; 1010 BYTE *srcdata; 1011 UINT srcstride, srcdatasize; 1012 const BYTE *srcrow; 1013 const BYTE *srcpixel; 1014 BYTE *dstrow; 1015 BYTE *dstpixel; 1016 1017 srcstride = 4 * prc->Width; 1018 srcdatasize = srcstride * prc->Height; 1019 1020 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1021 if (!srcdata) return E_OUTOFMEMORY; 1022 1023 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 1024 1025 if (SUCCEEDED(res)) 1026 { 1027 srcrow = srcdata; 1028 dstrow = pbBuffer; 1029 for (y=0; y<prc->Height; y++) { 1030 srcpixel=srcrow; 1031 dstpixel=dstrow; 1032 for (x=0; x<prc->Width; x++) { 1033 *dstpixel++=*srcpixel++; /* blue */ 1034 *dstpixel++=*srcpixel++; /* green */ 1035 *dstpixel++=*srcpixel++; /* red */ 1036 srcpixel++; /* alpha */ 1037 } 1038 srcrow += srcstride; 1039 dstrow += cbStride; 1040 } 1041 } 1042 1043 HeapFree(GetProcessHeap(), 0, srcdata); 1044 1045 return res; 1046 } 1047 return S_OK; 1048 1049 case format_32bppGrayFloat: 1050 if (prc) 1051 { 1052 BYTE *srcdata; 1053 UINT srcstride, srcdatasize; 1054 1055 srcstride = 4 * prc->Width; 1056 srcdatasize = srcstride * prc->Height; 1057 1058 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1059 if (!srcdata) return E_OUTOFMEMORY; 1060 1061 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 1062 1063 if (SUCCEEDED(hr)) 1064 { 1065 INT x, y; 1066 BYTE *src = srcdata, *dst = pbBuffer; 1067 1068 for (y = 0; y < prc->Height; y++) 1069 { 1070 float *gray_float = (float *)src; 1071 BYTE *bgr = dst; 1072 1073 for (x = 0; x < prc->Width; x++) 1074 { 1075 BYTE gray = (BYTE)floorf(to_sRGB_component(gray_float[x]) * 255.0f + 0.51f); 1076 *bgr++ = gray; 1077 *bgr++ = gray; 1078 *bgr++ = gray; 1079 } 1080 src += srcstride; 1081 dst += cbStride; 1082 } 1083 } 1084 1085 HeapFree(GetProcessHeap(), 0, srcdata); 1086 1087 return hr; 1088 } 1089 return S_OK; 1090 1091 case format_32bppCMYK: 1092 if (prc) 1093 { 1094 BYTE *srcdata; 1095 UINT srcstride, srcdatasize; 1096 1097 srcstride = 4 * prc->Width; 1098 srcdatasize = srcstride * prc->Height; 1099 1100 srcdata = heap_alloc(srcdatasize); 1101 if (!srcdata) return E_OUTOFMEMORY; 1102 1103 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 1104 if (SUCCEEDED(hr)) 1105 { 1106 INT x, y; 1107 BYTE *src = srcdata, *dst = pbBuffer; 1108 1109 for (y = 0; y < prc->Height; y++) 1110 { 1111 BYTE *cmyk = src; 1112 BYTE *bgr = dst; 1113 1114 for (x = 0; x < prc->Width; x++) 1115 { 1116 BYTE c = cmyk[0], m = cmyk[1], y = cmyk[2], k = cmyk[3]; 1117 bgr[0] = (255 - y) * (255 - k) / 255; /* B */ 1118 bgr[1] = (255 - m) * (255 - k) / 255; /* G */ 1119 bgr[2] = (255 - c) * (255 - k) / 255; /* R */ 1120 cmyk += 4; 1121 bgr += 3; 1122 } 1123 src += srcstride; 1124 dst += cbStride; 1125 } 1126 } 1127 1128 heap_free(srcdata); 1129 return hr; 1130 } 1131 return S_OK; 1132 1133 default: 1134 FIXME("Unimplemented conversion path!\n"); 1135 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1136 } 1137 } 1138 1139 static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRect *prc, 1140 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 1141 { 1142 HRESULT hr; 1143 1144 switch (source_format) 1145 { 1146 case format_24bppBGR: 1147 case format_24bppRGB: 1148 if (prc) 1149 { 1150 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 1151 if (SUCCEEDED(hr) && source_format == format_24bppBGR) 1152 reverse_bgr8(3, pbBuffer, prc->Width, prc->Height, cbStride); 1153 return hr; 1154 } 1155 return S_OK; 1156 case format_32bppBGR: 1157 case format_32bppBGRA: 1158 case format_32bppPBGRA: 1159 if (prc) 1160 { 1161 HRESULT res; 1162 INT x, y; 1163 BYTE *srcdata; 1164 UINT srcstride, srcdatasize; 1165 const BYTE *srcrow; 1166 const BYTE *srcpixel; 1167 BYTE *dstrow; 1168 BYTE *dstpixel; 1169 BYTE tmppixel[3]; 1170 1171 srcstride = 4 * prc->Width; 1172 srcdatasize = srcstride * prc->Height; 1173 1174 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1175 if (!srcdata) return E_OUTOFMEMORY; 1176 1177 res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 1178 1179 if (SUCCEEDED(res)) 1180 { 1181 srcrow = srcdata; 1182 dstrow = pbBuffer; 1183 for (y=0; y<prc->Height; y++) { 1184 srcpixel=srcrow; 1185 dstpixel=dstrow; 1186 for (x=0; x<prc->Width; x++) { 1187 tmppixel[0]=*srcpixel++; /* blue */ 1188 tmppixel[1]=*srcpixel++; /* green */ 1189 tmppixel[2]=*srcpixel++; /* red */ 1190 srcpixel++; /* alpha */ 1191 1192 *dstpixel++=tmppixel[2]; /* red */ 1193 *dstpixel++=tmppixel[1]; /* green */ 1194 *dstpixel++=tmppixel[0]; /* blue */ 1195 } 1196 srcrow += srcstride; 1197 dstrow += cbStride; 1198 } 1199 } 1200 1201 HeapFree(GetProcessHeap(), 0, srcdata); 1202 1203 return res; 1204 } 1205 return S_OK; 1206 default: 1207 FIXME("Unimplemented conversion path!\n"); 1208 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1209 } 1210 } 1211 1212 static HRESULT copypixels_to_32bppGrayFloat(struct FormatConverter *This, const WICRect *prc, 1213 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 1214 { 1215 HRESULT hr; 1216 1217 switch (source_format) 1218 { 1219 case format_32bppBGR: 1220 case format_32bppBGRA: 1221 case format_32bppPBGRA: 1222 case format_32bppGrayFloat: 1223 if (prc) 1224 { 1225 hr = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 1226 break; 1227 } 1228 return S_OK; 1229 1230 default: 1231 hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); 1232 break; 1233 } 1234 1235 if (SUCCEEDED(hr) && prc && source_format != format_32bppGrayFloat) 1236 { 1237 INT x, y; 1238 BYTE *p = pbBuffer; 1239 1240 for (y = 0; y < prc->Height; y++) 1241 { 1242 BYTE *bgr = p; 1243 for (x = 0; x < prc->Width; x++) 1244 { 1245 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f; 1246 *(float *)bgr = gray; 1247 bgr += 4; 1248 } 1249 p += cbStride; 1250 } 1251 } 1252 return hr; 1253 } 1254 1255 static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRect *prc, 1256 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 1257 { 1258 HRESULT hr; 1259 BYTE *srcdata; 1260 UINT srcstride, srcdatasize; 1261 1262 if (source_format == format_8bppGray) 1263 { 1264 if (prc) 1265 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 1266 1267 return S_OK; 1268 } 1269 1270 if (source_format == format_32bppGrayFloat) 1271 { 1272 hr = S_OK; 1273 1274 if (prc) 1275 { 1276 srcstride = 4 * prc->Width; 1277 srcdatasize = srcstride * prc->Height; 1278 1279 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1280 if (!srcdata) return E_OUTOFMEMORY; 1281 1282 hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); 1283 if (SUCCEEDED(hr)) 1284 { 1285 INT x, y; 1286 BYTE *src = srcdata, *dst = pbBuffer; 1287 1288 for (y=0; y < prc->Height; y++) 1289 { 1290 float *srcpixel = (float*)src; 1291 BYTE *dstpixel = dst; 1292 1293 for (x=0; x < prc->Width; x++) 1294 *dstpixel++ = (BYTE)floorf(to_sRGB_component(*srcpixel++) * 255.0f + 0.51f); 1295 1296 src += srcstride; 1297 dst += cbStride; 1298 } 1299 } 1300 1301 HeapFree(GetProcessHeap(), 0, srcdata); 1302 } 1303 1304 return hr; 1305 } 1306 1307 srcstride = 3 * prc->Width; 1308 srcdatasize = srcstride * prc->Height; 1309 1310 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1311 if (!srcdata) return E_OUTOFMEMORY; 1312 1313 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); 1314 if (SUCCEEDED(hr) && prc) 1315 { 1316 INT x, y; 1317 BYTE *src = srcdata, *dst = pbBuffer; 1318 1319 for (y = 0; y < prc->Height; y++) 1320 { 1321 BYTE *bgr = src; 1322 1323 for (x = 0; x < prc->Width; x++) 1324 { 1325 float gray = (bgr[2] * 0.2126f + bgr[1] * 0.7152f + bgr[0] * 0.0722f) / 255.0f; 1326 1327 gray = to_sRGB_component(gray) * 255.0f; 1328 dst[x] = (BYTE)floorf(gray + 0.51f); 1329 bgr += 3; 1330 } 1331 src += srcstride; 1332 dst += cbStride; 1333 } 1334 } 1335 1336 HeapFree(GetProcessHeap(), 0, srcdata); 1337 return hr; 1338 } 1339 1340 static UINT rgb_to_palette_index(BYTE r, BYTE g, BYTE b, WICColor *colors, UINT count) 1341 { 1342 UINT best_diff, best_index, i; 1343 1344 best_diff = ~0; 1345 best_index = 0; 1346 1347 for (i = 0; i < count; i++) 1348 { 1349 BYTE pal_r, pal_g, pal_b; 1350 DWORD diff_r, diff_g, diff_b, diff; 1351 1352 pal_r = colors[i] >> 16; 1353 pal_g = colors[i] >> 8; 1354 pal_b = colors[i]; 1355 1356 diff_r = r - pal_r; 1357 diff_g = g - pal_g; 1358 diff_b = b - pal_b; 1359 1360 diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b; 1361 if (diff == 0) return i; 1362 1363 if (diff < best_diff) 1364 { 1365 best_diff = diff; 1366 best_index = i; 1367 } 1368 } 1369 1370 return best_index; 1371 } 1372 1373 static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc, 1374 UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) 1375 { 1376 HRESULT hr; 1377 BYTE *srcdata; 1378 WICColor colors[256]; 1379 UINT srcstride, srcdatasize, count; 1380 1381 if (source_format == format_8bppIndexed) 1382 { 1383 if (prc) 1384 return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); 1385 1386 return S_OK; 1387 } 1388 1389 if (!This->palette) return WINCODEC_ERR_WRONGSTATE; 1390 1391 hr = IWICPalette_GetColors(This->palette, 256, colors, &count); 1392 if (hr != S_OK) return hr; 1393 1394 srcstride = 3 * prc->Width; 1395 srcdatasize = srcstride * prc->Height; 1396 1397 srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); 1398 if (!srcdata) return E_OUTOFMEMORY; 1399 1400 hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); 1401 if (SUCCEEDED(hr) && prc) 1402 { 1403 INT x, y; 1404 BYTE *src = srcdata, *dst = pbBuffer; 1405 1406 for (y = 0; y < prc->Height; y++) 1407 { 1408 BYTE *bgr = src; 1409 1410 for (x = 0; x < prc->Width; x++) 1411 { 1412 dst[x] = rgb_to_palette_index(bgr[2], bgr[1], bgr[0], colors, count); 1413 bgr += 3; 1414 } 1415 src += srcstride; 1416 dst += cbStride; 1417 } 1418 } 1419 1420 HeapFree(GetProcessHeap(), 0, srcdata); 1421 return hr; 1422 } 1423 1424 static const struct pixelformatinfo supported_formats[] = { 1425 {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL}, 1426 {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL}, 1427 {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL}, 1428 {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed}, 1429 {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL}, 1430 {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL}, 1431 {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL}, 1432 {format_8bppGray, &GUID_WICPixelFormat8bppGray, copypixels_to_8bppGray}, 1433 {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL}, 1434 {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL}, 1435 {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL}, 1436 {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL}, 1437 {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR}, 1438 {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB}, 1439 {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat}, 1440 {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR}, 1441 {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB}, 1442 {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA}, 1443 {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA}, 1444 {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA}, 1445 {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA}, 1446 {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL}, 1447 {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL}, 1448 {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL}, 1449 {0} 1450 }; 1451 1452 static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *format) 1453 { 1454 UINT i; 1455 1456 for (i=0; supported_formats[i].guid; i++) 1457 if (IsEqualGUID(supported_formats[i].guid, format)) return &supported_formats[i]; 1458 1459 return NULL; 1460 } 1461 1462 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid, 1463 void **ppv) 1464 { 1465 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1466 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1467 1468 if (!ppv) return E_INVALIDARG; 1469 1470 if (IsEqualIID(&IID_IUnknown, iid) || 1471 IsEqualIID(&IID_IWICBitmapSource, iid) || 1472 IsEqualIID(&IID_IWICFormatConverter, iid)) 1473 { 1474 *ppv = &This->IWICFormatConverter_iface; 1475 } 1476 else 1477 { 1478 *ppv = NULL; 1479 return E_NOINTERFACE; 1480 } 1481 1482 IUnknown_AddRef((IUnknown*)*ppv); 1483 return S_OK; 1484 } 1485 1486 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface) 1487 { 1488 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1489 ULONG ref = InterlockedIncrement(&This->ref); 1490 1491 TRACE("(%p) refcount=%u\n", iface, ref); 1492 1493 return ref; 1494 } 1495 1496 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface) 1497 { 1498 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1499 ULONG ref = InterlockedDecrement(&This->ref); 1500 1501 TRACE("(%p) refcount=%u\n", iface, ref); 1502 1503 if (ref == 0) 1504 { 1505 This->lock.DebugInfo->Spare[0] = 0; 1506 DeleteCriticalSection(&This->lock); 1507 if (This->source) IWICBitmapSource_Release(This->source); 1508 if (This->palette) IWICPalette_Release(This->palette); 1509 HeapFree(GetProcessHeap(), 0, This); 1510 } 1511 1512 return ref; 1513 } 1514 1515 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface, 1516 UINT *puiWidth, UINT *puiHeight) 1517 { 1518 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1519 1520 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 1521 1522 if (This->source) 1523 return IWICBitmapSource_GetSize(This->source, puiWidth, puiHeight); 1524 else 1525 return WINCODEC_ERR_NOTINITIALIZED; 1526 } 1527 1528 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface, 1529 WICPixelFormatGUID *pPixelFormat) 1530 { 1531 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1532 1533 TRACE("(%p,%p)\n", iface, pPixelFormat); 1534 1535 if (This->source) 1536 memcpy(pPixelFormat, This->dst_format->guid, sizeof(GUID)); 1537 else 1538 return WINCODEC_ERR_NOTINITIALIZED; 1539 1540 return S_OK; 1541 } 1542 1543 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface, 1544 double *pDpiX, double *pDpiY) 1545 { 1546 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1547 1548 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 1549 1550 if (This->source) 1551 return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY); 1552 else 1553 return WINCODEC_ERR_NOTINITIALIZED; 1554 } 1555 1556 static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface, 1557 IWICPalette *palette) 1558 { 1559 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1560 1561 TRACE("(%p,%p)\n", iface, palette); 1562 1563 if (!palette) return E_INVALIDARG; 1564 if (!This->source) return WINCODEC_ERR_WRONGSTATE; 1565 1566 if (!This->palette) 1567 { 1568 HRESULT hr; 1569 UINT bpp; 1570 1571 hr = get_pixelformat_bpp(This->dst_format->guid, &bpp); 1572 if (hr != S_OK) return hr; 1573 if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE; 1574 return IWICBitmapSource_CopyPalette(This->source, palette); 1575 } 1576 1577 return IWICPalette_InitializeFromPalette(palette, This->palette); 1578 } 1579 1580 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface, 1581 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 1582 { 1583 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1584 WICRect rc; 1585 HRESULT hr; 1586 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 1587 1588 if (This->source) 1589 { 1590 if (!prc) 1591 { 1592 UINT width, height; 1593 hr = IWICBitmapSource_GetSize(This->source, &width, &height); 1594 if (FAILED(hr)) return hr; 1595 rc.X = 0; 1596 rc.Y = 0; 1597 rc.Width = width; 1598 rc.Height = height; 1599 prc = &rc; 1600 } 1601 1602 return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize, 1603 pbBuffer, This->src_format->format); 1604 } 1605 else 1606 return WINCODEC_ERR_WRONGSTATE; 1607 } 1608 1609 static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, 1610 IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither, 1611 IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type) 1612 { 1613 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1614 const struct pixelformatinfo *srcinfo, *dstinfo; 1615 GUID srcFormat; 1616 HRESULT res; 1617 1618 TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat), 1619 dither, palette, alpha_threshold, palette_type); 1620 1621 if (!palette) 1622 { 1623 UINT bpp; 1624 res = get_pixelformat_bpp(dstFormat, &bpp); 1625 if (res != S_OK) return res; 1626 1627 res = PaletteImpl_Create(&palette); 1628 if (res != S_OK) return res; 1629 1630 switch (palette_type) 1631 { 1632 case WICBitmapPaletteTypeCustom: 1633 IWICPalette_Release(palette); 1634 palette = NULL; 1635 if (bpp <= 8) return E_INVALIDARG; 1636 break; 1637 1638 case WICBitmapPaletteTypeMedianCut: 1639 { 1640 if (bpp <= 8) 1641 res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE); 1642 break; 1643 } 1644 1645 default: 1646 if (bpp <= 8) 1647 res = IWICPalette_InitializePredefined(palette, palette_type, FALSE); 1648 break; 1649 } 1650 1651 if (res != S_OK) 1652 { 1653 IWICPalette_Release(palette); 1654 return res; 1655 } 1656 } 1657 else 1658 IWICPalette_AddRef(palette); 1659 1660 EnterCriticalSection(&This->lock); 1661 1662 if (This->source) 1663 { 1664 res = WINCODEC_ERR_WRONGSTATE; 1665 goto end; 1666 } 1667 1668 res = IWICBitmapSource_GetPixelFormat(source, &srcFormat); 1669 if (FAILED(res)) goto end; 1670 1671 srcinfo = get_formatinfo(&srcFormat); 1672 if (!srcinfo) 1673 { 1674 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 1675 FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat)); 1676 goto end; 1677 } 1678 1679 dstinfo = get_formatinfo(dstFormat); 1680 if (!dstinfo) 1681 { 1682 res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 1683 FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat)); 1684 goto end; 1685 } 1686 1687 if (dstinfo->copy_function) 1688 { 1689 IWICBitmapSource_AddRef(source); 1690 This->src_format = srcinfo; 1691 This->dst_format = dstinfo; 1692 This->dither = dither; 1693 This->alpha_threshold = alpha_threshold; 1694 This->palette = palette; 1695 This->source = source; 1696 } 1697 else 1698 { 1699 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat)); 1700 res = WINCODEC_ERR_UNSUPPORTEDOPERATION; 1701 } 1702 1703 end: 1704 1705 LeaveCriticalSection(&This->lock); 1706 1707 if (res != S_OK && palette) 1708 IWICPalette_Release(palette); 1709 1710 return res; 1711 } 1712 1713 static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface, 1714 REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat, 1715 BOOL *pfCanConvert) 1716 { 1717 FormatConverter *This = impl_from_IWICFormatConverter(iface); 1718 const struct pixelformatinfo *srcinfo, *dstinfo; 1719 1720 TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat), 1721 debugstr_guid(dstPixelFormat), pfCanConvert); 1722 1723 srcinfo = get_formatinfo(srcPixelFormat); 1724 if (!srcinfo) 1725 { 1726 FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat)); 1727 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 1728 } 1729 1730 dstinfo = get_formatinfo(dstPixelFormat); 1731 if (!dstinfo) 1732 { 1733 FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat)); 1734 return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; 1735 } 1736 1737 if (dstinfo->copy_function && 1738 SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format))) 1739 *pfCanConvert = TRUE; 1740 else 1741 { 1742 FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat)); 1743 *pfCanConvert = FALSE; 1744 } 1745 1746 return S_OK; 1747 } 1748 1749 static const IWICFormatConverterVtbl FormatConverter_Vtbl = { 1750 FormatConverter_QueryInterface, 1751 FormatConverter_AddRef, 1752 FormatConverter_Release, 1753 FormatConverter_GetSize, 1754 FormatConverter_GetPixelFormat, 1755 FormatConverter_GetResolution, 1756 FormatConverter_CopyPalette, 1757 FormatConverter_CopyPixels, 1758 FormatConverter_Initialize, 1759 FormatConverter_CanConvert 1760 }; 1761 1762 HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv) 1763 { 1764 FormatConverter *This; 1765 HRESULT ret; 1766 1767 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1768 1769 *ppv = NULL; 1770 1771 This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter)); 1772 if (!This) return E_OUTOFMEMORY; 1773 1774 This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl; 1775 This->ref = 1; 1776 This->source = NULL; 1777 This->palette = NULL; 1778 InitializeCriticalSection(&This->lock); 1779 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock"); 1780 1781 ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv); 1782 IWICFormatConverter_Release(&This->IWICFormatConverter_iface); 1783 1784 return ret; 1785 } 1786