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