1 /* 2 * Copyright 2010 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 "pshpack1.h" 22 23 typedef struct { 24 BYTE id_length; 25 BYTE colormap_type; 26 BYTE image_type; 27 /* Colormap Specification */ 28 WORD colormap_firstentry; 29 WORD colormap_length; 30 BYTE colormap_entrysize; 31 /* Image Specification */ 32 WORD xorigin; 33 WORD yorigin; 34 WORD width; 35 WORD height; 36 BYTE depth; 37 BYTE image_descriptor; 38 } tga_header; 39 40 #define IMAGETYPE_COLORMAPPED 1 41 #define IMAGETYPE_TRUECOLOR 2 42 #define IMAGETYPE_GRAYSCALE 3 43 #define IMAGETYPE_RLE 8 44 45 #define IMAGE_ATTRIBUTE_BITCOUNT_MASK 0xf 46 #define IMAGE_RIGHTTOLEFT 0x10 47 #define IMAGE_TOPTOBOTTOM 0x20 48 49 typedef struct { 50 DWORD extension_area_offset; 51 DWORD developer_directory_offset; 52 char magic[18]; 53 } tga_footer; 54 55 static const BYTE tga_footer_magic[18] = "TRUEVISION-XFILE."; 56 57 typedef struct { 58 WORD size; 59 char author_name[41]; 60 char author_comments[324]; 61 WORD timestamp[6]; 62 char job_name[41]; 63 WORD job_timestamp[6]; 64 char software_id[41]; 65 WORD software_version; 66 char software_version_letter; 67 DWORD key_color; 68 WORD pixel_width; 69 WORD pixel_height; 70 WORD gamma_numerator; 71 WORD gamma_denominator; 72 DWORD color_correction_offset; 73 DWORD thumbnail_offset; 74 DWORD scanline_offset; 75 BYTE attributes_type; 76 } tga_extension_area; 77 78 #define ATTRIBUTE_NO_ALPHA 0 79 #define ATTRIBUTE_UNDEFINED 1 80 #define ATTRIBUTE_UNDEFINED_PRESERVE 2 81 #define ATTRIBUTE_ALPHA 3 82 #define ATTRIBUTE_PALPHA 4 83 84 #include "poppack.h" 85 86 typedef struct { 87 IWICBitmapDecoder IWICBitmapDecoder_iface; 88 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 89 LONG ref; 90 BOOL initialized; 91 IStream *stream; 92 tga_header header; 93 tga_extension_area extension_area; 94 BYTE *imagebits; 95 BYTE *origin; 96 int stride; 97 ULONG id_offset; 98 ULONG colormap_length; 99 ULONG colormap_offset; 100 ULONG image_offset; 101 ULONG extension_area_offset; 102 ULONG developer_directory_offset; 103 CRITICAL_SECTION lock; 104 } TgaDecoder; 105 106 static inline TgaDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 107 { 108 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapDecoder_iface); 109 } 110 111 static inline TgaDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 112 { 113 return CONTAINING_RECORD(iface, TgaDecoder, IWICBitmapFrameDecode_iface); 114 } 115 116 static HRESULT WINAPI TgaDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 117 void **ppv) 118 { 119 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 120 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 121 122 if (!ppv) return E_INVALIDARG; 123 124 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) 125 { 126 *ppv = &This->IWICBitmapDecoder_iface; 127 } 128 else 129 { 130 *ppv = NULL; 131 return E_NOINTERFACE; 132 } 133 134 IUnknown_AddRef((IUnknown*)*ppv); 135 return S_OK; 136 } 137 138 static ULONG WINAPI TgaDecoder_AddRef(IWICBitmapDecoder *iface) 139 { 140 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 141 ULONG ref = InterlockedIncrement(&This->ref); 142 143 TRACE("(%p) refcount=%u\n", iface, ref); 144 145 return ref; 146 } 147 148 static ULONG WINAPI TgaDecoder_Release(IWICBitmapDecoder *iface) 149 { 150 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 151 ULONG ref = InterlockedDecrement(&This->ref); 152 153 TRACE("(%p) refcount=%u\n", iface, ref); 154 155 if (ref == 0) 156 { 157 This->lock.DebugInfo->Spare[0] = 0; 158 DeleteCriticalSection(&This->lock); 159 if (This->stream) 160 IStream_Release(This->stream); 161 HeapFree(GetProcessHeap(), 0, This->imagebits); 162 HeapFree(GetProcessHeap(), 0, This); 163 } 164 165 return ref; 166 } 167 168 static HRESULT WINAPI TgaDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 169 DWORD *capability) 170 { 171 HRESULT hr; 172 173 TRACE("(%p,%p,%p)\n", iface, stream, capability); 174 175 if (!stream || !capability) return E_INVALIDARG; 176 177 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 178 if (hr != S_OK) return hr; 179 180 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 181 WICBitmapDecoderCapabilityCanDecodeSomeImages; 182 return S_OK; 183 } 184 185 static HRESULT WINAPI TgaDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 186 WICDecodeOptions cacheOptions) 187 { 188 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 189 HRESULT hr=S_OK; 190 DWORD bytesread; 191 LARGE_INTEGER seek; 192 tga_footer footer; 193 int attribute_bitcount; 194 int mapped_depth=0; 195 196 TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions); 197 198 EnterCriticalSection(&This->lock); 199 200 if (This->initialized) 201 { 202 hr = WINCODEC_ERR_WRONGSTATE; 203 goto end; 204 } 205 206 seek.QuadPart = 0; 207 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 208 if (FAILED(hr)) goto end; 209 210 hr = IStream_Read(pIStream, &This->header, sizeof(tga_header), &bytesread); 211 if (SUCCEEDED(hr) && bytesread != sizeof(tga_header)) 212 { 213 TRACE("got only %u bytes\n", bytesread); 214 hr = E_FAIL; 215 } 216 if (FAILED(hr)) goto end; 217 218 TRACE("imagetype=%u, colormap type=%u, depth=%u, image descriptor=0x%x\n", 219 This->header.image_type, This->header.colormap_type, 220 This->header.depth, This->header.image_descriptor); 221 222 /* Sanity checking. Since TGA has no clear identifying markers, we need 223 * to be careful to not load a non-TGA image. */ 224 switch (This->header.image_type) 225 { 226 case IMAGETYPE_COLORMAPPED: 227 case IMAGETYPE_COLORMAPPED|IMAGETYPE_RLE: 228 if (This->header.colormap_type != 1) 229 hr = E_FAIL; 230 mapped_depth = This->header.colormap_entrysize; 231 break; 232 case IMAGETYPE_TRUECOLOR: 233 case IMAGETYPE_TRUECOLOR|IMAGETYPE_RLE: 234 if (This->header.colormap_type != 0 && This->header.colormap_type != 1) 235 hr = E_FAIL; 236 mapped_depth = This->header.depth; 237 break; 238 case IMAGETYPE_GRAYSCALE: 239 case IMAGETYPE_GRAYSCALE|IMAGETYPE_RLE: 240 if (This->header.colormap_type != 0) 241 hr = E_FAIL; 242 mapped_depth = 0; 243 break; 244 default: 245 hr = E_FAIL; 246 } 247 248 if (This->header.depth != 8 && This->header.depth != 16 && 249 This->header.depth != 24 && This->header.depth != 32) 250 hr = E_FAIL; 251 252 if ((This->header.image_descriptor & 0xc0) != 0) 253 hr = E_FAIL; 254 255 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 256 257 if (attribute_bitcount && 258 !((mapped_depth == 32 && attribute_bitcount == 8) || 259 (mapped_depth == 16 && attribute_bitcount == 1))) 260 hr = E_FAIL; 261 262 if (FAILED(hr)) 263 { 264 WARN("bad tga header\n"); 265 goto end; 266 } 267 268 /* Locate data in the file based on the header. */ 269 This->id_offset = sizeof(tga_header); 270 This->colormap_offset = This->id_offset + This->header.id_length; 271 if (This->header.colormap_type == 1) 272 This->colormap_length = ((This->header.colormap_entrysize+7)/8) * This->header.colormap_length; 273 else 274 This->colormap_length = 0; 275 This->image_offset = This->colormap_offset + This->colormap_length; 276 277 /* Read footer if there is one */ 278 seek.QuadPart = -(LONGLONG)sizeof(tga_footer); 279 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_END, NULL); 280 281 if (SUCCEEDED(hr)) { 282 hr = IStream_Read(pIStream, &footer, sizeof(tga_footer), &bytesread); 283 if (SUCCEEDED(hr) && bytesread != sizeof(tga_footer)) 284 { 285 TRACE("got only %u footer bytes\n", bytesread); 286 hr = E_FAIL; 287 } 288 289 if (memcmp(footer.magic, tga_footer_magic, sizeof(tga_footer_magic)) == 0) 290 { 291 This->extension_area_offset = footer.extension_area_offset; 292 This->developer_directory_offset = footer.developer_directory_offset; 293 } 294 else 295 { 296 This->extension_area_offset = 0; 297 This->developer_directory_offset = 0; 298 } 299 } 300 else 301 { 302 /* File is too small to have a footer. */ 303 This->extension_area_offset = 0; 304 This->developer_directory_offset = 0; 305 hr = S_OK; 306 } 307 308 if (This->extension_area_offset) 309 { 310 seek.QuadPart = This->extension_area_offset; 311 hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 312 if (FAILED(hr)) goto end; 313 314 hr = IStream_Read(pIStream, &This->extension_area, sizeof(tga_extension_area), &bytesread); 315 if (SUCCEEDED(hr) && bytesread != sizeof(tga_extension_area)) 316 { 317 TRACE("got only %u extension area bytes\n", bytesread); 318 hr = E_FAIL; 319 } 320 if (SUCCEEDED(hr) && This->extension_area.size < 495) 321 { 322 TRACE("extension area is only %u bytes long\n", This->extension_area.size); 323 hr = E_FAIL; 324 } 325 if (FAILED(hr)) goto end; 326 } 327 328 IStream_AddRef(pIStream); 329 This->stream = pIStream; 330 This->initialized = TRUE; 331 332 end: 333 LeaveCriticalSection(&This->lock); 334 return hr; 335 } 336 337 static HRESULT WINAPI TgaDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 338 GUID *pguidContainerFormat) 339 { 340 memcpy(pguidContainerFormat, &GUID_WineContainerFormatTga, sizeof(GUID)); 341 return S_OK; 342 } 343 344 static HRESULT WINAPI TgaDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 345 IWICBitmapDecoderInfo **ppIDecoderInfo) 346 { 347 HRESULT hr; 348 IWICComponentInfo *compinfo; 349 350 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 351 352 hr = CreateComponentInfo(&CLSID_WineTgaDecoder, &compinfo); 353 if (FAILED(hr)) return hr; 354 355 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 356 (void**)ppIDecoderInfo); 357 358 IWICComponentInfo_Release(compinfo); 359 360 return hr; 361 } 362 363 static HRESULT WINAPI TgaDecoder_CopyPalette(IWICBitmapDecoder *iface, 364 IWICPalette *pIPalette) 365 { 366 FIXME("(%p,%p): stub\n", iface, pIPalette); 367 return E_NOTIMPL; 368 } 369 370 static HRESULT WINAPI TgaDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 371 IWICMetadataQueryReader **ppIMetadataQueryReader) 372 { 373 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 374 return E_NOTIMPL; 375 } 376 377 static HRESULT WINAPI TgaDecoder_GetPreview(IWICBitmapDecoder *iface, 378 IWICBitmapSource **ppIBitmapSource) 379 { 380 FIXME("(%p,%p): stub\n", iface, ppIBitmapSource); 381 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 382 } 383 384 static HRESULT WINAPI TgaDecoder_GetColorContexts(IWICBitmapDecoder *iface, 385 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 386 { 387 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 388 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 389 } 390 391 static HRESULT WINAPI TgaDecoder_GetThumbnail(IWICBitmapDecoder *iface, 392 IWICBitmapSource **ppIThumbnail) 393 { 394 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 395 return WINCODEC_ERR_CODECNOTHUMBNAIL; 396 } 397 398 static HRESULT WINAPI TgaDecoder_GetFrameCount(IWICBitmapDecoder *iface, 399 UINT *pCount) 400 { 401 if (!pCount) return E_INVALIDARG; 402 403 *pCount = 1; 404 return S_OK; 405 } 406 407 static HRESULT WINAPI TgaDecoder_GetFrame(IWICBitmapDecoder *iface, 408 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 409 { 410 TgaDecoder *This = impl_from_IWICBitmapDecoder(iface); 411 TRACE("(%p,%p)\n", iface, ppIBitmapFrame); 412 413 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 414 415 if (index != 0) return E_INVALIDARG; 416 417 IWICBitmapDecoder_AddRef(iface); 418 *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; 419 420 return S_OK; 421 } 422 423 static const IWICBitmapDecoderVtbl TgaDecoder_Vtbl = { 424 TgaDecoder_QueryInterface, 425 TgaDecoder_AddRef, 426 TgaDecoder_Release, 427 TgaDecoder_QueryCapability, 428 TgaDecoder_Initialize, 429 TgaDecoder_GetContainerFormat, 430 TgaDecoder_GetDecoderInfo, 431 TgaDecoder_CopyPalette, 432 TgaDecoder_GetMetadataQueryReader, 433 TgaDecoder_GetPreview, 434 TgaDecoder_GetColorContexts, 435 TgaDecoder_GetThumbnail, 436 TgaDecoder_GetFrameCount, 437 TgaDecoder_GetFrame 438 }; 439 440 static HRESULT WINAPI TgaDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 441 void **ppv) 442 { 443 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 444 445 if (!ppv) return E_INVALIDARG; 446 447 if (IsEqualIID(&IID_IUnknown, iid) || 448 IsEqualIID(&IID_IWICBitmapSource, iid) || 449 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 450 { 451 *ppv = iface; 452 } 453 else 454 { 455 *ppv = NULL; 456 return E_NOINTERFACE; 457 } 458 459 IUnknown_AddRef((IUnknown*)*ppv); 460 return S_OK; 461 } 462 463 static ULONG WINAPI TgaDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) 464 { 465 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 466 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 467 } 468 469 static ULONG WINAPI TgaDecoder_Frame_Release(IWICBitmapFrameDecode *iface) 470 { 471 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 472 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 473 } 474 475 static HRESULT WINAPI TgaDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, 476 UINT *puiWidth, UINT *puiHeight) 477 { 478 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 479 480 *puiWidth = This->header.width; 481 *puiHeight = This->header.height; 482 483 TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); 484 485 return S_OK; 486 } 487 488 static HRESULT WINAPI TgaDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, 489 WICPixelFormatGUID *pPixelFormat) 490 { 491 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 492 int attribute_bitcount; 493 byte attribute_type; 494 495 TRACE("(%p,%p)\n", iface, pPixelFormat); 496 497 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 498 499 if (attribute_bitcount && This->extension_area_offset) 500 attribute_type = This->extension_area.attributes_type; 501 else if (attribute_bitcount) 502 attribute_type = ATTRIBUTE_ALPHA; 503 else 504 attribute_type = ATTRIBUTE_NO_ALPHA; 505 506 switch (This->header.image_type & ~IMAGETYPE_RLE) 507 { 508 case IMAGETYPE_COLORMAPPED: 509 switch (This->header.depth) 510 { 511 case 8: 512 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); 513 break; 514 default: 515 FIXME("Unhandled indexed color depth %u\n", This->header.depth); 516 return E_NOTIMPL; 517 } 518 break; 519 case IMAGETYPE_TRUECOLOR: 520 switch (This->header.depth) 521 { 522 case 16: 523 switch (attribute_type) 524 { 525 case ATTRIBUTE_NO_ALPHA: 526 case ATTRIBUTE_UNDEFINED: 527 case ATTRIBUTE_UNDEFINED_PRESERVE: 528 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGR555, sizeof(GUID)); 529 break; 530 case ATTRIBUTE_ALPHA: 531 case ATTRIBUTE_PALPHA: 532 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppBGRA5551, sizeof(GUID)); 533 break; 534 default: 535 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 536 return E_NOTIMPL; 537 } 538 break; 539 case 24: 540 memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID)); 541 break; 542 case 32: 543 switch (attribute_type) 544 { 545 case ATTRIBUTE_NO_ALPHA: 546 case ATTRIBUTE_UNDEFINED: 547 case ATTRIBUTE_UNDEFINED_PRESERVE: 548 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGR, sizeof(GUID)); 549 break; 550 case ATTRIBUTE_ALPHA: 551 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID)); 552 break; 553 case ATTRIBUTE_PALPHA: 554 memcpy(pPixelFormat, &GUID_WICPixelFormat32bppPBGRA, sizeof(GUID)); 555 break; 556 default: 557 FIXME("Unhandled 32-bit attribute type %u\n", attribute_type); 558 return E_NOTIMPL; 559 } 560 break; 561 default: 562 FIXME("Unhandled truecolor depth %u\n", This->header.depth); 563 return E_NOTIMPL; 564 } 565 break; 566 case IMAGETYPE_GRAYSCALE: 567 switch (This->header.depth) 568 { 569 case 8: 570 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID)); 571 break; 572 case 16: 573 memcpy(pPixelFormat, &GUID_WICPixelFormat16bppGray, sizeof(GUID)); 574 break; 575 default: 576 FIXME("Unhandled grayscale depth %u\n", This->header.depth); 577 return E_NOTIMPL; 578 } 579 break; 580 default: 581 ERR("Unknown image type %u\n", This->header.image_type); 582 return E_FAIL; 583 } 584 585 return S_OK; 586 } 587 588 static HRESULT WINAPI TgaDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, 589 double *pDpiX, double *pDpiY) 590 { 591 FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY); 592 return E_NOTIMPL; 593 } 594 595 static HRESULT WINAPI TgaDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, 596 IWICPalette *pIPalette) 597 { 598 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 599 HRESULT hr=S_OK; 600 WICColor colors[256], *color; 601 BYTE *colormap_data; 602 WORD *wcolormap_data; 603 DWORD *dwcolormap_data; 604 LARGE_INTEGER seek; 605 ULONG bytesread; 606 int depth, attribute_bitcount, attribute_type; 607 int i; 608 609 TRACE("(%p,%p)\n", iface, pIPalette); 610 611 if (!This->colormap_length) 612 { 613 WARN("no colormap present in this file\n"); 614 return WINCODEC_ERR_PALETTEUNAVAILABLE; 615 } 616 617 if (This->header.colormap_firstentry + This->header.colormap_length > 256) 618 { 619 FIXME("cannot read colormap with %i entries starting at %i\n", 620 This->header.colormap_firstentry + This->header.colormap_length, 621 This->header.colormap_firstentry); 622 return E_FAIL; 623 } 624 625 colormap_data = HeapAlloc(GetProcessHeap(), 0, This->colormap_length); 626 if (!colormap_data) return E_OUTOFMEMORY; 627 628 wcolormap_data = (WORD*)colormap_data; 629 dwcolormap_data = (DWORD*)colormap_data; 630 631 EnterCriticalSection(&This->lock); 632 633 seek.QuadPart = This->colormap_offset; 634 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL); 635 636 if (SUCCEEDED(hr)) 637 { 638 hr = IStream_Read(This->stream, colormap_data, This->colormap_length, &bytesread); 639 if (SUCCEEDED(hr) && bytesread != This->colormap_length) 640 { 641 WARN("expected %i bytes in colormap, got %i\n", This->colormap_length, bytesread); 642 hr = E_FAIL; 643 } 644 } 645 646 LeaveCriticalSection(&This->lock); 647 648 if (SUCCEEDED(hr)) 649 { 650 attribute_bitcount = This->header.image_descriptor & IMAGE_ATTRIBUTE_BITCOUNT_MASK; 651 652 if (attribute_bitcount && This->extension_area_offset) 653 attribute_type = This->extension_area.attributes_type; 654 else if (attribute_bitcount) 655 attribute_type = ATTRIBUTE_ALPHA; 656 else 657 attribute_type = ATTRIBUTE_NO_ALPHA; 658 659 depth = This->header.colormap_entrysize; 660 if (depth == 15) 661 { 662 depth = 16; 663 attribute_type = ATTRIBUTE_NO_ALPHA; 664 } 665 666 memset(colors, 0, sizeof(colors)); 667 668 color = &colors[This->header.colormap_firstentry]; 669 670 /* Colormap entries can be in any truecolor format, and we have to convert them. */ 671 switch (depth) 672 { 673 case 16: 674 switch (attribute_type) 675 { 676 case ATTRIBUTE_NO_ALPHA: 677 case ATTRIBUTE_UNDEFINED: 678 case ATTRIBUTE_UNDEFINED_PRESERVE: 679 for (i=0; i<This->header.colormap_length; i++) 680 { 681 WORD srcval = wcolormap_data[i]; 682 *color++=0xff000000 | /* constant 255 alpha */ 683 ((srcval << 9) & 0xf80000) | /* r */ 684 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 685 ((srcval << 6) & 0x00f800) | /* g */ 686 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 687 ((srcval << 3) & 0x0000f8) | /* b */ 688 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 689 } 690 break; 691 case ATTRIBUTE_ALPHA: 692 case ATTRIBUTE_PALPHA: 693 for (i=0; i<This->header.colormap_length; i++) 694 { 695 WORD srcval = wcolormap_data[i]; 696 *color++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */ 697 ((srcval << 9) & 0xf80000) | /* r */ 698 ((srcval << 4) & 0x070000) | /* r - 3 bits */ 699 ((srcval << 6) & 0x00f800) | /* g */ 700 ((srcval << 1) & 0x000700) | /* g - 3 bits */ 701 ((srcval << 3) & 0x0000f8) | /* b */ 702 ((srcval >> 2) & 0x000007); /* b - 3 bits */ 703 } 704 break; 705 default: 706 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 707 hr = E_NOTIMPL; 708 } 709 break; 710 case 24: 711 for (i=0; i<This->header.colormap_length; i++) 712 { 713 *color++=0xff000000 | /* alpha */ 714 colormap_data[i*3+2] | /* red */ 715 colormap_data[i*3+1] | /* green */ 716 colormap_data[i*3]; /* blue */ 717 } 718 break; 719 case 32: 720 switch (attribute_type) 721 { 722 case ATTRIBUTE_NO_ALPHA: 723 case ATTRIBUTE_UNDEFINED: 724 case ATTRIBUTE_UNDEFINED_PRESERVE: 725 for (i=0; i<This->header.colormap_length; i++) 726 *color++=dwcolormap_data[i]|0xff000000; 727 break; 728 case ATTRIBUTE_ALPHA: 729 for (i=0; i<This->header.colormap_length; i++) 730 *color++=dwcolormap_data[i]; 731 break; 732 case ATTRIBUTE_PALPHA: 733 /* FIXME: Unpremultiply alpha */ 734 default: 735 FIXME("Unhandled 16-bit attribute type %u\n", attribute_type); 736 hr = E_NOTIMPL; 737 } 738 break; 739 default: 740 FIXME("Unhandled truecolor depth %u\n", This->header.depth); 741 hr = E_NOTIMPL; 742 } 743 } 744 745 HeapFree(GetProcessHeap(), 0, colormap_data); 746 747 if (SUCCEEDED(hr)) 748 hr = IWICPalette_InitializeCustom(pIPalette, colors, 256); 749 750 return hr; 751 } 752 753 static HRESULT TgaDecoder_ReadRLE(TgaDecoder *This, BYTE *imagebits, int datasize) 754 { 755 int i=0, j, bytesperpixel; 756 ULONG bytesread; 757 HRESULT hr=S_OK; 758 759 bytesperpixel = This->header.depth / 8; 760 761 while (i<datasize) 762 { 763 BYTE rc; 764 int count, size; 765 BYTE pixeldata[4]; 766 767 hr = IStream_Read(This->stream, &rc, 1, &bytesread); 768 if (bytesread != 1) hr = E_FAIL; 769 if (FAILED(hr)) break; 770 771 count = (rc&0x7f)+1; 772 size = count * bytesperpixel; 773 774 if (size + i > datasize) 775 { 776 WARN("RLE packet too large\n"); 777 hr = E_FAIL; 778 break; 779 } 780 781 if (rc&0x80) 782 { 783 /* Run-length packet */ 784 hr = IStream_Read(This->stream, pixeldata, bytesperpixel, &bytesread); 785 if (bytesread != bytesperpixel) hr = E_FAIL; 786 if (FAILED(hr)) break; 787 788 if (bytesperpixel == 1) 789 memset(&imagebits[i], pixeldata[0], count); 790 else 791 { 792 for (j=0; j<count; j++) 793 memcpy(&imagebits[i+j*bytesperpixel], pixeldata, bytesperpixel); 794 } 795 } 796 else 797 { 798 /* Raw packet */ 799 hr = IStream_Read(This->stream, &imagebits[i], size, &bytesread); 800 if (bytesread != size) hr = E_FAIL; 801 if (FAILED(hr)) break; 802 } 803 804 i += size; 805 } 806 807 return hr; 808 } 809 810 static HRESULT TgaDecoder_ReadImage(TgaDecoder *This) 811 { 812 HRESULT hr=S_OK; 813 int datasize; 814 LARGE_INTEGER seek; 815 ULONG bytesread; 816 817 if (This->imagebits) 818 return S_OK; 819 820 EnterCriticalSection(&This->lock); 821 822 if (!This->imagebits) 823 { 824 if (This->header.image_descriptor & IMAGE_RIGHTTOLEFT) 825 { 826 FIXME("Right to left image reading not implemented\n"); 827 hr = E_NOTIMPL; 828 } 829 830 if (SUCCEEDED(hr)) 831 { 832 datasize = This->header.width * This->header.height * (This->header.depth / 8); 833 This->imagebits = HeapAlloc(GetProcessHeap(), 0, datasize); 834 if (!This->imagebits) hr = E_OUTOFMEMORY; 835 } 836 837 if (SUCCEEDED(hr)) 838 { 839 seek.QuadPart = This->image_offset; 840 hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL); 841 } 842 843 if (SUCCEEDED(hr)) 844 { 845 if (This->header.image_type & IMAGETYPE_RLE) 846 { 847 hr = TgaDecoder_ReadRLE(This, This->imagebits, datasize); 848 } 849 else 850 { 851 hr = IStream_Read(This->stream, This->imagebits, datasize, &bytesread); 852 if (SUCCEEDED(hr) && bytesread != datasize) 853 hr = E_FAIL; 854 } 855 } 856 857 if (SUCCEEDED(hr)) 858 { 859 if (This->header.image_descriptor & IMAGE_TOPTOBOTTOM) 860 { 861 This->origin = This->imagebits; 862 This->stride = This->header.width * (This->header.depth / 8); 863 } 864 else 865 { 866 This->stride = -This->header.width * (This->header.depth / 8); 867 This->origin = This->imagebits + This->header.width * (This->header.height - 1) * (This->header.depth / 8); 868 } 869 } 870 else 871 { 872 HeapFree(GetProcessHeap(), 0, This->imagebits); 873 This->imagebits = NULL; 874 } 875 } 876 877 LeaveCriticalSection(&This->lock); 878 879 return hr; 880 } 881 882 static HRESULT WINAPI TgaDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, 883 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 884 { 885 TgaDecoder *This = impl_from_IWICBitmapFrameDecode(iface); 886 HRESULT hr; 887 888 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 889 890 hr = TgaDecoder_ReadImage(This); 891 892 if (SUCCEEDED(hr)) 893 { 894 hr = copy_pixels(This->header.depth, This->origin, 895 This->header.width, This->header.height, This->stride, 896 prc, cbStride, cbBufferSize, pbBuffer); 897 } 898 899 return hr; 900 } 901 902 static HRESULT WINAPI TgaDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 903 IWICMetadataQueryReader **ppIMetadataQueryReader) 904 { 905 FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); 906 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 907 } 908 909 static HRESULT WINAPI TgaDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, 910 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 911 { 912 FIXME("(%p,%u,%p,%p): stub\n", iface, cCount, ppIColorContexts, pcActualCount); 913 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 914 } 915 916 static HRESULT WINAPI TgaDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, 917 IWICBitmapSource **ppIThumbnail) 918 { 919 FIXME("(%p,%p): stub\n", iface, ppIThumbnail); 920 return WINCODEC_ERR_CODECNOTHUMBNAIL; 921 } 922 923 static const IWICBitmapFrameDecodeVtbl TgaDecoder_Frame_Vtbl = { 924 TgaDecoder_Frame_QueryInterface, 925 TgaDecoder_Frame_AddRef, 926 TgaDecoder_Frame_Release, 927 TgaDecoder_Frame_GetSize, 928 TgaDecoder_Frame_GetPixelFormat, 929 TgaDecoder_Frame_GetResolution, 930 TgaDecoder_Frame_CopyPalette, 931 TgaDecoder_Frame_CopyPixels, 932 TgaDecoder_Frame_GetMetadataQueryReader, 933 TgaDecoder_Frame_GetColorContexts, 934 TgaDecoder_Frame_GetThumbnail 935 }; 936 937 HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv) 938 { 939 TgaDecoder *This; 940 HRESULT ret; 941 942 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 943 944 *ppv = NULL; 945 946 This = HeapAlloc(GetProcessHeap(), 0, sizeof(TgaDecoder)); 947 if (!This) return E_OUTOFMEMORY; 948 949 This->IWICBitmapDecoder_iface.lpVtbl = &TgaDecoder_Vtbl; 950 This->IWICBitmapFrameDecode_iface.lpVtbl = &TgaDecoder_Frame_Vtbl; 951 This->ref = 1; 952 This->initialized = FALSE; 953 This->stream = NULL; 954 This->imagebits = NULL; 955 InitializeCriticalSection(&This->lock); 956 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TgaDecoder.lock"); 957 958 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 959 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 960 961 return ret; 962 } 963