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