1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * Copyright 2012 Dmitry Timoshkov 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 18 */ 19 20 #include "wincodecs_private.h" 21 22 #include <ole2.h> 23 24 #include "ungif.h" 25 26 static LPWSTR strdupAtoW(const char *src) 27 { 28 int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); 29 LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 30 if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len); 31 return dst; 32 } 33 34 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options, 35 MetadataItem **items, DWORD *count) 36 { 37 #include "pshpack1.h" 38 struct logical_screen_descriptor 39 { 40 char signature[6]; 41 USHORT width; 42 USHORT height; 43 BYTE packed; 44 /* global_color_table_flag : 1; 45 * color_resolution : 3; 46 * sort_flag : 1; 47 * global_color_table_size : 3; 48 */ 49 BYTE background_color_index; 50 BYTE pixel_aspect_ratio; 51 } lsd_data; 52 #include "poppack.h" 53 HRESULT hr; 54 ULONG bytesread, i; 55 MetadataItem *result; 56 57 *items = NULL; 58 *count = 0; 59 60 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread); 61 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK; 62 63 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9); 64 if (!result) return E_OUTOFMEMORY; 65 66 for (i = 0; i < 9; i++) 67 { 68 PropVariantInit(&result[i].schema); 69 PropVariantInit(&result[i].id); 70 PropVariantInit(&result[i].value); 71 } 72 73 result[0].id.vt = VT_LPWSTR; 74 result[0].id.u.pwszVal = strdupAtoW("Signature"); 75 result[0].value.vt = VT_UI1|VT_VECTOR; 76 result[0].value.u.caub.cElems = sizeof(lsd_data.signature); 77 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature)); 78 memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature)); 79 80 result[1].id.vt = VT_LPWSTR; 81 result[1].id.u.pwszVal = strdupAtoW("Width"); 82 result[1].value.vt = VT_UI2; 83 result[1].value.u.uiVal = lsd_data.width; 84 85 result[2].id.vt = VT_LPWSTR; 86 result[2].id.u.pwszVal = strdupAtoW("Height"); 87 result[2].value.vt = VT_UI2; 88 result[2].value.u.uiVal = lsd_data.height; 89 90 result[3].id.vt = VT_LPWSTR; 91 result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag"); 92 result[3].value.vt = VT_BOOL; 93 result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1; 94 95 result[4].id.vt = VT_LPWSTR; 96 result[4].id.u.pwszVal = strdupAtoW("ColorResolution"); 97 result[4].value.vt = VT_UI1; 98 result[4].value.u.bVal = (lsd_data.packed >> 4) & 7; 99 100 result[5].id.vt = VT_LPWSTR; 101 result[5].id.u.pwszVal = strdupAtoW("SortFlag"); 102 result[5].value.vt = VT_BOOL; 103 result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1; 104 105 result[6].id.vt = VT_LPWSTR; 106 result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize"); 107 result[6].value.vt = VT_UI1; 108 result[6].value.u.bVal = lsd_data.packed & 7; 109 110 result[7].id.vt = VT_LPWSTR; 111 result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex"); 112 result[7].value.vt = VT_UI1; 113 result[7].value.u.bVal = lsd_data.background_color_index; 114 115 result[8].id.vt = VT_LPWSTR; 116 result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio"); 117 result[8].value.vt = VT_UI1; 118 result[8].value.u.bVal = lsd_data.pixel_aspect_ratio; 119 120 *items = result; 121 *count = 9; 122 123 return S_OK; 124 } 125 126 static const MetadataHandlerVtbl LSDReader_Vtbl = { 127 0, 128 &CLSID_WICLSDMetadataReader, 129 load_LSD_metadata 130 }; 131 132 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv) 133 { 134 return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv); 135 } 136 137 #include "pshpack1.h" 138 struct image_descriptor 139 { 140 USHORT left; 141 USHORT top; 142 USHORT width; 143 USHORT height; 144 BYTE packed; 145 /* local_color_table_flag : 1; 146 * interlace_flag : 1; 147 * sort_flag : 1; 148 * reserved : 2; 149 * local_color_table_size : 3; 150 */ 151 }; 152 #include "poppack.h" 153 154 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options, 155 MetadataItem **items, DWORD *count) 156 { 157 struct image_descriptor imd_data; 158 HRESULT hr; 159 ULONG bytesread, i; 160 MetadataItem *result; 161 162 *items = NULL; 163 *count = 0; 164 165 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread); 166 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK; 167 168 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8); 169 if (!result) return E_OUTOFMEMORY; 170 171 for (i = 0; i < 8; i++) 172 { 173 PropVariantInit(&result[i].schema); 174 PropVariantInit(&result[i].id); 175 PropVariantInit(&result[i].value); 176 } 177 178 result[0].id.vt = VT_LPWSTR; 179 result[0].id.u.pwszVal = strdupAtoW("Left"); 180 result[0].value.vt = VT_UI2; 181 result[0].value.u.uiVal = imd_data.left; 182 183 result[1].id.vt = VT_LPWSTR; 184 result[1].id.u.pwszVal = strdupAtoW("Top"); 185 result[1].value.vt = VT_UI2; 186 result[1].value.u.uiVal = imd_data.top; 187 188 result[2].id.vt = VT_LPWSTR; 189 result[2].id.u.pwszVal = strdupAtoW("Width"); 190 result[2].value.vt = VT_UI2; 191 result[2].value.u.uiVal = imd_data.width; 192 193 result[3].id.vt = VT_LPWSTR; 194 result[3].id.u.pwszVal = strdupAtoW("Height"); 195 result[3].value.vt = VT_UI2; 196 result[3].value.u.uiVal = imd_data.height; 197 198 result[4].id.vt = VT_LPWSTR; 199 result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag"); 200 result[4].value.vt = VT_BOOL; 201 result[4].value.u.boolVal = (imd_data.packed >> 7) & 1; 202 203 result[5].id.vt = VT_LPWSTR; 204 result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag"); 205 result[5].value.vt = VT_BOOL; 206 result[5].value.u.boolVal = (imd_data.packed >> 6) & 1; 207 208 result[6].id.vt = VT_LPWSTR; 209 result[6].id.u.pwszVal = strdupAtoW("SortFlag"); 210 result[6].value.vt = VT_BOOL; 211 result[6].value.u.boolVal = (imd_data.packed >> 5) & 1; 212 213 result[7].id.vt = VT_LPWSTR; 214 result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize"); 215 result[7].value.vt = VT_UI1; 216 result[7].value.u.bVal = imd_data.packed & 7; 217 218 *items = result; 219 *count = 8; 220 221 return S_OK; 222 } 223 224 static const MetadataHandlerVtbl IMDReader_Vtbl = { 225 0, 226 &CLSID_WICIMDMetadataReader, 227 load_IMD_metadata 228 }; 229 230 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv) 231 { 232 return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv); 233 } 234 235 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options, 236 MetadataItem **items, DWORD *count) 237 { 238 #include "pshpack1.h" 239 struct graphic_control_extension 240 { 241 BYTE packed; 242 /* reservred: 3; 243 * disposal : 3; 244 * user_input_flag : 1; 245 * transparency_flag : 1; 246 */ 247 USHORT delay; 248 BYTE transparent_color_index; 249 } gce_data; 250 #include "poppack.h" 251 HRESULT hr; 252 ULONG bytesread, i; 253 MetadataItem *result; 254 255 *items = NULL; 256 *count = 0; 257 258 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread); 259 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK; 260 261 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5); 262 if (!result) return E_OUTOFMEMORY; 263 264 for (i = 0; i < 5; i++) 265 { 266 PropVariantInit(&result[i].schema); 267 PropVariantInit(&result[i].id); 268 PropVariantInit(&result[i].value); 269 } 270 271 result[0].id.vt = VT_LPWSTR; 272 result[0].id.u.pwszVal = strdupAtoW("Disposal"); 273 result[0].value.vt = VT_UI1; 274 result[0].value.u.bVal = (gce_data.packed >> 2) & 7; 275 276 result[1].id.vt = VT_LPWSTR; 277 result[1].id.u.pwszVal = strdupAtoW("UserInputFlag"); 278 result[1].value.vt = VT_BOOL; 279 result[1].value.u.boolVal = (gce_data.packed >> 1) & 1; 280 281 result[2].id.vt = VT_LPWSTR; 282 result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag"); 283 result[2].value.vt = VT_BOOL; 284 result[2].value.u.boolVal = gce_data.packed & 1; 285 286 result[3].id.vt = VT_LPWSTR; 287 result[3].id.u.pwszVal = strdupAtoW("Delay"); 288 result[3].value.vt = VT_UI2; 289 result[3].value.u.uiVal = gce_data.delay; 290 291 result[4].id.vt = VT_LPWSTR; 292 result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex"); 293 result[4].value.vt = VT_UI1; 294 result[4].value.u.bVal = gce_data.transparent_color_index; 295 296 *items = result; 297 *count = 5; 298 299 return S_OK; 300 } 301 302 static const MetadataHandlerVtbl GCEReader_Vtbl = { 303 0, 304 &CLSID_WICGCEMetadataReader, 305 load_GCE_metadata 306 }; 307 308 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv) 309 { 310 return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv); 311 } 312 313 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options, 314 MetadataItem **items, DWORD *count) 315 { 316 #include "pshpack1.h" 317 struct application_extension 318 { 319 BYTE extension_introducer; 320 BYTE extension_label; 321 BYTE block_size; 322 BYTE application[11]; 323 } ape_data; 324 #include "poppack.h" 325 HRESULT hr; 326 ULONG bytesread, data_size, i; 327 MetadataItem *result; 328 BYTE subblock_size; 329 BYTE *data; 330 331 *items = NULL; 332 *count = 0; 333 334 hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread); 335 if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK; 336 if (ape_data.extension_introducer != 0x21 || 337 ape_data.extension_label != APPLICATION_EXT_FUNC_CODE || 338 ape_data.block_size != 11) 339 return S_OK; 340 341 data = NULL; 342 data_size = 0; 343 344 for (;;) 345 { 346 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread); 347 if (FAILED(hr) || bytesread != sizeof(subblock_size)) 348 { 349 HeapFree(GetProcessHeap(), 0, data); 350 return S_OK; 351 } 352 if (!subblock_size) break; 353 354 if (!data) 355 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1); 356 else 357 { 358 BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1); 359 if (!new_data) 360 { 361 HeapFree(GetProcessHeap(), 0, data); 362 return S_OK; 363 } 364 data = new_data; 365 } 366 data[data_size] = subblock_size; 367 hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread); 368 if (FAILED(hr) || bytesread != subblock_size) 369 { 370 HeapFree(GetProcessHeap(), 0, data); 371 return S_OK; 372 } 373 data_size += subblock_size + 1; 374 } 375 376 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2); 377 if (!result) 378 { 379 HeapFree(GetProcessHeap(), 0, data); 380 return E_OUTOFMEMORY; 381 } 382 383 for (i = 0; i < 2; i++) 384 { 385 PropVariantInit(&result[i].schema); 386 PropVariantInit(&result[i].id); 387 PropVariantInit(&result[i].value); 388 } 389 390 result[0].id.vt = VT_LPWSTR; 391 result[0].id.u.pwszVal = strdupAtoW("Application"); 392 result[0].value.vt = VT_UI1|VT_VECTOR; 393 result[0].value.u.caub.cElems = sizeof(ape_data.application); 394 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application)); 395 memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application)); 396 397 result[1].id.vt = VT_LPWSTR; 398 result[1].id.u.pwszVal = strdupAtoW("Data"); 399 result[1].value.vt = VT_UI1|VT_VECTOR; 400 result[1].value.u.caub.cElems = data_size; 401 result[1].value.u.caub.pElems = data; 402 403 *items = result; 404 *count = 2; 405 406 return S_OK; 407 } 408 409 static const MetadataHandlerVtbl APEReader_Vtbl = { 410 0, 411 &CLSID_WICAPEMetadataReader, 412 load_APE_metadata 413 }; 414 415 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv) 416 { 417 return MetadataReader_Create(&APEReader_Vtbl, iid, ppv); 418 } 419 420 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options, 421 MetadataItem **items, DWORD *count) 422 { 423 #include "pshpack1.h" 424 struct gif_extension 425 { 426 BYTE extension_introducer; 427 BYTE extension_label; 428 } ext_data; 429 #include "poppack.h" 430 HRESULT hr; 431 ULONG bytesread, data_size; 432 MetadataItem *result; 433 BYTE subblock_size; 434 char *data; 435 436 *items = NULL; 437 *count = 0; 438 439 hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread); 440 if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK; 441 if (ext_data.extension_introducer != 0x21 || 442 ext_data.extension_label != COMMENT_EXT_FUNC_CODE) 443 return S_OK; 444 445 data = NULL; 446 data_size = 0; 447 448 for (;;) 449 { 450 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread); 451 if (FAILED(hr) || bytesread != sizeof(subblock_size)) 452 { 453 HeapFree(GetProcessHeap(), 0, data); 454 return S_OK; 455 } 456 if (!subblock_size) break; 457 458 if (!data) 459 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1); 460 else 461 { 462 char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1); 463 if (!new_data) 464 { 465 HeapFree(GetProcessHeap(), 0, data); 466 return S_OK; 467 } 468 data = new_data; 469 } 470 hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread); 471 if (FAILED(hr) || bytesread != subblock_size) 472 { 473 HeapFree(GetProcessHeap(), 0, data); 474 return S_OK; 475 } 476 data_size += subblock_size; 477 } 478 479 data[data_size] = 0; 480 481 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); 482 if (!result) 483 { 484 HeapFree(GetProcessHeap(), 0, data); 485 return E_OUTOFMEMORY; 486 } 487 488 PropVariantInit(&result->schema); 489 PropVariantInit(&result->id); 490 PropVariantInit(&result->value); 491 492 result->id.vt = VT_LPWSTR; 493 result->id.u.pwszVal = strdupAtoW("TextEntry"); 494 result->value.vt = VT_LPSTR; 495 result->value.u.pszVal = data; 496 497 *items = result; 498 *count = 1; 499 500 return S_OK; 501 } 502 503 static const MetadataHandlerVtbl GifCommentReader_Vtbl = { 504 0, 505 &CLSID_WICGifCommentMetadataReader, 506 load_GifComment_metadata 507 }; 508 509 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv) 510 { 511 return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv); 512 } 513 514 static IStream *create_stream(const void *data, int data_size) 515 { 516 HRESULT hr; 517 IStream *stream; 518 HGLOBAL hdata; 519 void *locked_data; 520 521 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size); 522 if (!hdata) return NULL; 523 524 locked_data = GlobalLock(hdata); 525 memcpy(locked_data, data, data_size); 526 GlobalUnlock(hdata); 527 528 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream); 529 return FAILED(hr) ? NULL : stream; 530 } 531 532 static HRESULT create_metadata_reader(const void *data, int data_size, 533 class_constructor constructor, 534 IWICMetadataReader **reader) 535 { 536 HRESULT hr; 537 IWICMetadataReader *metadata_reader; 538 IWICPersistStream *persist; 539 IStream *stream; 540 541 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 542 543 hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader); 544 if (FAILED(hr)) return hr; 545 546 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 547 if (FAILED(hr)) 548 { 549 IWICMetadataReader_Release(metadata_reader); 550 return hr; 551 } 552 553 stream = create_stream(data, data_size); 554 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); 555 IStream_Release(stream); 556 557 IWICPersistStream_Release(persist); 558 559 *reader = metadata_reader; 560 return S_OK; 561 } 562 563 typedef struct { 564 IWICBitmapDecoder IWICBitmapDecoder_iface; 565 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 566 IStream *stream; 567 BYTE LSD_data[13]; /* Logical Screen Descriptor */ 568 LONG ref; 569 BOOL initialized; 570 GifFileType *gif; 571 UINT current_frame; 572 CRITICAL_SECTION lock; 573 } GifDecoder; 574 575 typedef struct { 576 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 577 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 578 LONG ref; 579 SavedImage *frame; 580 GifDecoder *parent; 581 } GifFrameDecode; 582 583 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 584 { 585 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface); 586 } 587 588 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 589 { 590 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface); 591 } 592 593 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 594 { 595 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface); 596 } 597 598 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 599 { 600 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface); 601 } 602 603 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 604 void **ppv) 605 { 606 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 607 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 608 609 if (!ppv) return E_INVALIDARG; 610 611 if (IsEqualIID(&IID_IUnknown, iid) || 612 IsEqualIID(&IID_IWICBitmapSource, iid) || 613 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 614 { 615 *ppv = &This->IWICBitmapFrameDecode_iface; 616 } 617 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 618 { 619 *ppv = &This->IWICMetadataBlockReader_iface; 620 } 621 else 622 { 623 *ppv = NULL; 624 return E_NOINTERFACE; 625 } 626 627 IUnknown_AddRef((IUnknown*)*ppv); 628 return S_OK; 629 } 630 631 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 632 { 633 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 634 ULONG ref = InterlockedIncrement(&This->ref); 635 636 TRACE("(%p) refcount=%u\n", iface, ref); 637 638 return ref; 639 } 640 641 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface) 642 { 643 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 644 ULONG ref = InterlockedDecrement(&This->ref); 645 646 TRACE("(%p) refcount=%u\n", iface, ref); 647 648 if (ref == 0) 649 { 650 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); 651 HeapFree(GetProcessHeap(), 0, This); 652 } 653 654 return ref; 655 } 656 657 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 658 UINT *puiWidth, UINT *puiHeight) 659 { 660 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 661 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 662 663 *puiWidth = This->frame->ImageDesc.Width; 664 *puiHeight = This->frame->ImageDesc.Height; 665 666 return S_OK; 667 } 668 669 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 670 WICPixelFormatGUID *pPixelFormat) 671 { 672 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); 673 674 return S_OK; 675 } 676 677 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 678 double *pDpiX, double *pDpiY) 679 { 680 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 681 const GifWord aspect_word = This->parent->gif->SAspectRatio; 682 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0; 683 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 684 685 *pDpiX = 96.0 / aspect; 686 *pDpiY = 96.0; 687 688 return S_OK; 689 } 690 691 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 692 IWICPalette *pIPalette) 693 { 694 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 695 WICColor colors[256]; 696 ColorMapObject *cm = This->frame->ImageDesc.ColorMap; 697 int i, trans; 698 ExtensionBlock *eb; 699 TRACE("(%p,%p)\n", iface, pIPalette); 700 701 if (!cm) cm = This->parent->gif->SColorMap; 702 703 if (cm->ColorCount > 256) 704 { 705 ERR("GIF contains %i colors???\n", cm->ColorCount); 706 return E_FAIL; 707 } 708 709 for (i = 0; i < cm->ColorCount; i++) { 710 colors[i] = 0xff000000| /* alpha */ 711 cm->Colors[i].Red << 16| 712 cm->Colors[i].Green << 8| 713 cm->Colors[i].Blue; 714 } 715 716 /* look for the transparent color extension */ 717 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) { 718 eb = This->frame->Extensions.ExtensionBlocks + i; 719 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) { 720 if (eb->Bytes[3] & 1) { 721 trans = (unsigned char)eb->Bytes[6]; 722 colors[trans] &= 0xffffff; /* set alpha to 0 */ 723 break; 724 } 725 } 726 } 727 728 return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount); 729 } 730 731 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer, 732 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc, 733 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) 734 { 735 UINT row_offset; /* number of bytes into the source rows where the data starts */ 736 const BYTE *src; 737 BYTE *dst; 738 UINT y; 739 WICRect rect; 740 741 if (!rc) 742 { 743 rect.X = 0; 744 rect.Y = 0; 745 rect.Width = srcwidth; 746 rect.Height = srcheight; 747 rc = ▭ 748 } 749 else 750 { 751 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight) 752 return E_INVALIDARG; 753 } 754 755 if (dststride < rc->Width) 756 return E_INVALIDARG; 757 758 if ((dststride * rc->Height) > dstbuffersize) 759 return E_INVALIDARG; 760 761 row_offset = rc->X; 762 763 dst = dstbuffer; 764 for (y=rc->Y; y-rc->Y < rc->Height; y++) 765 { 766 if (y%8 == 0) 767 src = srcbuffer + srcstride * (y/8); 768 else if (y%4 == 0) 769 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8); 770 else if (y%2 == 0) 771 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4); 772 else /* y%2 == 1 */ 773 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2); 774 src += row_offset; 775 memcpy(dst, src, rc->Width); 776 dst += dststride; 777 } 778 return S_OK; 779 } 780 781 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 782 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 783 { 784 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 785 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 786 787 if (This->frame->ImageDesc.Interlace) 788 { 789 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width, 790 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, 791 prc, cbStride, cbBufferSize, pbBuffer); 792 } 793 else 794 { 795 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width, 796 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, 797 prc, cbStride, cbBufferSize, pbBuffer); 798 } 799 } 800 801 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 802 IWICMetadataQueryReader **ppIMetadataQueryReader) 803 { 804 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 805 806 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 807 808 if (!ppIMetadataQueryReader) 809 return E_INVALIDARG; 810 811 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 812 } 813 814 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 815 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 816 { 817 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 818 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 819 } 820 821 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 822 IWICBitmapSource **ppIThumbnail) 823 { 824 TRACE("(%p,%p)\n", iface, ppIThumbnail); 825 return WINCODEC_ERR_CODECNOTHUMBNAIL; 826 } 827 828 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = { 829 GifFrameDecode_QueryInterface, 830 GifFrameDecode_AddRef, 831 GifFrameDecode_Release, 832 GifFrameDecode_GetSize, 833 GifFrameDecode_GetPixelFormat, 834 GifFrameDecode_GetResolution, 835 GifFrameDecode_CopyPalette, 836 GifFrameDecode_CopyPixels, 837 GifFrameDecode_GetMetadataQueryReader, 838 GifFrameDecode_GetColorContexts, 839 GifFrameDecode_GetThumbnail 840 }; 841 842 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, 843 REFIID iid, void **ppv) 844 { 845 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 846 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 847 } 848 849 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) 850 { 851 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 852 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); 853 } 854 855 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface) 856 { 857 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 858 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); 859 } 860 861 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 862 GUID *guid) 863 { 864 TRACE("(%p,%p)\n", iface, guid); 865 866 if (!guid) return E_INVALIDARG; 867 868 *guid = GUID_ContainerFormatGif; 869 return S_OK; 870 } 871 872 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, 873 UINT *count) 874 { 875 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 876 877 TRACE("%p,%p\n", iface, count); 878 879 if (!count) return E_INVALIDARG; 880 881 *count = This->frame->Extensions.ExtensionBlockCount + 1; 882 return S_OK; 883 } 884 885 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader) 886 { 887 HRESULT hr; 888 IWICMetadataReader *metadata_reader; 889 IWICPersistStream *persist; 890 IStream *stream; 891 struct image_descriptor IMD_data; 892 893 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 894 895 hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); 896 if (FAILED(hr)) return hr; 897 898 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 899 if (FAILED(hr)) 900 { 901 IWICMetadataReader_Release(metadata_reader); 902 return hr; 903 } 904 905 /* recreate IMD structure from GIF decoder data */ 906 IMD_data.left = This->frame->ImageDesc.Left; 907 IMD_data.top = This->frame->ImageDesc.Top; 908 IMD_data.width = This->frame->ImageDesc.Width; 909 IMD_data.height = This->frame->ImageDesc.Height; 910 IMD_data.packed = 0; 911 /* interlace_flag */ 912 IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0; 913 if (This->frame->ImageDesc.ColorMap) 914 { 915 /* local_color_table_flag */ 916 IMD_data.packed |= 1 << 7; 917 /* local_color_table_size */ 918 IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1; 919 /* sort_flag */ 920 IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0; 921 } 922 923 stream = create_stream(&IMD_data, sizeof(IMD_data)); 924 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); 925 IStream_Release(stream); 926 927 IWICPersistStream_Release(persist); 928 929 *reader = metadata_reader; 930 return S_OK; 931 } 932 933 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 934 UINT index, IWICMetadataReader **reader) 935 { 936 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 937 int i, gce_index = -1, gce_skipped = 0; 938 939 TRACE("(%p,%u,%p)\n", iface, index, reader); 940 941 if (!reader) return E_INVALIDARG; 942 943 if (index == 0) 944 return create_IMD_metadata_reader(This, reader); 945 946 if (index >= This->frame->Extensions.ExtensionBlockCount + 1) 947 return E_INVALIDARG; 948 949 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++) 950 { 951 class_constructor constructor; 952 const void *data; 953 int data_size; 954 955 if (index != i + 1 - gce_skipped) continue; 956 957 if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE) 958 { 959 gce_index = i; 960 gce_skipped = 1; 961 continue; 962 } 963 else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) 964 { 965 constructor = GifCommentReader_CreateInstance; 966 data = This->frame->Extensions.ExtensionBlocks[i].Bytes; 967 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; 968 } 969 else 970 { 971 constructor = UnknownMetadataReader_CreateInstance; 972 data = This->frame->Extensions.ExtensionBlocks[i].Bytes; 973 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; 974 } 975 return create_metadata_reader(data, data_size, constructor, reader); 976 } 977 978 if (gce_index == -1) return E_INVALIDARG; 979 980 return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3, 981 This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4, 982 GCEReader_CreateInstance, reader); 983 } 984 985 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, 986 IEnumUnknown **enumerator) 987 { 988 FIXME("(%p,%p): stub\n", iface, enumerator); 989 return E_NOTIMPL; 990 } 991 992 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl = 993 { 994 GifFrameDecode_Block_QueryInterface, 995 GifFrameDecode_Block_AddRef, 996 GifFrameDecode_Block_Release, 997 GifFrameDecode_Block_GetContainerFormat, 998 GifFrameDecode_Block_GetCount, 999 GifFrameDecode_Block_GetReaderByIndex, 1000 GifFrameDecode_Block_GetEnumerator 1001 }; 1002 1003 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 1004 void **ppv) 1005 { 1006 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1007 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1008 1009 if (!ppv) return E_INVALIDARG; 1010 1011 if (IsEqualIID(&IID_IUnknown, iid) || 1012 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 1013 { 1014 *ppv = &This->IWICBitmapDecoder_iface; 1015 } 1016 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 1017 { 1018 *ppv = &This->IWICMetadataBlockReader_iface; 1019 } 1020 else 1021 { 1022 *ppv = NULL; 1023 return E_NOINTERFACE; 1024 } 1025 1026 IUnknown_AddRef((IUnknown*)*ppv); 1027 return S_OK; 1028 } 1029 1030 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface) 1031 { 1032 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1033 ULONG ref = InterlockedIncrement(&This->ref); 1034 1035 TRACE("(%p) refcount=%u\n", iface, ref); 1036 1037 return ref; 1038 } 1039 1040 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface) 1041 { 1042 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1043 ULONG ref = InterlockedDecrement(&This->ref); 1044 1045 TRACE("(%p) refcount=%u\n", iface, ref); 1046 1047 if (ref == 0) 1048 { 1049 if (This->stream) 1050 { 1051 IStream_Release(This->stream); 1052 DGifCloseFile(This->gif); 1053 } 1054 This->lock.DebugInfo->Spare[0] = 0; 1055 DeleteCriticalSection(&This->lock); 1056 HeapFree(GetProcessHeap(), 0, This); 1057 } 1058 1059 return ref; 1060 } 1061 1062 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 1063 DWORD *capability) 1064 { 1065 HRESULT hr; 1066 1067 TRACE("(%p,%p,%p)\n", iface, stream, capability); 1068 1069 if (!stream || !capability) return E_INVALIDARG; 1070 1071 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 1072 if (hr != S_OK) return hr; 1073 1074 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 1075 WICBitmapDecoderCapabilityCanDecodeSomeImages | 1076 WICBitmapDecoderCapabilityCanEnumerateMetadata; 1077 return S_OK; 1078 } 1079 1080 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { 1081 IStream *stream = gif->UserData; 1082 ULONG bytesread; 1083 HRESULT hr; 1084 1085 if (!stream) 1086 { 1087 ERR("attempting to read file after initialization\n"); 1088 return 0; 1089 } 1090 1091 hr = IStream_Read(stream, data, len, &bytesread); 1092 if (FAILED(hr)) bytesread = 0; 1093 return bytesread; 1094 } 1095 1096 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 1097 WICDecodeOptions cacheOptions) 1098 { 1099 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1100 LARGE_INTEGER seek; 1101 int ret; 1102 1103 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 1104 1105 EnterCriticalSection(&This->lock); 1106 1107 if (This->initialized || This->gif) 1108 { 1109 WARN("already initialized\n"); 1110 LeaveCriticalSection(&This->lock); 1111 return WINCODEC_ERR_WRONGSTATE; 1112 } 1113 1114 /* seek to start of stream */ 1115 seek.QuadPart = 0; 1116 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 1117 1118 /* read all data from the stream */ 1119 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc); 1120 if (!This->gif) 1121 { 1122 LeaveCriticalSection(&This->lock); 1123 return E_FAIL; 1124 } 1125 1126 ret = DGifSlurp(This->gif); 1127 if (ret == GIF_ERROR) 1128 { 1129 LeaveCriticalSection(&This->lock); 1130 return E_FAIL; 1131 } 1132 1133 /* make sure we don't use the stream after this method returns */ 1134 This->gif->UserData = NULL; 1135 1136 seek.QuadPart = 0; 1137 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 1138 IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL); 1139 1140 This->stream = pIStream; 1141 IStream_AddRef(This->stream); 1142 1143 This->initialized = TRUE; 1144 1145 LeaveCriticalSection(&This->lock); 1146 1147 return S_OK; 1148 } 1149 1150 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 1151 GUID *pguidContainerFormat) 1152 { 1153 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID)); 1154 return S_OK; 1155 } 1156 1157 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 1158 IWICBitmapDecoderInfo **ppIDecoderInfo) 1159 { 1160 HRESULT hr; 1161 IWICComponentInfo *compinfo; 1162 1163 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 1164 1165 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo); 1166 if (FAILED(hr)) return hr; 1167 1168 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 1169 (void**)ppIDecoderInfo); 1170 1171 IWICComponentInfo_Release(compinfo); 1172 1173 return hr; 1174 } 1175 1176 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) 1177 { 1178 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1179 WICColor colors[256]; 1180 ColorMapObject *cm; 1181 int i, trans, count; 1182 ExtensionBlock *eb; 1183 1184 TRACE("(%p,%p)\n", iface, palette); 1185 1186 cm = This->gif->SColorMap; 1187 if (cm) 1188 { 1189 if (cm->ColorCount > 256) 1190 { 1191 ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount); 1192 return E_FAIL; 1193 } 1194 1195 for (i = 0; i < cm->ColorCount; i++) 1196 { 1197 colors[i] = 0xff000000 | /* alpha */ 1198 cm->Colors[i].Red << 16 | 1199 cm->Colors[i].Green << 8 | 1200 cm->Colors[i].Blue; 1201 } 1202 1203 count = cm->ColorCount; 1204 } 1205 else 1206 { 1207 colors[0] = 0xff000000; 1208 colors[1] = 0xffffffff; 1209 1210 for (i = 2; i < 256; i++) 1211 colors[i] = 0xff000000; 1212 1213 count = 256; 1214 } 1215 1216 /* look for the transparent color extension */ 1217 for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++) 1218 { 1219 eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i; 1220 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) 1221 { 1222 if (eb->Bytes[3] & 1) 1223 { 1224 trans = (unsigned char)eb->Bytes[6]; 1225 colors[trans] &= 0xffffff; /* set alpha to 0 */ 1226 break; 1227 } 1228 } 1229 } 1230 1231 return IWICPalette_InitializeCustom(palette, colors, count); 1232 } 1233 1234 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 1235 IWICMetadataQueryReader **ppIMetadataQueryReader) 1236 { 1237 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1238 1239 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1240 1241 if (!ppIMetadataQueryReader) return E_INVALIDARG; 1242 1243 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1244 } 1245 1246 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface, 1247 IWICBitmapSource **ppIBitmapSource) 1248 { 1249 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 1250 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1251 } 1252 1253 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface, 1254 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1255 { 1256 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1257 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1258 } 1259 1260 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface, 1261 IWICBitmapSource **ppIThumbnail) 1262 { 1263 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1264 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1265 } 1266 1267 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface, 1268 UINT *pCount) 1269 { 1270 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1271 1272 if (!pCount) return E_INVALIDARG; 1273 1274 EnterCriticalSection(&This->lock); 1275 *pCount = This->gif ? This->gif->ImageCount : 0; 1276 LeaveCriticalSection(&This->lock); 1277 1278 TRACE("(%p) <-- %d\n", iface, *pCount); 1279 1280 return S_OK; 1281 } 1282 1283 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface, 1284 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 1285 { 1286 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1287 GifFrameDecode *result; 1288 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 1289 1290 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 1291 1292 if (index >= This->gif->ImageCount) return E_INVALIDARG; 1293 1294 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode)); 1295 if (!result) return E_OUTOFMEMORY; 1296 1297 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl; 1298 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl; 1299 result->ref = 1; 1300 result->frame = &This->gif->SavedImages[index]; 1301 IWICBitmapDecoder_AddRef(iface); 1302 result->parent = This; 1303 This->current_frame = index; 1304 1305 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 1306 1307 return S_OK; 1308 } 1309 1310 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = { 1311 GifDecoder_QueryInterface, 1312 GifDecoder_AddRef, 1313 GifDecoder_Release, 1314 GifDecoder_QueryCapability, 1315 GifDecoder_Initialize, 1316 GifDecoder_GetContainerFormat, 1317 GifDecoder_GetDecoderInfo, 1318 GifDecoder_CopyPalette, 1319 GifDecoder_GetMetadataQueryReader, 1320 GifDecoder_GetPreview, 1321 GifDecoder_GetColorContexts, 1322 GifDecoder_GetThumbnail, 1323 GifDecoder_GetFrameCount, 1324 GifDecoder_GetFrame 1325 }; 1326 1327 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, 1328 REFIID iid, void **ppv) 1329 { 1330 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1331 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1332 } 1333 1334 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface) 1335 { 1336 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1337 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 1338 } 1339 1340 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface) 1341 { 1342 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1343 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1344 } 1345 1346 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1347 GUID *guid) 1348 { 1349 TRACE("(%p,%p)\n", iface, guid); 1350 1351 if (!guid) return E_INVALIDARG; 1352 1353 *guid = GUID_ContainerFormatGif; 1354 return S_OK; 1355 } 1356 1357 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface, 1358 UINT *count) 1359 { 1360 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1361 1362 TRACE("%p,%p\n", iface, count); 1363 1364 if (!count) return E_INVALIDARG; 1365 1366 *count = This->gif->Extensions.ExtensionBlockCount + 1; 1367 return S_OK; 1368 } 1369 1370 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1371 UINT index, IWICMetadataReader **reader) 1372 { 1373 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1374 int i; 1375 1376 TRACE("(%p,%u,%p)\n", iface, index, reader); 1377 1378 if (!reader) return E_INVALIDARG; 1379 1380 if (index == 0) 1381 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data), 1382 LSDReader_CreateInstance, reader); 1383 1384 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) 1385 { 1386 class_constructor constructor; 1387 1388 if (index != i + 1) continue; 1389 1390 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE) 1391 constructor = APEReader_CreateInstance; 1392 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) 1393 constructor = GifCommentReader_CreateInstance; 1394 else 1395 constructor = UnknownMetadataReader_CreateInstance; 1396 1397 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, 1398 This->gif->Extensions.ExtensionBlocks[i].ByteCount, 1399 constructor, reader); 1400 } 1401 1402 return E_INVALIDARG; 1403 } 1404 1405 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1406 IEnumUnknown **enumerator) 1407 { 1408 FIXME("(%p,%p): stub\n", iface, enumerator); 1409 return E_NOTIMPL; 1410 } 1411 1412 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl = 1413 { 1414 GifDecoder_Block_QueryInterface, 1415 GifDecoder_Block_AddRef, 1416 GifDecoder_Block_Release, 1417 GifDecoder_Block_GetContainerFormat, 1418 GifDecoder_Block_GetCount, 1419 GifDecoder_Block_GetReaderByIndex, 1420 GifDecoder_Block_GetEnumerator 1421 }; 1422 1423 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv) 1424 { 1425 GifDecoder *This; 1426 HRESULT ret; 1427 1428 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1429 1430 *ppv = NULL; 1431 1432 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder)); 1433 if (!This) return E_OUTOFMEMORY; 1434 1435 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl; 1436 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl; 1437 This->stream = NULL; 1438 This->ref = 1; 1439 This->initialized = FALSE; 1440 This->gif = NULL; 1441 This->current_frame = 0; 1442 InitializeCriticalSection(&This->lock); 1443 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock"); 1444 1445 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1446 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1447 1448 return ret; 1449 } 1450