1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 #include "config.h" 20 21 #include <assert.h> 22 #include <stdarg.h> 23 24 #define COBJMACROS 25 26 #include "windef.h" 27 #include "winbase.h" 28 #include "winreg.h" 29 #include "wingdi.h" 30 #include "objbase.h" 31 32 #include "wincodecs_private.h" 33 34 #include "wine/debug.h" 35 36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 37 38 typedef struct { 39 DWORD bc2Size; 40 DWORD bc2Width; 41 DWORD bc2Height; 42 WORD bc2Planes; 43 WORD bc2BitCount; 44 DWORD bc2Compression; 45 DWORD bc2SizeImage; 46 DWORD bc2XRes; 47 DWORD bc2YRes; 48 DWORD bc2ClrUsed; 49 DWORD bc2ClrImportant; 50 /* same as BITMAPINFOHEADER until this point */ 51 WORD bc2ResUnit; 52 WORD bc2Reserved; 53 WORD bc2Orientation; 54 WORD bc2Halftoning; 55 DWORD bc2HalftoneSize1; 56 DWORD bc2HalftoneSize2; 57 DWORD bc2ColorSpace; 58 DWORD bc2AppData; 59 } BITMAPCOREHEADER2; 60 61 typedef HRESULT (*ReadDataFunc)(BmpDecoder* This); 62 63 struct BmpDecoder { 64 IWICBitmapDecoder IWICBitmapDecoder_iface; 65 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 66 LONG ref; 67 BOOL initialized; 68 IStream *stream; 69 ULONG palette_offset; 70 ULONG image_offset; 71 BITMAPV5HEADER bih; 72 const WICPixelFormatGUID *pixelformat; 73 int bitsperpixel; 74 ReadDataFunc read_data_func; 75 INT stride; 76 BYTE *imagedata; 77 BYTE *imagedatastart; 78 CRITICAL_SECTION lock; /* must be held when initialized/imagedata is set or stream is accessed */ 79 int packed; /* If TRUE, don't look for a file header and assume a packed DIB. */ 80 int icoframe; /* If TRUE, this is a frame of a .ico file. */ 81 }; 82 83 static inline BmpDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 84 { 85 return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapDecoder_iface); 86 } 87 88 static inline BmpDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 89 { 90 return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapFrameDecode_iface); 91 } 92 93 static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 94 void **ppv) 95 { 96 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 97 98 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 99 100 if (!ppv) return E_INVALIDARG; 101 102 if (IsEqualIID(&IID_IUnknown, iid) || 103 IsEqualIID(&IID_IWICBitmapSource, iid) || 104 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 105 { 106 *ppv = &This->IWICBitmapFrameDecode_iface; 107 } 108 else 109 { 110 *ppv = NULL; 111 return E_NOINTERFACE; 112 } 113 114 IUnknown_AddRef((IUnknown*)*ppv); 115 return S_OK; 116 } 117 118 static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 119 { 120 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 121 122 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 123 } 124 125 static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface) 126 { 127 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 128 129 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 130 } 131 132 static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 133 UINT *puiWidth, UINT *puiHeight) 134 { 135 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 136 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 137 138 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 139 { 140 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 141 *puiWidth = bch->bcWidth; 142 *puiHeight = bch->bcHeight; 143 } 144 else 145 { 146 *puiWidth = This->bih.bV5Width; 147 *puiHeight = abs(This->bih.bV5Height); 148 } 149 return S_OK; 150 } 151 152 static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 153 WICPixelFormatGUID *pPixelFormat) 154 { 155 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 156 TRACE("(%p,%p)\n", iface, pPixelFormat); 157 158 memcpy(pPixelFormat, This->pixelformat, sizeof(GUID)); 159 160 return S_OK; 161 } 162 163 static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, double *pDpiY) 164 { 165 LONG resx = 0, resy = 0; 166 167 switch (bih->bV5Size) 168 { 169 default: 170 case sizeof(BITMAPCOREHEADER): 171 break; 172 173 case sizeof(BITMAPCOREHEADER2): 174 case sizeof(BITMAPINFOHEADER): 175 case sizeof(BITMAPV4HEADER): 176 case sizeof(BITMAPV5HEADER): 177 resx = bih->bV5XPelsPerMeter; 178 resy = bih->bV5YPelsPerMeter; 179 break; 180 } 181 182 if (!resx || !resy) 183 { 184 *pDpiX = 96.0; 185 *pDpiY = 96.0; 186 } 187 else 188 { 189 *pDpiX = resx * 0.0254; 190 *pDpiY = resy * 0.0254; 191 } 192 193 return S_OK; 194 } 195 196 static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 197 double *pDpiX, double *pDpiY) 198 { 199 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 200 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 201 202 return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY); 203 } 204 205 static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 206 IWICPalette *pIPalette) 207 { 208 HRESULT hr; 209 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 210 int count; 211 WICColor *wiccolors=NULL; 212 RGBTRIPLE *bgrcolors=NULL; 213 214 TRACE("(%p,%p)\n", iface, pIPalette); 215 216 EnterCriticalSection(&This->lock); 217 218 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 219 { 220 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 221 if (bch->bcBitCount <= 8) 222 { 223 /* 2**n colors in BGR format after the header */ 224 ULONG tablesize, bytesread; 225 LARGE_INTEGER offset; 226 int i; 227 228 count = 1 << bch->bcBitCount; 229 wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count); 230 tablesize = sizeof(RGBTRIPLE) * count; 231 bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize); 232 if (!wiccolors || !bgrcolors) 233 { 234 hr = E_OUTOFMEMORY; 235 goto end; 236 } 237 238 offset.QuadPart = This->palette_offset; 239 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL); 240 if (FAILED(hr)) goto end; 241 242 hr = IStream_Read(This->stream, bgrcolors, tablesize, &bytesread); 243 if (FAILED(hr)) goto end; 244 if (bytesread != tablesize) { 245 hr = E_FAIL; 246 goto end; 247 } 248 249 for (i=0; i<count; i++) 250 { 251 wiccolors[i] = 0xff000000| 252 (bgrcolors[i].rgbtRed<<16)| 253 (bgrcolors[i].rgbtGreen<<8)| 254 bgrcolors[i].rgbtBlue; 255 } 256 } 257 else 258 { 259 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 260 goto end; 261 } 262 } 263 else 264 { 265 if (This->bih.bV5BitCount <= 8) 266 { 267 ULONG tablesize, bytesread; 268 LARGE_INTEGER offset; 269 int i; 270 271 if (This->bih.bV5ClrUsed == 0) 272 count = 1 << This->bih.bV5BitCount; 273 else 274 count = min(This->bih.bV5ClrUsed, 1 << This->bih.bV5BitCount); 275 276 tablesize = sizeof(WICColor) * count; 277 wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize); 278 if (!wiccolors) 279 { 280 hr = E_OUTOFMEMORY; 281 goto end; 282 } 283 284 offset.QuadPart = This->palette_offset; 285 hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL); 286 if (FAILED(hr)) goto end; 287 288 hr = IStream_Read(This->stream, wiccolors, tablesize, &bytesread); 289 if (FAILED(hr)) goto end; 290 if (bytesread != tablesize) { 291 hr = E_FAIL; 292 goto end; 293 } 294 295 /* convert from BGR to BGRA by setting alpha to 100% */ 296 for (i=0; i<count; i++) 297 wiccolors[i] |= 0xff000000; 298 } 299 else 300 { 301 hr = WINCODEC_ERR_PALETTEUNAVAILABLE; 302 goto end; 303 } 304 } 305 306 end: 307 308 LeaveCriticalSection(&This->lock); 309 310 if (SUCCEEDED(hr)) 311 hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count); 312 313 HeapFree(GetProcessHeap(), 0, wiccolors); 314 HeapFree(GetProcessHeap(), 0, bgrcolors); 315 return hr; 316 } 317 318 static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 319 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 320 { 321 BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 322 HRESULT hr=S_OK; 323 UINT width, height; 324 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); 325 326 EnterCriticalSection(&This->lock); 327 if (!This->imagedata) 328 { 329 hr = This->read_data_func(This); 330 } 331 LeaveCriticalSection(&This->lock); 332 if (FAILED(hr)) return hr; 333 334 hr = BmpFrameDecode_GetSize(iface, &width, &height); 335 if (FAILED(hr)) return hr; 336 337 return copy_pixels(This->bitsperpixel, This->imagedatastart, 338 width, height, This->stride, 339 prc, cbStride, cbBufferSize, pbBuffer); 340 } 341 342 static HRESULT WINAPI BmpFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 343 IWICMetadataQueryReader **ppIMetadataQueryReader) 344 { 345 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 346 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 347 } 348 349 static HRESULT WINAPI BmpFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 350 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 351 { 352 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 353 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 354 } 355 356 static HRESULT WINAPI BmpFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 357 IWICBitmapSource **ppIThumbnail) 358 { 359 TRACE("(%p,%p)\n", iface, ppIThumbnail); 360 return WINCODEC_ERR_CODECNOTHUMBNAIL; 361 } 362 363 static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This) 364 { 365 UINT bytesperrow; 366 UINT width, height; 367 UINT datasize; 368 int bottomup; 369 HRESULT hr; 370 LARGE_INTEGER offbits; 371 ULONG bytesread; 372 373 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 374 { 375 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 376 width = bch->bcWidth; 377 height = bch->bcHeight; 378 bottomup = 1; 379 } 380 else 381 { 382 width = This->bih.bV5Width; 383 height = abs(This->bih.bV5Height); 384 bottomup = (This->bih.bV5Height > 0); 385 } 386 387 /* row sizes in BMP files must be divisible by 4 bytes */ 388 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; 389 datasize = bytesperrow * height; 390 391 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 392 if (!This->imagedata) return E_OUTOFMEMORY; 393 394 offbits.QuadPart = This->image_offset; 395 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 396 if (FAILED(hr)) goto fail; 397 398 hr = IStream_Read(This->stream, This->imagedata, datasize, &bytesread); 399 if (FAILED(hr) || bytesread != datasize) goto fail; 400 401 if (bottomup) 402 { 403 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 404 This->stride = -bytesperrow; 405 } 406 else 407 { 408 This->imagedatastart = This->imagedata; 409 This->stride = bytesperrow; 410 } 411 return S_OK; 412 413 fail: 414 HeapFree(GetProcessHeap(), 0, This->imagedata); 415 This->imagedata = NULL; 416 if (SUCCEEDED(hr)) hr = E_FAIL; 417 return hr; 418 } 419 420 static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This) 421 { 422 HRESULT hr; 423 UINT width, height; 424 425 hr = IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height); 426 427 if (SUCCEEDED(hr)) 428 { 429 hr = BmpFrameDecode_ReadUncompressed(This); 430 } 431 432 if (SUCCEEDED(hr)) 433 { 434 reverse_bgr8(This->bitsperpixel/8, This->imagedatastart, 435 width, height, This->stride); 436 } 437 438 return hr; 439 } 440 441 static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size, 442 ULONG *cursor, ULONG *bytesread, BYTE *result) 443 { 444 HRESULT hr=S_OK; 445 446 if (*bytesread == 0 || *cursor == *bytesread) 447 { 448 hr = IStream_Read(stream, buffer, buffer_size, bytesread); 449 *cursor = 0; 450 } 451 452 if (SUCCEEDED(hr)) 453 { 454 if (*cursor < *bytesread) 455 *result = buffer[(*cursor)++]; 456 else 457 hr = E_FAIL; 458 } 459 460 return hr; 461 } 462 463 static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This) 464 { 465 UINT bytesperrow; 466 UINT width, height; 467 BYTE rledata[4096]; 468 UINT datasize, palettesize; 469 DWORD palette[256]; 470 UINT x, y; 471 DWORD *bgrdata; 472 HRESULT hr; 473 LARGE_INTEGER offbits; 474 ULONG cursor=0, bytesread=0; 475 476 width = This->bih.bV5Width; 477 height = abs(This->bih.bV5Height); 478 bytesperrow = width * 4; 479 datasize = bytesperrow * height; 480 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 256) 481 palettesize = 4 * This->bih.bV5ClrUsed; 482 else 483 palettesize = 4 * 256; 484 485 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 486 if (!This->imagedata) 487 { 488 hr = E_OUTOFMEMORY; 489 goto fail; 490 } 491 492 /* read palette */ 493 offbits.QuadPart = This->palette_offset; 494 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 495 if (FAILED(hr)) goto fail; 496 497 hr = IStream_Read(This->stream, palette, palettesize, &bytesread); 498 if (FAILED(hr) || bytesread != palettesize) goto fail; 499 500 /* read RLE data */ 501 offbits.QuadPart = This->image_offset; 502 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 503 if (FAILED(hr)) goto fail; 504 505 /* decode RLE */ 506 bgrdata = (DWORD*)This->imagedata; 507 x = 0; 508 y = 0; 509 cursor = 0; 510 bytesread = 0; 511 while (y < height) 512 { 513 BYTE length; 514 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); 515 516 if (FAILED(hr)) 517 goto fail; 518 else if (length == 0) 519 { 520 /* escape code */ 521 BYTE escape; 522 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape); 523 if (FAILED(hr)) 524 goto fail; 525 switch(escape) 526 { 527 case 0: /* end of line */ 528 x = 0; 529 y++; 530 break; 531 case 1: /* end of bitmap */ 532 goto end; 533 case 2: /* delta */ 534 { 535 BYTE dx, dy; 536 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx); 537 if (SUCCEEDED(hr)) 538 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy); 539 if (FAILED(hr)) 540 goto fail; 541 x += dx; 542 y += dy; 543 break; 544 } 545 default: /* absolute mode */ 546 length = escape; 547 while (length-- && x < width) 548 { 549 BYTE index; 550 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index); 551 if (FAILED(hr)) 552 goto fail; 553 bgrdata[y*width + x++] = palette[index]; 554 } 555 if (escape & 1) 556 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */ 557 if (FAILED(hr)) 558 goto fail; 559 } 560 } 561 else 562 { 563 BYTE index; 564 DWORD color; 565 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &index); 566 if (FAILED(hr)) 567 goto fail; 568 color = palette[index]; 569 while (length-- && x < width) 570 bgrdata[y*width + x++] = color; 571 } 572 } 573 574 end: 575 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 576 This->stride = -bytesperrow; 577 578 return S_OK; 579 580 fail: 581 HeapFree(GetProcessHeap(), 0, This->imagedata); 582 This->imagedata = NULL; 583 if (SUCCEEDED(hr)) hr = E_FAIL; 584 return hr; 585 } 586 587 static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This) 588 { 589 UINT bytesperrow; 590 UINT width, height; 591 BYTE rledata[4096]; 592 UINT datasize, palettesize; 593 DWORD palette[16]; 594 UINT x, y; 595 DWORD *bgrdata; 596 HRESULT hr; 597 LARGE_INTEGER offbits; 598 ULONG cursor=0, bytesread=0; 599 600 width = This->bih.bV5Width; 601 height = abs(This->bih.bV5Height); 602 bytesperrow = width * 4; 603 datasize = bytesperrow * height; 604 if (This->bih.bV5ClrUsed && This->bih.bV5ClrUsed < 16) 605 palettesize = 4 * This->bih.bV5ClrUsed; 606 else 607 palettesize = 4 * 16; 608 609 This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); 610 if (!This->imagedata) 611 { 612 hr = E_OUTOFMEMORY; 613 goto fail; 614 } 615 616 /* read palette */ 617 offbits.QuadPart = This->palette_offset; 618 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 619 if (FAILED(hr)) goto fail; 620 621 hr = IStream_Read(This->stream, palette, palettesize, &bytesread); 622 if (FAILED(hr) || bytesread != palettesize) goto fail; 623 624 /* read RLE data */ 625 offbits.QuadPart = This->image_offset; 626 hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL); 627 if (FAILED(hr)) goto fail; 628 629 /* decode RLE */ 630 bgrdata = (DWORD*)This->imagedata; 631 x = 0; 632 y = 0; 633 cursor = 0; 634 bytesread = 0; 635 while (y < height) 636 { 637 BYTE length; 638 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); 639 640 if (FAILED(hr)) 641 goto fail; 642 else if (length == 0) 643 { 644 /* escape code */ 645 BYTE escape; 646 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &escape); 647 if (FAILED(hr)) 648 goto fail; 649 switch(escape) 650 { 651 case 0: /* end of line */ 652 x = 0; 653 y++; 654 break; 655 case 1: /* end of bitmap */ 656 goto end; 657 case 2: /* delta */ 658 { 659 BYTE dx, dy; 660 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dx); 661 if (SUCCEEDED(hr)) 662 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &dy); 663 if (FAILED(hr)) 664 goto fail; 665 x += dx; 666 y += dy; 667 break; 668 } 669 default: /* absolute mode */ 670 { 671 BYTE realsize=0; 672 length = escape; 673 while (length-- && x < width) 674 { 675 BYTE colors; 676 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors); 677 realsize++; 678 if (FAILED(hr)) 679 goto fail; 680 bgrdata[y*width + x++] = palette[colors>>4]; 681 if (length-- && x < width) 682 bgrdata[y*width + x++] = palette[colors&0xf]; 683 else 684 break; 685 } 686 if (realsize & 1) 687 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &length); /* skip pad byte */ 688 if (FAILED(hr)) 689 goto fail; 690 } 691 } 692 } 693 else 694 { 695 BYTE colors; 696 DWORD color1; 697 DWORD color2; 698 hr = ReadByte(This->stream, rledata, 4096, &cursor, &bytesread, &colors); 699 if (FAILED(hr)) 700 goto fail; 701 color1 = palette[colors>>4]; 702 color2 = palette[colors&0xf]; 703 while (length-- && x < width) 704 { 705 bgrdata[y*width + x++] = color1; 706 if (length-- && x < width) 707 bgrdata[y*width + x++] = color2; 708 else 709 break; 710 } 711 } 712 } 713 714 end: 715 This->imagedatastart = This->imagedata + (height-1) * bytesperrow; 716 This->stride = -bytesperrow; 717 718 return S_OK; 719 720 fail: 721 HeapFree(GetProcessHeap(), 0, This->imagedata); 722 This->imagedata = NULL; 723 if (SUCCEEDED(hr)) hr = E_FAIL; 724 return hr; 725 } 726 727 static HRESULT BmpFrameDecode_ReadUnsupported(BmpDecoder* This) 728 { 729 return E_FAIL; 730 } 731 732 struct bitfields_format { 733 WORD bitcount; /* 0 for end of list */ 734 DWORD redmask; 735 DWORD greenmask; 736 DWORD bluemask; 737 DWORD alphamask; 738 const WICPixelFormatGUID *pixelformat; 739 ReadDataFunc read_data_func; 740 }; 741 742 static const struct bitfields_format bitfields_formats[] = { 743 {16,0x7c00,0x3e0,0x1f,0,&GUID_WICPixelFormat16bppBGR555,BmpFrameDecode_ReadUncompressed}, 744 {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed}, 745 {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed}, 746 {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed}, 747 {32,0xff000000,0xff0000,0xff00,0xff,&GUID_WICPixelFormat32bppRGBA,BmpFrameDecode_ReadUncompressed}, 748 {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8}, 749 {0} 750 }; 751 752 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl = { 753 BmpFrameDecode_QueryInterface, 754 BmpFrameDecode_AddRef, 755 BmpFrameDecode_Release, 756 BmpFrameDecode_GetSize, 757 BmpFrameDecode_GetPixelFormat, 758 BmpFrameDecode_GetResolution, 759 BmpFrameDecode_CopyPalette, 760 BmpFrameDecode_CopyPixels, 761 BmpFrameDecode_GetMetadataQueryReader, 762 BmpFrameDecode_GetColorContexts, 763 BmpFrameDecode_GetThumbnail 764 }; 765 766 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) 767 { 768 HRESULT hr; 769 ULONG bytestoread, bytesread; 770 LARGE_INTEGER seek; 771 772 if (This->initialized) return WINCODEC_ERR_WRONGSTATE; 773 774 seek.QuadPart = 0; 775 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 776 if (FAILED(hr)) return hr; 777 778 if (!This->packed) 779 { 780 BITMAPFILEHEADER bfh; 781 hr = IStream_Read(stream, &bfh, sizeof(BITMAPFILEHEADER), &bytesread); 782 if (FAILED(hr)) return hr; 783 if (bytesread != sizeof(BITMAPFILEHEADER) || 784 bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL; 785 This->image_offset = bfh.bfOffBits; 786 } 787 788 hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread); 789 if (FAILED(hr)) return hr; 790 if (bytesread != sizeof(DWORD) || 791 (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) && 792 This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) && 793 This->bih.bV5Size != sizeof(BITMAPINFOHEADER) && 794 This->bih.bV5Size != sizeof(BITMAPV4HEADER) && 795 This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL; 796 797 bytestoread = This->bih.bV5Size-sizeof(DWORD); 798 hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread); 799 if (FAILED(hr)) return hr; 800 if (bytestoread != bytesread) return E_FAIL; 801 802 if (This->packed) 803 This->palette_offset = This->bih.bV5Size; 804 else 805 This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size; 806 807 if (This->icoframe) 808 { 809 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 810 { 811 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 812 bch->bcHeight /= 2; 813 } 814 else 815 { 816 This->bih.bV5Height /= 2; 817 } 818 } 819 820 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to 821 read the extra fields */ 822 if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) && 823 This->bih.bV5Compression == BI_BITFIELDS) 824 { 825 hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread); 826 if (FAILED(hr)) return hr; 827 if (bytesread != 12) return E_FAIL; 828 This->bih.bV5AlphaMask = 0; 829 This->palette_offset += 12; 830 } 831 832 /* decide what kind of bitmap this is and how/if we can read it */ 833 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 834 { 835 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 836 TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount); 837 This->bitsperpixel = bch->bcBitCount; 838 This->read_data_func = BmpFrameDecode_ReadUncompressed; 839 switch(bch->bcBitCount) 840 { 841 case 1: 842 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 843 break; 844 case 2: 845 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 846 break; 847 case 4: 848 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 849 break; 850 case 8: 851 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 852 break; 853 case 24: 854 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 855 break; 856 default: 857 This->pixelformat = &GUID_WICPixelFormatUndefined; 858 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount); 859 break; 860 } 861 } 862 else /* struct is compatible with BITMAPINFOHEADER */ 863 { 864 TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 865 switch(This->bih.bV5Compression) 866 { 867 case BI_RGB: 868 This->bitsperpixel = This->bih.bV5BitCount; 869 This->read_data_func = BmpFrameDecode_ReadUncompressed; 870 switch(This->bih.bV5BitCount) 871 { 872 case 1: 873 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 874 break; 875 case 2: 876 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 877 break; 878 case 4: 879 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 880 break; 881 case 8: 882 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 883 break; 884 case 16: 885 This->pixelformat = &GUID_WICPixelFormat16bppBGR555; 886 break; 887 case 24: 888 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 889 break; 890 case 32: 891 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 892 break; 893 default: 894 This->pixelformat = &GUID_WICPixelFormatUndefined; 895 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount); 896 } 897 break; 898 case BI_RLE8: 899 This->bitsperpixel = 32; 900 This->read_data_func = BmpFrameDecode_ReadRLE8; 901 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 902 break; 903 case BI_RLE4: 904 This->bitsperpixel = 32; 905 This->read_data_func = BmpFrameDecode_ReadRLE4; 906 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 907 break; 908 case BI_BITFIELDS: 909 { 910 const struct bitfields_format *format; 911 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2)) 912 { 913 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */ 914 This->bitsperpixel = 0; 915 This->read_data_func = BmpFrameDecode_ReadUnsupported; 916 This->pixelformat = &GUID_WICPixelFormatUndefined; 917 FIXME("Huffman 1D compression is unsupported\n"); 918 break; 919 } 920 This->bitsperpixel = This->bih.bV5BitCount; 921 for (format = bitfields_formats; format->bitcount; format++) 922 { 923 if ((format->bitcount == This->bih.bV5BitCount) && 924 (format->redmask == This->bih.bV5RedMask) && 925 (format->greenmask == This->bih.bV5GreenMask) && 926 (format->bluemask == This->bih.bV5BlueMask) && 927 (format->alphamask == This->bih.bV5AlphaMask)) 928 { 929 This->read_data_func = format->read_data_func; 930 This->pixelformat = format->pixelformat; 931 break; 932 } 933 } 934 if (!format->bitcount) 935 { 936 This->read_data_func = BmpFrameDecode_ReadUncompressed; 937 This->pixelformat = &GUID_WICPixelFormatUndefined; 938 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n", 939 This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask); 940 } 941 break; 942 } 943 default: 944 This->bitsperpixel = 0; 945 This->read_data_func = BmpFrameDecode_ReadUnsupported; 946 This->pixelformat = &GUID_WICPixelFormatUndefined; 947 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 948 break; 949 } 950 } 951 952 if (This->packed) 953 { 954 /* In a packed DIB, the image follows the palette. */ 955 ULONG palette_count, palette_size; 956 if (This->bih.bV5ClrUsed) 957 palette_count = This->bih.bV5ClrUsed; 958 else if (This->bih.bV5BitCount <= 8) 959 palette_count = 1 << This->bih.bV5BitCount; 960 else 961 palette_count = 0; 962 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 963 palette_size = sizeof(RGBTRIPLE) * palette_count; 964 else 965 palette_size = sizeof(RGBQUAD) * palette_count; 966 This->image_offset = This->palette_offset + palette_size; 967 } 968 969 This->initialized = TRUE; 970 971 return S_OK; 972 } 973 974 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 975 void **ppv) 976 { 977 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 978 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 979 980 if (!ppv) return E_INVALIDARG; 981 982 if (IsEqualIID(&IID_IUnknown, iid) || 983 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 984 { 985 *ppv = &This->IWICBitmapDecoder_iface; 986 } 987 else 988 { 989 *ppv = NULL; 990 return E_NOINTERFACE; 991 } 992 993 IUnknown_AddRef((IUnknown*)*ppv); 994 return S_OK; 995 } 996 997 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface) 998 { 999 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1000 ULONG ref = InterlockedIncrement(&This->ref); 1001 1002 TRACE("(%p) refcount=%u\n", iface, ref); 1003 1004 return ref; 1005 } 1006 1007 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface) 1008 { 1009 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1010 ULONG ref = InterlockedDecrement(&This->ref); 1011 1012 TRACE("(%p) refcount=%u\n", iface, ref); 1013 1014 if (ref == 0) 1015 { 1016 if (This->stream) IStream_Release(This->stream); 1017 HeapFree(GetProcessHeap(), 0, This->imagedata); 1018 This->lock.DebugInfo->Spare[0] = 0; 1019 DeleteCriticalSection(&This->lock); 1020 HeapFree(GetProcessHeap(), 0, This); 1021 } 1022 1023 return ref; 1024 } 1025 1026 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 1027 DWORD *capability) 1028 { 1029 HRESULT hr; 1030 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1031 1032 TRACE("(%p,%p,%p)\n", iface, stream, capability); 1033 1034 if (!stream || !capability) return E_INVALIDARG; 1035 1036 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 1037 if (hr != S_OK) return hr; 1038 1039 *capability = This->read_data_func == BmpFrameDecode_ReadUnsupported ? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages; 1040 return S_OK; 1041 } 1042 1043 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 1044 WICDecodeOptions cacheOptions) 1045 { 1046 HRESULT hr; 1047 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1048 1049 EnterCriticalSection(&This->lock); 1050 hr = BmpDecoder_ReadHeaders(This, pIStream); 1051 1052 if (SUCCEEDED(hr)) 1053 { 1054 This->stream = pIStream; 1055 IStream_AddRef(pIStream); 1056 } 1057 LeaveCriticalSection(&This->lock); 1058 1059 return hr; 1060 } 1061 1062 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 1063 GUID *pguidContainerFormat) 1064 { 1065 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID)); 1066 return S_OK; 1067 } 1068 1069 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 1070 IWICBitmapDecoderInfo **ppIDecoderInfo) 1071 { 1072 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 1073 1074 return get_decoder_info(&CLSID_WICBmpDecoder, ppIDecoderInfo); 1075 } 1076 1077 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface, 1078 IWICPalette *pIPalette) 1079 { 1080 TRACE("(%p,%p)\n", iface, pIPalette); 1081 1082 return WINCODEC_ERR_PALETTEUNAVAILABLE; 1083 } 1084 1085 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 1086 IWICMetadataQueryReader **ppIMetadataQueryReader) 1087 { 1088 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1089 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1090 } 1091 1092 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface, 1093 IWICBitmapSource **ppIBitmapSource) 1094 { 1095 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 1096 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1097 } 1098 1099 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface, 1100 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1101 { 1102 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1103 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1104 } 1105 1106 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface, 1107 IWICBitmapSource **ppIThumbnail) 1108 { 1109 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1110 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1111 } 1112 1113 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface, 1114 UINT *pCount) 1115 { 1116 if (!pCount) return E_INVALIDARG; 1117 1118 *pCount = 1; 1119 return S_OK; 1120 } 1121 1122 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface, 1123 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 1124 { 1125 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1126 1127 if (index != 0) return E_INVALIDARG; 1128 1129 if (!This->stream) return WINCODEC_ERR_FRAMEMISSING; 1130 1131 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 1132 IWICBitmapDecoder_AddRef(iface); 1133 1134 return S_OK; 1135 } 1136 1137 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = { 1138 BmpDecoder_QueryInterface, 1139 BmpDecoder_AddRef, 1140 BmpDecoder_Release, 1141 BmpDecoder_QueryCapability, 1142 BmpDecoder_Initialize, 1143 BmpDecoder_GetContainerFormat, 1144 BmpDecoder_GetDecoderInfo, 1145 BmpDecoder_CopyPalette, 1146 BmpDecoder_GetMetadataQueryReader, 1147 BmpDecoder_GetPreview, 1148 BmpDecoder_GetColorContexts, 1149 BmpDecoder_GetThumbnail, 1150 BmpDecoder_GetFrameCount, 1151 BmpDecoder_GetFrame 1152 }; 1153 1154 static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder) 1155 { 1156 BmpDecoder *This; 1157 1158 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder)); 1159 if (!This) return E_OUTOFMEMORY; 1160 1161 This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl; 1162 This->IWICBitmapFrameDecode_iface.lpVtbl = &BmpDecoder_FrameVtbl; 1163 This->ref = 1; 1164 This->initialized = FALSE; 1165 This->stream = NULL; 1166 This->imagedata = NULL; 1167 InitializeCriticalSection(&This->lock); 1168 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock"); 1169 This->packed = packed; 1170 This->icoframe = icoframe; 1171 1172 *ppDecoder = This; 1173 1174 return S_OK; 1175 } 1176 1177 static HRESULT BmpDecoder_Construct(int packed, int icoframe, REFIID iid, void** ppv) 1178 { 1179 BmpDecoder *This; 1180 HRESULT ret; 1181 1182 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1183 1184 *ppv = NULL; 1185 1186 ret = BmpDecoder_Create(packed, icoframe, &This); 1187 if (FAILED(ret)) return ret; 1188 1189 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1190 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1191 1192 return ret; 1193 } 1194 1195 HRESULT BmpDecoder_CreateInstance(REFIID iid, void** ppv) 1196 { 1197 return BmpDecoder_Construct(FALSE, FALSE, iid, ppv); 1198 } 1199 1200 HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv) 1201 { 1202 return BmpDecoder_Construct(TRUE, FALSE, iid, ppv); 1203 } 1204 1205 HRESULT IcoDibDecoder_CreateInstance(BmpDecoder **ppDecoder) 1206 { 1207 return BmpDecoder_Create(TRUE, TRUE, ppDecoder); 1208 } 1209 1210 void BmpDecoder_GetWICDecoder(BmpDecoder *This, IWICBitmapDecoder **ppDecoder) 1211 { 1212 *ppDecoder = &This->IWICBitmapDecoder_iface; 1213 } 1214 1215 /* Return the offset where the mask of an icon might be, or 0 for failure. */ 1216 void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown) 1217 { 1218 assert(This->stream != NULL); 1219 1220 if (This->read_data_func == BmpFrameDecode_ReadUncompressed) 1221 { 1222 /* RGB or BITFIELDS data */ 1223 ULONG width, height, bytesperrow, datasize; 1224 IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height); 1225 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; 1226 datasize = bytesperrow * height; 1227 *mask_offset = This->image_offset + datasize; 1228 } 1229 else 1230 *mask_offset = 0; 1231 1232 *topdown = This->stride > 0; 1233 } 1234