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,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8}, 748 {0} 749 }; 750 751 static const IWICBitmapFrameDecodeVtbl BmpDecoder_FrameVtbl = { 752 BmpFrameDecode_QueryInterface, 753 BmpFrameDecode_AddRef, 754 BmpFrameDecode_Release, 755 BmpFrameDecode_GetSize, 756 BmpFrameDecode_GetPixelFormat, 757 BmpFrameDecode_GetResolution, 758 BmpFrameDecode_CopyPalette, 759 BmpFrameDecode_CopyPixels, 760 BmpFrameDecode_GetMetadataQueryReader, 761 BmpFrameDecode_GetColorContexts, 762 BmpFrameDecode_GetThumbnail 763 }; 764 765 static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) 766 { 767 HRESULT hr; 768 ULONG bytestoread, bytesread; 769 LARGE_INTEGER seek; 770 771 if (This->initialized) return WINCODEC_ERR_WRONGSTATE; 772 773 seek.QuadPart = 0; 774 hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL); 775 if (FAILED(hr)) return hr; 776 777 if (!This->packed) 778 { 779 BITMAPFILEHEADER bfh; 780 hr = IStream_Read(stream, &bfh, sizeof(BITMAPFILEHEADER), &bytesread); 781 if (FAILED(hr)) return hr; 782 if (bytesread != sizeof(BITMAPFILEHEADER) || 783 bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL; 784 This->image_offset = bfh.bfOffBits; 785 } 786 787 hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread); 788 if (FAILED(hr)) return hr; 789 if (bytesread != sizeof(DWORD) || 790 (This->bih.bV5Size != sizeof(BITMAPCOREHEADER) && 791 This->bih.bV5Size != sizeof(BITMAPCOREHEADER2) && 792 This->bih.bV5Size != sizeof(BITMAPINFOHEADER) && 793 This->bih.bV5Size != sizeof(BITMAPV4HEADER) && 794 This->bih.bV5Size != sizeof(BITMAPV5HEADER))) return E_FAIL; 795 796 bytestoread = This->bih.bV5Size-sizeof(DWORD); 797 hr = IStream_Read(stream, &This->bih.bV5Width, bytestoread, &bytesread); 798 if (FAILED(hr)) return hr; 799 if (bytestoread != bytesread) return E_FAIL; 800 801 if (This->packed) 802 This->palette_offset = This->bih.bV5Size; 803 else 804 This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size; 805 806 if (This->icoframe) 807 { 808 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 809 { 810 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 811 bch->bcHeight /= 2; 812 } 813 else 814 { 815 This->bih.bV5Height /= 2; 816 } 817 } 818 819 /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to 820 read the extra fields */ 821 if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) && 822 This->bih.bV5Compression == BI_BITFIELDS) 823 { 824 hr = IStream_Read(stream, &This->bih.bV5RedMask, 12, &bytesread); 825 if (FAILED(hr)) return hr; 826 if (bytesread != 12) return E_FAIL; 827 This->bih.bV5AlphaMask = 0; 828 This->palette_offset += 12; 829 } 830 831 /* decide what kind of bitmap this is and how/if we can read it */ 832 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 833 { 834 BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih; 835 TRACE("BITMAPCOREHEADER with depth=%i\n", bch->bcBitCount); 836 This->bitsperpixel = bch->bcBitCount; 837 This->read_data_func = BmpFrameDecode_ReadUncompressed; 838 switch(bch->bcBitCount) 839 { 840 case 1: 841 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 842 break; 843 case 2: 844 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 845 break; 846 case 4: 847 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 848 break; 849 case 8: 850 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 851 break; 852 case 24: 853 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 854 break; 855 default: 856 This->pixelformat = &GUID_WICPixelFormatUndefined; 857 WARN("unsupported bit depth %i for BITMAPCOREHEADER\n", bch->bcBitCount); 858 break; 859 } 860 } 861 else /* struct is compatible with BITMAPINFOHEADER */ 862 { 863 TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 864 switch(This->bih.bV5Compression) 865 { 866 case BI_RGB: 867 This->bitsperpixel = This->bih.bV5BitCount; 868 This->read_data_func = BmpFrameDecode_ReadUncompressed; 869 switch(This->bih.bV5BitCount) 870 { 871 case 1: 872 This->pixelformat = &GUID_WICPixelFormat1bppIndexed; 873 break; 874 case 2: 875 This->pixelformat = &GUID_WICPixelFormat2bppIndexed; 876 break; 877 case 4: 878 This->pixelformat = &GUID_WICPixelFormat4bppIndexed; 879 break; 880 case 8: 881 This->pixelformat = &GUID_WICPixelFormat8bppIndexed; 882 break; 883 case 16: 884 This->pixelformat = &GUID_WICPixelFormat16bppBGR555; 885 break; 886 case 24: 887 This->pixelformat = &GUID_WICPixelFormat24bppBGR; 888 break; 889 case 32: 890 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 891 break; 892 default: 893 This->pixelformat = &GUID_WICPixelFormatUndefined; 894 FIXME("unsupported bit depth %i for uncompressed RGB\n", This->bih.bV5BitCount); 895 } 896 break; 897 case BI_RLE8: 898 This->bitsperpixel = 32; 899 This->read_data_func = BmpFrameDecode_ReadRLE8; 900 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 901 break; 902 case BI_RLE4: 903 This->bitsperpixel = 32; 904 This->read_data_func = BmpFrameDecode_ReadRLE4; 905 This->pixelformat = &GUID_WICPixelFormat32bppBGR; 906 break; 907 case BI_BITFIELDS: 908 { 909 const struct bitfields_format *format; 910 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER2)) 911 { 912 /* BCH2 doesn't support bitfields; this is Huffman 1D compression */ 913 This->bitsperpixel = 0; 914 This->read_data_func = BmpFrameDecode_ReadUnsupported; 915 This->pixelformat = &GUID_WICPixelFormatUndefined; 916 FIXME("Huffman 1D compression is unsupported\n"); 917 break; 918 } 919 This->bitsperpixel = This->bih.bV5BitCount; 920 for (format = bitfields_formats; format->bitcount; format++) 921 { 922 if ((format->bitcount == This->bih.bV5BitCount) && 923 (format->redmask == This->bih.bV5RedMask) && 924 (format->greenmask == This->bih.bV5GreenMask) && 925 (format->bluemask == This->bih.bV5BlueMask) && 926 (format->alphamask == This->bih.bV5AlphaMask)) 927 { 928 This->read_data_func = format->read_data_func; 929 This->pixelformat = format->pixelformat; 930 break; 931 } 932 } 933 if (!format->bitcount) 934 { 935 This->read_data_func = BmpFrameDecode_ReadUncompressed; 936 This->pixelformat = &GUID_WICPixelFormatUndefined; 937 FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n", 938 This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask); 939 } 940 break; 941 } 942 default: 943 This->bitsperpixel = 0; 944 This->read_data_func = BmpFrameDecode_ReadUnsupported; 945 This->pixelformat = &GUID_WICPixelFormatUndefined; 946 FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); 947 break; 948 } 949 } 950 951 if (This->packed) 952 { 953 /* In a packed DIB, the image follows the palette. */ 954 ULONG palette_count, palette_size; 955 if (This->bih.bV5ClrUsed) 956 palette_count = This->bih.bV5ClrUsed; 957 else if (This->bih.bV5BitCount <= 8) 958 palette_count = 1 << This->bih.bV5BitCount; 959 else 960 palette_count = 0; 961 if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER)) 962 palette_size = sizeof(RGBTRIPLE) * palette_count; 963 else 964 palette_size = sizeof(RGBQUAD) * palette_count; 965 This->image_offset = This->palette_offset + palette_size; 966 } 967 968 This->initialized = TRUE; 969 970 return S_OK; 971 } 972 973 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 974 void **ppv) 975 { 976 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 977 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 978 979 if (!ppv) return E_INVALIDARG; 980 981 if (IsEqualIID(&IID_IUnknown, iid) || 982 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 983 { 984 *ppv = &This->IWICBitmapDecoder_iface; 985 } 986 else 987 { 988 *ppv = NULL; 989 return E_NOINTERFACE; 990 } 991 992 IUnknown_AddRef((IUnknown*)*ppv); 993 return S_OK; 994 } 995 996 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface) 997 { 998 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 999 ULONG ref = InterlockedIncrement(&This->ref); 1000 1001 TRACE("(%p) refcount=%u\n", iface, ref); 1002 1003 return ref; 1004 } 1005 1006 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface) 1007 { 1008 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1009 ULONG ref = InterlockedDecrement(&This->ref); 1010 1011 TRACE("(%p) refcount=%u\n", iface, ref); 1012 1013 if (ref == 0) 1014 { 1015 if (This->stream) IStream_Release(This->stream); 1016 HeapFree(GetProcessHeap(), 0, This->imagedata); 1017 This->lock.DebugInfo->Spare[0] = 0; 1018 DeleteCriticalSection(&This->lock); 1019 HeapFree(GetProcessHeap(), 0, This); 1020 } 1021 1022 return ref; 1023 } 1024 1025 static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 1026 DWORD *capability) 1027 { 1028 HRESULT hr; 1029 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1030 1031 TRACE("(%p,%p,%p)\n", iface, stream, capability); 1032 1033 if (!stream || !capability) return E_INVALIDARG; 1034 1035 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 1036 if (hr != S_OK) return hr; 1037 1038 *capability = This->read_data_func == BmpFrameDecode_ReadUnsupported ? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages; 1039 return S_OK; 1040 } 1041 1042 static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 1043 WICDecodeOptions cacheOptions) 1044 { 1045 HRESULT hr; 1046 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1047 1048 EnterCriticalSection(&This->lock); 1049 hr = BmpDecoder_ReadHeaders(This, pIStream); 1050 1051 if (SUCCEEDED(hr)) 1052 { 1053 This->stream = pIStream; 1054 IStream_AddRef(pIStream); 1055 } 1056 LeaveCriticalSection(&This->lock); 1057 1058 return hr; 1059 } 1060 1061 static HRESULT WINAPI BmpDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 1062 GUID *pguidContainerFormat) 1063 { 1064 memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID)); 1065 return S_OK; 1066 } 1067 1068 static HRESULT WINAPI BmpDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 1069 IWICBitmapDecoderInfo **ppIDecoderInfo) 1070 { 1071 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 1072 1073 return get_decoder_info(&CLSID_WICBmpDecoder, ppIDecoderInfo); 1074 } 1075 1076 static HRESULT WINAPI BmpDecoder_CopyPalette(IWICBitmapDecoder *iface, 1077 IWICPalette *pIPalette) 1078 { 1079 TRACE("(%p,%p)\n", iface, pIPalette); 1080 1081 return WINCODEC_ERR_PALETTEUNAVAILABLE; 1082 } 1083 1084 static HRESULT WINAPI BmpDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 1085 IWICMetadataQueryReader **ppIMetadataQueryReader) 1086 { 1087 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1088 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1089 } 1090 1091 static HRESULT WINAPI BmpDecoder_GetPreview(IWICBitmapDecoder *iface, 1092 IWICBitmapSource **ppIBitmapSource) 1093 { 1094 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 1095 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1096 } 1097 1098 static HRESULT WINAPI BmpDecoder_GetColorContexts(IWICBitmapDecoder *iface, 1099 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1100 { 1101 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1102 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1103 } 1104 1105 static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface, 1106 IWICBitmapSource **ppIThumbnail) 1107 { 1108 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1109 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1110 } 1111 1112 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface, 1113 UINT *pCount) 1114 { 1115 if (!pCount) return E_INVALIDARG; 1116 1117 *pCount = 1; 1118 return S_OK; 1119 } 1120 1121 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface, 1122 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 1123 { 1124 BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); 1125 1126 if (index != 0) return E_INVALIDARG; 1127 1128 if (!This->stream) return WINCODEC_ERR_FRAMEMISSING; 1129 1130 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 1131 IWICBitmapDecoder_AddRef(iface); 1132 1133 return S_OK; 1134 } 1135 1136 static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = { 1137 BmpDecoder_QueryInterface, 1138 BmpDecoder_AddRef, 1139 BmpDecoder_Release, 1140 BmpDecoder_QueryCapability, 1141 BmpDecoder_Initialize, 1142 BmpDecoder_GetContainerFormat, 1143 BmpDecoder_GetDecoderInfo, 1144 BmpDecoder_CopyPalette, 1145 BmpDecoder_GetMetadataQueryReader, 1146 BmpDecoder_GetPreview, 1147 BmpDecoder_GetColorContexts, 1148 BmpDecoder_GetThumbnail, 1149 BmpDecoder_GetFrameCount, 1150 BmpDecoder_GetFrame 1151 }; 1152 1153 static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder) 1154 { 1155 BmpDecoder *This; 1156 1157 This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder)); 1158 if (!This) return E_OUTOFMEMORY; 1159 1160 This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl; 1161 This->IWICBitmapFrameDecode_iface.lpVtbl = &BmpDecoder_FrameVtbl; 1162 This->ref = 1; 1163 This->initialized = FALSE; 1164 This->stream = NULL; 1165 This->imagedata = NULL; 1166 InitializeCriticalSection(&This->lock); 1167 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock"); 1168 This->packed = packed; 1169 This->icoframe = icoframe; 1170 1171 *ppDecoder = This; 1172 1173 return S_OK; 1174 } 1175 1176 static HRESULT BmpDecoder_Construct(int packed, int icoframe, REFIID iid, void** ppv) 1177 { 1178 BmpDecoder *This; 1179 HRESULT ret; 1180 1181 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1182 1183 *ppv = NULL; 1184 1185 ret = BmpDecoder_Create(packed, icoframe, &This); 1186 if (FAILED(ret)) return ret; 1187 1188 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1189 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1190 1191 return ret; 1192 } 1193 1194 HRESULT BmpDecoder_CreateInstance(REFIID iid, void** ppv) 1195 { 1196 return BmpDecoder_Construct(FALSE, FALSE, iid, ppv); 1197 } 1198 1199 HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv) 1200 { 1201 return BmpDecoder_Construct(TRUE, FALSE, iid, ppv); 1202 } 1203 1204 HRESULT IcoDibDecoder_CreateInstance(BmpDecoder **ppDecoder) 1205 { 1206 return BmpDecoder_Create(TRUE, TRUE, ppDecoder); 1207 } 1208 1209 void BmpDecoder_GetWICDecoder(BmpDecoder *This, IWICBitmapDecoder **ppDecoder) 1210 { 1211 *ppDecoder = &This->IWICBitmapDecoder_iface; 1212 } 1213 1214 /* Return the offset where the mask of an icon might be, or 0 for failure. */ 1215 void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown) 1216 { 1217 assert(This->stream != NULL); 1218 1219 if (This->read_data_func == BmpFrameDecode_ReadUncompressed) 1220 { 1221 /* RGB or BITFIELDS data */ 1222 ULONG width, height, bytesperrow, datasize; 1223 IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height); 1224 bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; 1225 datasize = bytesperrow * height; 1226 *mask_offset = This->image_offset + datasize; 1227 } 1228 else 1229 *mask_offset = 0; 1230 1231 *topdown = This->stride > 0; 1232 } 1233