1 /* 2 * Copyright 2009 Vincent Povirk for CodeWeavers 3 * Copyright 2012,2016 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 "config.h" 21 22 #include <stdarg.h> 23 24 #define COBJMACROS 25 #define NONAMELESSUNION 26 27 #include "windef.h" 28 #include "winbase.h" 29 #include "objbase.h" 30 31 #include "ungif.h" 32 33 #include "wincodecs_private.h" 34 35 #include "wine/debug.h" 36 37 #ifdef __REACTOS__ 38 #include <ole2.h> 39 #endif 40 41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 42 43 #include "pshpack1.h" 44 45 struct logical_screen_descriptor 46 { 47 char signature[6]; 48 USHORT width; 49 USHORT height; 50 BYTE packed; 51 /* global_color_table_flag : 1; 52 * color_resolution : 3; 53 * sort_flag : 1; 54 * global_color_table_size : 3; 55 */ 56 BYTE background_color_index; 57 BYTE pixel_aspect_ratio; 58 }; 59 60 struct image_descriptor 61 { 62 USHORT left; 63 USHORT top; 64 USHORT width; 65 USHORT height; 66 BYTE packed; 67 /* local_color_table_flag : 1; 68 * interlace_flag : 1; 69 * sort_flag : 1; 70 * reserved : 2; 71 * local_color_table_size : 3; 72 */ 73 }; 74 75 #include "poppack.h" 76 77 static LPWSTR strdupAtoW(const char *src) 78 { 79 int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); 80 LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 81 if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len); 82 return dst; 83 } 84 85 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options, 86 MetadataItem **items, DWORD *count) 87 { 88 struct logical_screen_descriptor lsd_data; 89 HRESULT hr; 90 ULONG bytesread, i; 91 MetadataItem *result; 92 93 *items = NULL; 94 *count = 0; 95 96 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread); 97 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK; 98 99 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9); 100 if (!result) return E_OUTOFMEMORY; 101 102 for (i = 0; i < 9; i++) 103 { 104 PropVariantInit(&result[i].schema); 105 PropVariantInit(&result[i].id); 106 PropVariantInit(&result[i].value); 107 } 108 109 result[0].id.vt = VT_LPWSTR; 110 result[0].id.u.pwszVal = strdupAtoW("Signature"); 111 result[0].value.vt = VT_UI1|VT_VECTOR; 112 result[0].value.u.caub.cElems = sizeof(lsd_data.signature); 113 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature)); 114 memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature)); 115 116 result[1].id.vt = VT_LPWSTR; 117 result[1].id.u.pwszVal = strdupAtoW("Width"); 118 result[1].value.vt = VT_UI2; 119 result[1].value.u.uiVal = lsd_data.width; 120 121 result[2].id.vt = VT_LPWSTR; 122 result[2].id.u.pwszVal = strdupAtoW("Height"); 123 result[2].value.vt = VT_UI2; 124 result[2].value.u.uiVal = lsd_data.height; 125 126 result[3].id.vt = VT_LPWSTR; 127 result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag"); 128 result[3].value.vt = VT_BOOL; 129 result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1; 130 131 result[4].id.vt = VT_LPWSTR; 132 result[4].id.u.pwszVal = strdupAtoW("ColorResolution"); 133 result[4].value.vt = VT_UI1; 134 result[4].value.u.bVal = (lsd_data.packed >> 4) & 7; 135 136 result[5].id.vt = VT_LPWSTR; 137 result[5].id.u.pwszVal = strdupAtoW("SortFlag"); 138 result[5].value.vt = VT_BOOL; 139 result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1; 140 141 result[6].id.vt = VT_LPWSTR; 142 result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize"); 143 result[6].value.vt = VT_UI1; 144 result[6].value.u.bVal = lsd_data.packed & 7; 145 146 result[7].id.vt = VT_LPWSTR; 147 result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex"); 148 result[7].value.vt = VT_UI1; 149 result[7].value.u.bVal = lsd_data.background_color_index; 150 151 result[8].id.vt = VT_LPWSTR; 152 result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio"); 153 result[8].value.vt = VT_UI1; 154 result[8].value.u.bVal = lsd_data.pixel_aspect_ratio; 155 156 *items = result; 157 *count = 9; 158 159 return S_OK; 160 } 161 162 static const MetadataHandlerVtbl LSDReader_Vtbl = { 163 0, 164 &CLSID_WICLSDMetadataReader, 165 load_LSD_metadata 166 }; 167 168 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv) 169 { 170 return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv); 171 } 172 173 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options, 174 MetadataItem **items, DWORD *count) 175 { 176 struct image_descriptor imd_data; 177 HRESULT hr; 178 ULONG bytesread, i; 179 MetadataItem *result; 180 181 *items = NULL; 182 *count = 0; 183 184 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread); 185 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK; 186 187 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8); 188 if (!result) return E_OUTOFMEMORY; 189 190 for (i = 0; i < 8; i++) 191 { 192 PropVariantInit(&result[i].schema); 193 PropVariantInit(&result[i].id); 194 PropVariantInit(&result[i].value); 195 } 196 197 result[0].id.vt = VT_LPWSTR; 198 result[0].id.u.pwszVal = strdupAtoW("Left"); 199 result[0].value.vt = VT_UI2; 200 result[0].value.u.uiVal = imd_data.left; 201 202 result[1].id.vt = VT_LPWSTR; 203 result[1].id.u.pwszVal = strdupAtoW("Top"); 204 result[1].value.vt = VT_UI2; 205 result[1].value.u.uiVal = imd_data.top; 206 207 result[2].id.vt = VT_LPWSTR; 208 result[2].id.u.pwszVal = strdupAtoW("Width"); 209 result[2].value.vt = VT_UI2; 210 result[2].value.u.uiVal = imd_data.width; 211 212 result[3].id.vt = VT_LPWSTR; 213 result[3].id.u.pwszVal = strdupAtoW("Height"); 214 result[3].value.vt = VT_UI2; 215 result[3].value.u.uiVal = imd_data.height; 216 217 result[4].id.vt = VT_LPWSTR; 218 result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag"); 219 result[4].value.vt = VT_BOOL; 220 result[4].value.u.boolVal = (imd_data.packed >> 7) & 1; 221 222 result[5].id.vt = VT_LPWSTR; 223 result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag"); 224 result[5].value.vt = VT_BOOL; 225 result[5].value.u.boolVal = (imd_data.packed >> 6) & 1; 226 227 result[6].id.vt = VT_LPWSTR; 228 result[6].id.u.pwszVal = strdupAtoW("SortFlag"); 229 result[6].value.vt = VT_BOOL; 230 result[6].value.u.boolVal = (imd_data.packed >> 5) & 1; 231 232 result[7].id.vt = VT_LPWSTR; 233 result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize"); 234 result[7].value.vt = VT_UI1; 235 result[7].value.u.bVal = imd_data.packed & 7; 236 237 *items = result; 238 *count = 8; 239 240 return S_OK; 241 } 242 243 static const MetadataHandlerVtbl IMDReader_Vtbl = { 244 0, 245 &CLSID_WICIMDMetadataReader, 246 load_IMD_metadata 247 }; 248 249 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv) 250 { 251 return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv); 252 } 253 254 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options, 255 MetadataItem **items, DWORD *count) 256 { 257 #include "pshpack1.h" 258 struct graphic_control_extension 259 { 260 BYTE packed; 261 /* reservred: 3; 262 * disposal : 3; 263 * user_input_flag : 1; 264 * transparency_flag : 1; 265 */ 266 USHORT delay; 267 BYTE transparent_color_index; 268 } gce_data; 269 #include "poppack.h" 270 HRESULT hr; 271 ULONG bytesread, i; 272 MetadataItem *result; 273 274 *items = NULL; 275 *count = 0; 276 277 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread); 278 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK; 279 280 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5); 281 if (!result) return E_OUTOFMEMORY; 282 283 for (i = 0; i < 5; i++) 284 { 285 PropVariantInit(&result[i].schema); 286 PropVariantInit(&result[i].id); 287 PropVariantInit(&result[i].value); 288 } 289 290 result[0].id.vt = VT_LPWSTR; 291 result[0].id.u.pwszVal = strdupAtoW("Disposal"); 292 result[0].value.vt = VT_UI1; 293 result[0].value.u.bVal = (gce_data.packed >> 2) & 7; 294 295 result[1].id.vt = VT_LPWSTR; 296 result[1].id.u.pwszVal = strdupAtoW("UserInputFlag"); 297 result[1].value.vt = VT_BOOL; 298 result[1].value.u.boolVal = (gce_data.packed >> 1) & 1; 299 300 result[2].id.vt = VT_LPWSTR; 301 result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag"); 302 result[2].value.vt = VT_BOOL; 303 result[2].value.u.boolVal = gce_data.packed & 1; 304 305 result[3].id.vt = VT_LPWSTR; 306 result[3].id.u.pwszVal = strdupAtoW("Delay"); 307 result[3].value.vt = VT_UI2; 308 result[3].value.u.uiVal = gce_data.delay; 309 310 result[4].id.vt = VT_LPWSTR; 311 result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex"); 312 result[4].value.vt = VT_UI1; 313 result[4].value.u.bVal = gce_data.transparent_color_index; 314 315 *items = result; 316 *count = 5; 317 318 return S_OK; 319 } 320 321 static const MetadataHandlerVtbl GCEReader_Vtbl = { 322 0, 323 &CLSID_WICGCEMetadataReader, 324 load_GCE_metadata 325 }; 326 327 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv) 328 { 329 return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv); 330 } 331 332 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options, 333 MetadataItem **items, DWORD *count) 334 { 335 #include "pshpack1.h" 336 struct application_extension 337 { 338 BYTE extension_introducer; 339 BYTE extension_label; 340 BYTE block_size; 341 BYTE application[11]; 342 } ape_data; 343 #include "poppack.h" 344 HRESULT hr; 345 ULONG bytesread, data_size, i; 346 MetadataItem *result; 347 BYTE subblock_size; 348 BYTE *data; 349 350 *items = NULL; 351 *count = 0; 352 353 hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread); 354 if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK; 355 if (ape_data.extension_introducer != 0x21 || 356 ape_data.extension_label != APPLICATION_EXT_FUNC_CODE || 357 ape_data.block_size != 11) 358 return S_OK; 359 360 data = NULL; 361 data_size = 0; 362 363 for (;;) 364 { 365 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread); 366 if (FAILED(hr) || bytesread != sizeof(subblock_size)) 367 { 368 HeapFree(GetProcessHeap(), 0, data); 369 return S_OK; 370 } 371 if (!subblock_size) break; 372 373 if (!data) 374 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1); 375 else 376 { 377 BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1); 378 if (!new_data) 379 { 380 HeapFree(GetProcessHeap(), 0, data); 381 return S_OK; 382 } 383 data = new_data; 384 } 385 data[data_size] = subblock_size; 386 hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread); 387 if (FAILED(hr) || bytesread != subblock_size) 388 { 389 HeapFree(GetProcessHeap(), 0, data); 390 return S_OK; 391 } 392 data_size += subblock_size + 1; 393 } 394 395 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2); 396 if (!result) 397 { 398 HeapFree(GetProcessHeap(), 0, data); 399 return E_OUTOFMEMORY; 400 } 401 402 for (i = 0; i < 2; i++) 403 { 404 PropVariantInit(&result[i].schema); 405 PropVariantInit(&result[i].id); 406 PropVariantInit(&result[i].value); 407 } 408 409 result[0].id.vt = VT_LPWSTR; 410 result[0].id.u.pwszVal = strdupAtoW("Application"); 411 result[0].value.vt = VT_UI1|VT_VECTOR; 412 result[0].value.u.caub.cElems = sizeof(ape_data.application); 413 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application)); 414 memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application)); 415 416 result[1].id.vt = VT_LPWSTR; 417 result[1].id.u.pwszVal = strdupAtoW("Data"); 418 result[1].value.vt = VT_UI1|VT_VECTOR; 419 result[1].value.u.caub.cElems = data_size; 420 result[1].value.u.caub.pElems = data; 421 422 *items = result; 423 *count = 2; 424 425 return S_OK; 426 } 427 428 static const MetadataHandlerVtbl APEReader_Vtbl = { 429 0, 430 &CLSID_WICAPEMetadataReader, 431 load_APE_metadata 432 }; 433 434 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv) 435 { 436 return MetadataReader_Create(&APEReader_Vtbl, iid, ppv); 437 } 438 439 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options, 440 MetadataItem **items, DWORD *count) 441 { 442 #include "pshpack1.h" 443 struct gif_extension 444 { 445 BYTE extension_introducer; 446 BYTE extension_label; 447 } ext_data; 448 #include "poppack.h" 449 HRESULT hr; 450 ULONG bytesread, data_size; 451 MetadataItem *result; 452 BYTE subblock_size; 453 char *data; 454 455 *items = NULL; 456 *count = 0; 457 458 hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread); 459 if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK; 460 if (ext_data.extension_introducer != 0x21 || 461 ext_data.extension_label != COMMENT_EXT_FUNC_CODE) 462 return S_OK; 463 464 data = NULL; 465 data_size = 0; 466 467 for (;;) 468 { 469 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread); 470 if (FAILED(hr) || bytesread != sizeof(subblock_size)) 471 { 472 HeapFree(GetProcessHeap(), 0, data); 473 return S_OK; 474 } 475 if (!subblock_size) break; 476 477 if (!data) 478 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1); 479 else 480 { 481 char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1); 482 if (!new_data) 483 { 484 HeapFree(GetProcessHeap(), 0, data); 485 return S_OK; 486 } 487 data = new_data; 488 } 489 hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread); 490 if (FAILED(hr) || bytesread != subblock_size) 491 { 492 HeapFree(GetProcessHeap(), 0, data); 493 return S_OK; 494 } 495 data_size += subblock_size; 496 } 497 498 data[data_size] = 0; 499 500 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); 501 if (!result) 502 { 503 HeapFree(GetProcessHeap(), 0, data); 504 return E_OUTOFMEMORY; 505 } 506 507 PropVariantInit(&result->schema); 508 PropVariantInit(&result->id); 509 PropVariantInit(&result->value); 510 511 result->id.vt = VT_LPWSTR; 512 result->id.u.pwszVal = strdupAtoW("TextEntry"); 513 result->value.vt = VT_LPSTR; 514 result->value.u.pszVal = data; 515 516 *items = result; 517 *count = 1; 518 519 return S_OK; 520 } 521 522 static const MetadataHandlerVtbl GifCommentReader_Vtbl = { 523 0, 524 &CLSID_WICGifCommentMetadataReader, 525 load_GifComment_metadata 526 }; 527 528 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv) 529 { 530 return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv); 531 } 532 533 static IStream *create_stream(const void *data, int data_size) 534 { 535 HRESULT hr; 536 IStream *stream; 537 HGLOBAL hdata; 538 void *locked_data; 539 540 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size); 541 if (!hdata) return NULL; 542 543 locked_data = GlobalLock(hdata); 544 memcpy(locked_data, data, data_size); 545 GlobalUnlock(hdata); 546 547 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream); 548 return FAILED(hr) ? NULL : stream; 549 } 550 551 static HRESULT create_metadata_reader(const void *data, int data_size, 552 class_constructor constructor, 553 IWICMetadataReader **reader) 554 { 555 HRESULT hr; 556 IWICMetadataReader *metadata_reader; 557 IWICPersistStream *persist; 558 IStream *stream; 559 560 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 561 562 hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader); 563 if (FAILED(hr)) return hr; 564 565 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 566 if (FAILED(hr)) 567 { 568 IWICMetadataReader_Release(metadata_reader); 569 return hr; 570 } 571 572 stream = create_stream(data, data_size); 573 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); 574 IStream_Release(stream); 575 576 IWICPersistStream_Release(persist); 577 578 *reader = metadata_reader; 579 return S_OK; 580 } 581 582 typedef struct { 583 IWICBitmapDecoder IWICBitmapDecoder_iface; 584 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 585 IStream *stream; 586 BYTE LSD_data[13]; /* Logical Screen Descriptor */ 587 LONG ref; 588 BOOL initialized; 589 GifFileType *gif; 590 UINT current_frame; 591 CRITICAL_SECTION lock; 592 } GifDecoder; 593 594 typedef struct { 595 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; 596 IWICMetadataBlockReader IWICMetadataBlockReader_iface; 597 LONG ref; 598 SavedImage *frame; 599 GifDecoder *parent; 600 } GifFrameDecode; 601 602 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) 603 { 604 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface); 605 } 606 607 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 608 { 609 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface); 610 } 611 612 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) 613 { 614 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface); 615 } 616 617 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) 618 { 619 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface); 620 } 621 622 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, 623 void **ppv) 624 { 625 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 626 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 627 628 if (!ppv) return E_INVALIDARG; 629 630 if (IsEqualIID(&IID_IUnknown, iid) || 631 IsEqualIID(&IID_IWICBitmapSource, iid) || 632 IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) 633 { 634 *ppv = &This->IWICBitmapFrameDecode_iface; 635 } 636 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 637 { 638 *ppv = &This->IWICMetadataBlockReader_iface; 639 } 640 else 641 { 642 *ppv = NULL; 643 return E_NOINTERFACE; 644 } 645 646 IUnknown_AddRef((IUnknown*)*ppv); 647 return S_OK; 648 } 649 650 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface) 651 { 652 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 653 ULONG ref = InterlockedIncrement(&This->ref); 654 655 TRACE("(%p) refcount=%u\n", iface, ref); 656 657 return ref; 658 } 659 660 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface) 661 { 662 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 663 ULONG ref = InterlockedDecrement(&This->ref); 664 665 TRACE("(%p) refcount=%u\n", iface, ref); 666 667 if (ref == 0) 668 { 669 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); 670 HeapFree(GetProcessHeap(), 0, This); 671 } 672 673 return ref; 674 } 675 676 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface, 677 UINT *puiWidth, UINT *puiHeight) 678 { 679 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 680 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight); 681 682 *puiWidth = This->frame->ImageDesc.Width; 683 *puiHeight = This->frame->ImageDesc.Height; 684 685 return S_OK; 686 } 687 688 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, 689 WICPixelFormatGUID *pPixelFormat) 690 { 691 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID)); 692 693 return S_OK; 694 } 695 696 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, 697 double *pDpiX, double *pDpiY) 698 { 699 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 700 const GifWord aspect_word = This->parent->gif->SAspectRatio; 701 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0; 702 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY); 703 704 *pDpiX = 96.0 / aspect; 705 *pDpiY = 96.0; 706 707 return S_OK; 708 } 709 710 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, 711 IWICPalette *pIPalette) 712 { 713 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 714 WICColor colors[256]; 715 ColorMapObject *cm = This->frame->ImageDesc.ColorMap; 716 int i, trans; 717 ExtensionBlock *eb; 718 TRACE("(%p,%p)\n", iface, pIPalette); 719 720 if (!cm) cm = This->parent->gif->SColorMap; 721 722 if (cm->ColorCount > 256) 723 { 724 ERR("GIF contains %i colors???\n", cm->ColorCount); 725 return E_FAIL; 726 } 727 728 for (i = 0; i < cm->ColorCount; i++) { 729 colors[i] = 0xff000000| /* alpha */ 730 cm->Colors[i].Red << 16| 731 cm->Colors[i].Green << 8| 732 cm->Colors[i].Blue; 733 } 734 735 /* look for the transparent color extension */ 736 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) { 737 eb = This->frame->Extensions.ExtensionBlocks + i; 738 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) { 739 if (eb->Bytes[3] & 1) { 740 trans = (unsigned char)eb->Bytes[6]; 741 colors[trans] &= 0xffffff; /* set alpha to 0 */ 742 break; 743 } 744 } 745 } 746 747 return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount); 748 } 749 750 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer, 751 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc, 752 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer) 753 { 754 UINT row_offset; /* number of bytes into the source rows where the data starts */ 755 const BYTE *src; 756 BYTE *dst; 757 UINT y; 758 WICRect rect; 759 760 if (!rc) 761 { 762 rect.X = 0; 763 rect.Y = 0; 764 rect.Width = srcwidth; 765 rect.Height = srcheight; 766 rc = ▭ 767 } 768 else 769 { 770 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight) 771 return E_INVALIDARG; 772 } 773 774 if (dststride < rc->Width) 775 return E_INVALIDARG; 776 777 if ((dststride * rc->Height) > dstbuffersize) 778 return E_INVALIDARG; 779 780 row_offset = rc->X; 781 782 dst = dstbuffer; 783 for (y=rc->Y; y-rc->Y < rc->Height; y++) 784 { 785 if (y%8 == 0) 786 src = srcbuffer + srcstride * (y/8); 787 else if (y%4 == 0) 788 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8); 789 else if (y%2 == 0) 790 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4); 791 else /* y%2 == 1 */ 792 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2); 793 src += row_offset; 794 memcpy(dst, src, rc->Width); 795 dst += dststride; 796 } 797 return S_OK; 798 } 799 800 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, 801 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) 802 { 803 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 804 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer); 805 806 if (This->frame->ImageDesc.Interlace) 807 { 808 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width, 809 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, 810 prc, cbStride, cbBufferSize, pbBuffer); 811 } 812 else 813 { 814 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width, 815 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width, 816 prc, cbStride, cbBufferSize, pbBuffer); 817 } 818 } 819 820 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, 821 IWICMetadataQueryReader **ppIMetadataQueryReader) 822 { 823 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); 824 825 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 826 827 if (!ppIMetadataQueryReader) 828 return E_INVALIDARG; 829 830 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 831 } 832 833 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, 834 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 835 { 836 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 837 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 838 } 839 840 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, 841 IWICBitmapSource **ppIThumbnail) 842 { 843 TRACE("(%p,%p)\n", iface, ppIThumbnail); 844 return WINCODEC_ERR_CODECNOTHUMBNAIL; 845 } 846 847 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = { 848 GifFrameDecode_QueryInterface, 849 GifFrameDecode_AddRef, 850 GifFrameDecode_Release, 851 GifFrameDecode_GetSize, 852 GifFrameDecode_GetPixelFormat, 853 GifFrameDecode_GetResolution, 854 GifFrameDecode_CopyPalette, 855 GifFrameDecode_CopyPixels, 856 GifFrameDecode_GetMetadataQueryReader, 857 GifFrameDecode_GetColorContexts, 858 GifFrameDecode_GetThumbnail 859 }; 860 861 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, 862 REFIID iid, void **ppv) 863 { 864 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 865 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); 866 } 867 868 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) 869 { 870 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 871 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); 872 } 873 874 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface) 875 { 876 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 877 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); 878 } 879 880 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 881 GUID *guid) 882 { 883 TRACE("(%p,%p)\n", iface, guid); 884 885 if (!guid) return E_INVALIDARG; 886 887 *guid = GUID_ContainerFormatGif; 888 return S_OK; 889 } 890 891 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, 892 UINT *count) 893 { 894 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 895 896 TRACE("%p,%p\n", iface, count); 897 898 if (!count) return E_INVALIDARG; 899 900 *count = This->frame->Extensions.ExtensionBlockCount + 1; 901 return S_OK; 902 } 903 904 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader) 905 { 906 HRESULT hr; 907 IWICMetadataReader *metadata_reader; 908 IWICPersistStream *persist; 909 IStream *stream; 910 struct image_descriptor IMD_data; 911 912 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ 913 914 hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); 915 if (FAILED(hr)) return hr; 916 917 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); 918 if (FAILED(hr)) 919 { 920 IWICMetadataReader_Release(metadata_reader); 921 return hr; 922 } 923 924 /* recreate IMD structure from GIF decoder data */ 925 IMD_data.left = This->frame->ImageDesc.Left; 926 IMD_data.top = This->frame->ImageDesc.Top; 927 IMD_data.width = This->frame->ImageDesc.Width; 928 IMD_data.height = This->frame->ImageDesc.Height; 929 IMD_data.packed = 0; 930 /* interlace_flag */ 931 IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0; 932 if (This->frame->ImageDesc.ColorMap) 933 { 934 /* local_color_table_flag */ 935 IMD_data.packed |= 1 << 7; 936 /* local_color_table_size */ 937 IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1; 938 /* sort_flag */ 939 IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0; 940 } 941 942 stream = create_stream(&IMD_data, sizeof(IMD_data)); 943 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault); 944 IStream_Release(stream); 945 946 IWICPersistStream_Release(persist); 947 948 *reader = metadata_reader; 949 return S_OK; 950 } 951 952 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 953 UINT index, IWICMetadataReader **reader) 954 { 955 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); 956 int i, gce_index = -1, gce_skipped = 0; 957 958 TRACE("(%p,%u,%p)\n", iface, index, reader); 959 960 if (!reader) return E_INVALIDARG; 961 962 if (index == 0) 963 return create_IMD_metadata_reader(This, reader); 964 965 if (index >= This->frame->Extensions.ExtensionBlockCount + 1) 966 return E_INVALIDARG; 967 968 for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++) 969 { 970 class_constructor constructor; 971 const void *data; 972 int data_size; 973 974 if (index != i + 1 - gce_skipped) continue; 975 976 if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE) 977 { 978 gce_index = i; 979 gce_skipped = 1; 980 continue; 981 } 982 else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) 983 { 984 constructor = GifCommentReader_CreateInstance; 985 data = This->frame->Extensions.ExtensionBlocks[i].Bytes; 986 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; 987 } 988 else 989 { 990 constructor = UnknownMetadataReader_CreateInstance; 991 data = This->frame->Extensions.ExtensionBlocks[i].Bytes; 992 data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; 993 } 994 return create_metadata_reader(data, data_size, constructor, reader); 995 } 996 997 if (gce_index == -1) return E_INVALIDARG; 998 999 return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3, 1000 This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4, 1001 GCEReader_CreateInstance, reader); 1002 } 1003 1004 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1005 IEnumUnknown **enumerator) 1006 { 1007 FIXME("(%p,%p): stub\n", iface, enumerator); 1008 return E_NOTIMPL; 1009 } 1010 1011 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl = 1012 { 1013 GifFrameDecode_Block_QueryInterface, 1014 GifFrameDecode_Block_AddRef, 1015 GifFrameDecode_Block_Release, 1016 GifFrameDecode_Block_GetContainerFormat, 1017 GifFrameDecode_Block_GetCount, 1018 GifFrameDecode_Block_GetReaderByIndex, 1019 GifFrameDecode_Block_GetEnumerator 1020 }; 1021 1022 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, 1023 void **ppv) 1024 { 1025 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1026 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); 1027 1028 if (!ppv) return E_INVALIDARG; 1029 1030 if (IsEqualIID(&IID_IUnknown, iid) || 1031 IsEqualIID(&IID_IWICBitmapDecoder, iid)) 1032 { 1033 *ppv = &This->IWICBitmapDecoder_iface; 1034 } 1035 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) 1036 { 1037 *ppv = &This->IWICMetadataBlockReader_iface; 1038 } 1039 else 1040 { 1041 *ppv = NULL; 1042 return E_NOINTERFACE; 1043 } 1044 1045 IUnknown_AddRef((IUnknown*)*ppv); 1046 return S_OK; 1047 } 1048 1049 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface) 1050 { 1051 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1052 ULONG ref = InterlockedIncrement(&This->ref); 1053 1054 TRACE("(%p) refcount=%u\n", iface, ref); 1055 1056 return ref; 1057 } 1058 1059 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface) 1060 { 1061 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1062 ULONG ref = InterlockedDecrement(&This->ref); 1063 1064 TRACE("(%p) refcount=%u\n", iface, ref); 1065 1066 if (ref == 0) 1067 { 1068 if (This->stream) 1069 { 1070 IStream_Release(This->stream); 1071 DGifCloseFile(This->gif); 1072 } 1073 This->lock.DebugInfo->Spare[0] = 0; 1074 DeleteCriticalSection(&This->lock); 1075 HeapFree(GetProcessHeap(), 0, This); 1076 } 1077 1078 return ref; 1079 } 1080 1081 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, 1082 DWORD *capability) 1083 { 1084 HRESULT hr; 1085 1086 TRACE("(%p,%p,%p)\n", iface, stream, capability); 1087 1088 if (!stream || !capability) return E_INVALIDARG; 1089 1090 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); 1091 if (hr != S_OK) return hr; 1092 1093 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages | 1094 WICBitmapDecoderCapabilityCanDecodeSomeImages | 1095 WICBitmapDecoderCapabilityCanEnumerateMetadata; 1096 return S_OK; 1097 } 1098 1099 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) { 1100 IStream *stream = gif->UserData; 1101 ULONG bytesread; 1102 HRESULT hr; 1103 1104 if (!stream) 1105 { 1106 ERR("attempting to read file after initialization\n"); 1107 return 0; 1108 } 1109 1110 hr = IStream_Read(stream, data, len, &bytesread); 1111 if (FAILED(hr)) bytesread = 0; 1112 return bytesread; 1113 } 1114 1115 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, 1116 WICDecodeOptions cacheOptions) 1117 { 1118 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1119 LARGE_INTEGER seek; 1120 int ret; 1121 1122 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); 1123 1124 EnterCriticalSection(&This->lock); 1125 1126 if (This->initialized || This->gif) 1127 { 1128 WARN("already initialized\n"); 1129 LeaveCriticalSection(&This->lock); 1130 return WINCODEC_ERR_WRONGSTATE; 1131 } 1132 1133 /* seek to start of stream */ 1134 seek.QuadPart = 0; 1135 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 1136 1137 /* read all data from the stream */ 1138 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc); 1139 if (!This->gif) 1140 { 1141 LeaveCriticalSection(&This->lock); 1142 return E_FAIL; 1143 } 1144 1145 ret = DGifSlurp(This->gif); 1146 if (ret == GIF_ERROR) 1147 { 1148 LeaveCriticalSection(&This->lock); 1149 return E_FAIL; 1150 } 1151 1152 /* make sure we don't use the stream after this method returns */ 1153 This->gif->UserData = NULL; 1154 1155 seek.QuadPart = 0; 1156 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); 1157 IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL); 1158 1159 This->stream = pIStream; 1160 IStream_AddRef(This->stream); 1161 1162 This->initialized = TRUE; 1163 1164 LeaveCriticalSection(&This->lock); 1165 1166 return S_OK; 1167 } 1168 1169 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface, 1170 GUID *pguidContainerFormat) 1171 { 1172 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID)); 1173 return S_OK; 1174 } 1175 1176 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, 1177 IWICBitmapDecoderInfo **ppIDecoderInfo) 1178 { 1179 HRESULT hr; 1180 IWICComponentInfo *compinfo; 1181 1182 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 1183 1184 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo); 1185 if (FAILED(hr)) return hr; 1186 1187 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo, 1188 (void**)ppIDecoderInfo); 1189 1190 IWICComponentInfo_Release(compinfo); 1191 1192 return hr; 1193 } 1194 1195 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) 1196 { 1197 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1198 WICColor colors[256]; 1199 ColorMapObject *cm; 1200 int i, trans, count; 1201 ExtensionBlock *eb; 1202 1203 TRACE("(%p,%p)\n", iface, palette); 1204 1205 if (!This->gif) 1206 return WINCODEC_ERR_WRONGSTATE; 1207 1208 cm = This->gif->SColorMap; 1209 if (cm) 1210 { 1211 if (cm->ColorCount > 256) 1212 { 1213 ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount); 1214 return E_FAIL; 1215 } 1216 1217 for (i = 0; i < cm->ColorCount; i++) 1218 { 1219 colors[i] = 0xff000000 | /* alpha */ 1220 cm->Colors[i].Red << 16 | 1221 cm->Colors[i].Green << 8 | 1222 cm->Colors[i].Blue; 1223 } 1224 1225 count = cm->ColorCount; 1226 } 1227 else 1228 { 1229 colors[0] = 0xff000000; 1230 colors[1] = 0xffffffff; 1231 1232 for (i = 2; i < 256; i++) 1233 colors[i] = 0xff000000; 1234 1235 count = 256; 1236 } 1237 1238 /* look for the transparent color extension */ 1239 for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++) 1240 { 1241 eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i; 1242 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) 1243 { 1244 if (eb->Bytes[3] & 1) 1245 { 1246 trans = (unsigned char)eb->Bytes[6]; 1247 colors[trans] &= 0xffffff; /* set alpha to 0 */ 1248 break; 1249 } 1250 } 1251 } 1252 1253 return IWICPalette_InitializeCustom(palette, colors, count); 1254 } 1255 1256 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 1257 IWICMetadataQueryReader **ppIMetadataQueryReader) 1258 { 1259 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1260 1261 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1262 1263 if (!ppIMetadataQueryReader) return E_INVALIDARG; 1264 1265 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1266 } 1267 1268 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface, 1269 IWICBitmapSource **ppIBitmapSource) 1270 { 1271 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 1272 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1273 } 1274 1275 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface, 1276 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1277 { 1278 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1279 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1280 } 1281 1282 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface, 1283 IWICBitmapSource **ppIThumbnail) 1284 { 1285 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1286 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1287 } 1288 1289 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface, 1290 UINT *pCount) 1291 { 1292 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1293 1294 if (!pCount) return E_INVALIDARG; 1295 1296 EnterCriticalSection(&This->lock); 1297 *pCount = This->gif ? This->gif->ImageCount : 0; 1298 LeaveCriticalSection(&This->lock); 1299 1300 TRACE("(%p) <-- %d\n", iface, *pCount); 1301 1302 return S_OK; 1303 } 1304 1305 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface, 1306 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 1307 { 1308 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1309 GifFrameDecode *result; 1310 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 1311 1312 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 1313 1314 if (index >= This->gif->ImageCount) return E_INVALIDARG; 1315 1316 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode)); 1317 if (!result) return E_OUTOFMEMORY; 1318 1319 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl; 1320 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl; 1321 result->ref = 1; 1322 result->frame = &This->gif->SavedImages[index]; 1323 IWICBitmapDecoder_AddRef(iface); 1324 result->parent = This; 1325 This->current_frame = index; 1326 1327 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 1328 1329 return S_OK; 1330 } 1331 1332 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = { 1333 GifDecoder_QueryInterface, 1334 GifDecoder_AddRef, 1335 GifDecoder_Release, 1336 GifDecoder_QueryCapability, 1337 GifDecoder_Initialize, 1338 GifDecoder_GetContainerFormat, 1339 GifDecoder_GetDecoderInfo, 1340 GifDecoder_CopyPalette, 1341 GifDecoder_GetMetadataQueryReader, 1342 GifDecoder_GetPreview, 1343 GifDecoder_GetColorContexts, 1344 GifDecoder_GetThumbnail, 1345 GifDecoder_GetFrameCount, 1346 GifDecoder_GetFrame 1347 }; 1348 1349 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, 1350 REFIID iid, void **ppv) 1351 { 1352 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1353 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1354 } 1355 1356 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface) 1357 { 1358 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1359 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 1360 } 1361 1362 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface) 1363 { 1364 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1365 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1366 } 1367 1368 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1369 GUID *guid) 1370 { 1371 TRACE("(%p,%p)\n", iface, guid); 1372 1373 if (!guid) return E_INVALIDARG; 1374 1375 *guid = GUID_ContainerFormatGif; 1376 return S_OK; 1377 } 1378 1379 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface, 1380 UINT *count) 1381 { 1382 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1383 1384 TRACE("%p,%p\n", iface, count); 1385 1386 if (!count) return E_INVALIDARG; 1387 1388 *count = This->gif->Extensions.ExtensionBlockCount + 1; 1389 return S_OK; 1390 } 1391 1392 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1393 UINT index, IWICMetadataReader **reader) 1394 { 1395 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1396 int i; 1397 1398 TRACE("(%p,%u,%p)\n", iface, index, reader); 1399 1400 if (!reader) return E_INVALIDARG; 1401 1402 if (index == 0) 1403 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data), 1404 LSDReader_CreateInstance, reader); 1405 1406 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) 1407 { 1408 class_constructor constructor; 1409 1410 if (index != i + 1) continue; 1411 1412 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE) 1413 constructor = APEReader_CreateInstance; 1414 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) 1415 constructor = GifCommentReader_CreateInstance; 1416 else 1417 constructor = UnknownMetadataReader_CreateInstance; 1418 1419 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, 1420 This->gif->Extensions.ExtensionBlocks[i].ByteCount, 1421 constructor, reader); 1422 } 1423 1424 return E_INVALIDARG; 1425 } 1426 1427 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1428 IEnumUnknown **enumerator) 1429 { 1430 FIXME("(%p,%p): stub\n", iface, enumerator); 1431 return E_NOTIMPL; 1432 } 1433 1434 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl = 1435 { 1436 GifDecoder_Block_QueryInterface, 1437 GifDecoder_Block_AddRef, 1438 GifDecoder_Block_Release, 1439 GifDecoder_Block_GetContainerFormat, 1440 GifDecoder_Block_GetCount, 1441 GifDecoder_Block_GetReaderByIndex, 1442 GifDecoder_Block_GetEnumerator 1443 }; 1444 1445 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv) 1446 { 1447 GifDecoder *This; 1448 HRESULT ret; 1449 1450 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1451 1452 *ppv = NULL; 1453 1454 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder)); 1455 if (!This) return E_OUTOFMEMORY; 1456 1457 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl; 1458 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl; 1459 This->stream = NULL; 1460 This->ref = 1; 1461 This->initialized = FALSE; 1462 This->gif = NULL; 1463 This->current_frame = 0; 1464 InitializeCriticalSection(&This->lock); 1465 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock"); 1466 1467 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1468 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1469 1470 return ret; 1471 } 1472 1473 typedef struct GifEncoder 1474 { 1475 IWICBitmapEncoder IWICBitmapEncoder_iface; 1476 LONG ref; 1477 IStream *stream; 1478 CRITICAL_SECTION lock; 1479 BOOL initialized, info_written, committed; 1480 UINT n_frames; 1481 WICColor palette[256]; 1482 UINT colors; 1483 } GifEncoder; 1484 1485 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 1486 { 1487 return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface); 1488 } 1489 1490 typedef struct GifFrameEncode 1491 { 1492 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 1493 LONG ref; 1494 GifEncoder *encoder; 1495 BOOL initialized, interlace, committed; 1496 UINT width, height, lines; 1497 double xres, yres; 1498 WICColor palette[256]; 1499 UINT colors; 1500 BYTE *image_data; 1501 } GifFrameEncode; 1502 1503 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 1504 { 1505 return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface); 1506 } 1507 1508 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv) 1509 { 1510 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); 1511 1512 if (!ppv) return E_INVALIDARG; 1513 1514 if (IsEqualIID(&IID_IUnknown, iid) || 1515 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 1516 { 1517 IWICBitmapFrameEncode_AddRef(iface); 1518 *ppv = iface; 1519 return S_OK; 1520 } 1521 1522 *ppv = NULL; 1523 return E_NOINTERFACE; 1524 } 1525 1526 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 1527 { 1528 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1529 ULONG ref = InterlockedIncrement(&This->ref); 1530 1531 TRACE("%p -> %u\n", iface, ref); 1532 return ref; 1533 } 1534 1535 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface) 1536 { 1537 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1538 ULONG ref = InterlockedDecrement(&This->ref); 1539 1540 TRACE("%p -> %u\n", iface, ref); 1541 1542 if (!ref) 1543 { 1544 IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface); 1545 HeapFree(GetProcessHeap(), 0, This->image_data); 1546 HeapFree(GetProcessHeap(), 0, This); 1547 } 1548 1549 return ref; 1550 } 1551 1552 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options) 1553 { 1554 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1555 HRESULT hr; 1556 1557 TRACE("%p,%p\n", iface, options); 1558 1559 EnterCriticalSection(&This->encoder->lock); 1560 1561 if (!This->initialized) 1562 { 1563 This->initialized = TRUE; 1564 hr = S_OK; 1565 } 1566 else 1567 hr = WINCODEC_ERR_WRONGSTATE; 1568 1569 LeaveCriticalSection(&This->encoder->lock); 1570 1571 return hr; 1572 } 1573 1574 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height) 1575 { 1576 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1577 HRESULT hr; 1578 1579 TRACE("%p,%u,%u\n", iface, width, height); 1580 1581 if (!width || !height) return E_INVALIDARG; 1582 1583 EnterCriticalSection(&This->encoder->lock); 1584 1585 if (This->initialized) 1586 { 1587 HeapFree(GetProcessHeap(), 0, This->image_data); 1588 1589 This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height); 1590 if (This->image_data) 1591 { 1592 This->width = width; 1593 This->height = height; 1594 hr = S_OK; 1595 } 1596 else 1597 hr = E_OUTOFMEMORY; 1598 } 1599 else 1600 hr = WINCODEC_ERR_WRONGSTATE; 1601 1602 LeaveCriticalSection(&This->encoder->lock); 1603 1604 return hr; 1605 } 1606 1607 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres) 1608 { 1609 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1610 HRESULT hr; 1611 1612 TRACE("%p,%f,%f\n", iface, xres, yres); 1613 1614 EnterCriticalSection(&This->encoder->lock); 1615 1616 if (This->initialized) 1617 { 1618 This->xres = xres; 1619 This->yres = yres; 1620 hr = S_OK; 1621 } 1622 else 1623 hr = WINCODEC_ERR_WRONGSTATE; 1624 1625 LeaveCriticalSection(&This->encoder->lock); 1626 1627 return hr; 1628 } 1629 1630 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format) 1631 { 1632 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1633 HRESULT hr; 1634 1635 TRACE("%p,%s\n", iface, debugstr_guid(format)); 1636 1637 if (!format) return E_INVALIDARG; 1638 1639 EnterCriticalSection(&This->encoder->lock); 1640 1641 if (This->initialized) 1642 { 1643 *format = GUID_WICPixelFormat8bppIndexed; 1644 hr = S_OK; 1645 } 1646 else 1647 hr = WINCODEC_ERR_WRONGSTATE; 1648 1649 LeaveCriticalSection(&This->encoder->lock); 1650 1651 return hr; 1652 } 1653 1654 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context) 1655 { 1656 FIXME("%p,%u,%p: stub\n", iface, count, context); 1657 return E_NOTIMPL; 1658 } 1659 1660 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette) 1661 { 1662 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1663 HRESULT hr; 1664 1665 TRACE("%p,%p\n", iface, palette); 1666 1667 if (!palette) return E_INVALIDARG; 1668 1669 EnterCriticalSection(&This->encoder->lock); 1670 1671 if (This->initialized) 1672 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1673 else 1674 hr = WINCODEC_ERR_NOTINITIALIZED; 1675 1676 LeaveCriticalSection(&This->encoder->lock); 1677 return hr; 1678 } 1679 1680 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail) 1681 { 1682 FIXME("%p,%p: stub\n", iface, thumbnail); 1683 return E_NOTIMPL; 1684 } 1685 1686 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels) 1687 { 1688 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1689 HRESULT hr; 1690 1691 TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels); 1692 1693 if (!pixels) return E_INVALIDARG; 1694 1695 EnterCriticalSection(&This->encoder->lock); 1696 1697 if (This->initialized && This->image_data) 1698 { 1699 if (This->lines + lines <= This->height) 1700 { 1701 UINT i; 1702 BYTE *src, *dst; 1703 1704 src = pixels; 1705 dst = This->image_data + This->lines * This->width; 1706 1707 for (i = 0; i < lines; i++) 1708 { 1709 memcpy(dst, src, This->width); 1710 src += stride; 1711 dst += This->width; 1712 } 1713 1714 This->lines += lines; 1715 hr = S_OK; 1716 } 1717 else 1718 hr = E_INVALIDARG; 1719 } 1720 else 1721 hr = WINCODEC_ERR_WRONGSTATE; 1722 1723 LeaveCriticalSection(&This->encoder->lock); 1724 return hr; 1725 } 1726 1727 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc) 1728 { 1729 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1730 HRESULT hr; 1731 1732 TRACE("%p,%p,%p\n", iface, source, rc); 1733 1734 if (!source) return E_INVALIDARG; 1735 1736 EnterCriticalSection(&This->encoder->lock); 1737 1738 if (This->initialized) 1739 { 1740 const GUID *format = &GUID_WICPixelFormat8bppIndexed; 1741 1742 hr = configure_write_source(iface, source, rc, format, 1743 This->width, This->height, This->xres, This->yres); 1744 if (hr == S_OK) 1745 hr = write_source(iface, source, rc, format, 8, This->width, This->height); 1746 } 1747 else 1748 hr = WINCODEC_ERR_WRONGSTATE; 1749 1750 LeaveCriticalSection(&This->encoder->lock); 1751 return hr; 1752 } 1753 1754 #define LZW_DICT_SIZE (1 << 12) 1755 1756 struct lzw_dict 1757 { 1758 short prefix[LZW_DICT_SIZE]; 1759 unsigned char suffix[LZW_DICT_SIZE]; 1760 }; 1761 1762 struct lzw_state 1763 { 1764 struct lzw_dict dict; 1765 short init_code_bits, code_bits, next_code, clear_code, eof_code; 1766 unsigned bits_buf; 1767 int bits_count; 1768 int (*user_write_data)(void *user_ptr, void *data, int length); 1769 void *user_ptr; 1770 }; 1771 1772 struct input_stream 1773 { 1774 unsigned len; 1775 const BYTE *in; 1776 }; 1777 1778 struct output_stream 1779 { 1780 struct 1781 { 1782 unsigned char len; 1783 char data[255]; 1784 } gif_block; 1785 IStream *out; 1786 }; 1787 1788 static int lzw_output_code(struct lzw_state *state, short code) 1789 { 1790 state->bits_buf |= code << state->bits_count; 1791 state->bits_count += state->code_bits; 1792 1793 while (state->bits_count >= 8) 1794 { 1795 unsigned char byte = (unsigned char)state->bits_buf; 1796 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1797 return 0; 1798 state->bits_buf >>= 8; 1799 state->bits_count -= 8; 1800 } 1801 1802 return 1; 1803 } 1804 1805 static inline int lzw_output_clear_code(struct lzw_state *state) 1806 { 1807 return lzw_output_code(state, state->clear_code); 1808 } 1809 1810 static inline int lzw_output_eof_code(struct lzw_state *state) 1811 { 1812 return lzw_output_code(state, state->eof_code); 1813 } 1814 1815 static int lzw_flush_bits(struct lzw_state *state) 1816 { 1817 unsigned char byte; 1818 1819 while (state->bits_count >= 8) 1820 { 1821 byte = (unsigned char)state->bits_buf; 1822 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1823 return 0; 1824 state->bits_buf >>= 8; 1825 state->bits_count -= 8; 1826 } 1827 1828 if (state->bits_count) 1829 { 1830 static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f }; 1831 1832 byte = (unsigned char)state->bits_buf & mask[state->bits_count]; 1833 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1834 return 0; 1835 } 1836 1837 state->bits_buf = 0; 1838 state->bits_count = 0; 1839 1840 return 1; 1841 } 1842 1843 static void lzw_dict_reset(struct lzw_state *state) 1844 { 1845 int i; 1846 1847 state->code_bits = state->init_code_bits + 1; 1848 state->next_code = (1 << state->init_code_bits) + 2; 1849 1850 for(i = 0; i < LZW_DICT_SIZE; i++) 1851 { 1852 state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */ 1853 state->dict.suffix[i] = 0; 1854 } 1855 } 1856 1857 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr) 1858 { 1859 state->init_code_bits = init_code_bits; 1860 state->clear_code = 1 << init_code_bits; 1861 state->eof_code = state->clear_code + 1; 1862 state->bits_buf = 0; 1863 state->bits_count = 0; 1864 state->user_write_data = user_write_data; 1865 state->user_ptr = user_ptr; 1866 1867 lzw_dict_reset(state); 1868 } 1869 1870 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix) 1871 { 1872 if (state->next_code < LZW_DICT_SIZE) 1873 { 1874 state->dict.prefix[state->next_code] = prefix; 1875 state->dict.suffix[state->next_code] = suffix; 1876 1877 if ((state->next_code & (state->next_code - 1)) == 0) 1878 state->code_bits++; 1879 1880 state->next_code++; 1881 return state->next_code; 1882 } 1883 1884 return -1; 1885 } 1886 1887 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix) 1888 { 1889 short i; 1890 1891 for (i = 0; i < state->next_code; i++) 1892 { 1893 if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix) 1894 return i; 1895 } 1896 1897 return -1; 1898 } 1899 1900 static inline int write_byte(struct output_stream *out, char byte) 1901 { 1902 if (out->gif_block.len == 255) 1903 { 1904 if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK) 1905 return 0; 1906 1907 out->gif_block.len = 0; 1908 } 1909 1910 out->gif_block.data[out->gif_block.len++] = byte; 1911 1912 return 1; 1913 } 1914 1915 static int write_data(void *user_ptr, void *user_data, int length) 1916 { 1917 unsigned char *data = user_data; 1918 struct output_stream *out = user_ptr; 1919 int len = length; 1920 1921 while (len-- > 0) 1922 { 1923 if (!write_byte(out, *data++)) return 0; 1924 } 1925 1926 return length; 1927 } 1928 1929 static int flush_output_data(void *user_ptr) 1930 { 1931 struct output_stream *out = user_ptr; 1932 1933 if (out->gif_block.len) 1934 { 1935 if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK) 1936 return 0; 1937 } 1938 1939 /* write GIF block terminator */ 1940 out->gif_block.len = 0; 1941 return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK; 1942 } 1943 1944 static inline int read_byte(struct input_stream *in, unsigned char *byte) 1945 { 1946 if (in->len) 1947 { 1948 in->len--; 1949 *byte = *in->in++; 1950 return 1; 1951 } 1952 1953 return 0; 1954 } 1955 1956 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size) 1957 { 1958 struct input_stream in; 1959 struct output_stream out; 1960 struct lzw_state state; 1961 short init_code_bits, prefix, code; 1962 unsigned char suffix; 1963 1964 in.in = in_data; 1965 in.len = in_size; 1966 1967 out.gif_block.len = 0; 1968 out.out = out_stream; 1969 1970 init_code_bits = suffix = 8; 1971 if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK) 1972 return E_FAIL; 1973 1974 lzw_state_init(&state, init_code_bits, write_data, &out); 1975 1976 if (!lzw_output_clear_code(&state)) 1977 return E_FAIL; 1978 1979 if (read_byte(&in, &suffix)) 1980 { 1981 prefix = suffix; 1982 1983 while (read_byte(&in, &suffix)) 1984 { 1985 code = lzw_dict_lookup(&state, prefix, suffix); 1986 if (code == -1) 1987 { 1988 if (!lzw_output_code(&state, prefix)) 1989 return E_FAIL; 1990 1991 if (lzw_dict_add(&state, prefix, suffix) == -1) 1992 { 1993 if (!lzw_output_clear_code(&state)) 1994 return E_FAIL; 1995 lzw_dict_reset(&state); 1996 } 1997 1998 prefix = suffix; 1999 } 2000 else 2001 prefix = code; 2002 } 2003 2004 if (!lzw_output_code(&state, prefix)) 2005 return E_FAIL; 2006 if (!lzw_output_eof_code(&state)) 2007 return E_FAIL; 2008 if (!lzw_flush_bits(&state)) 2009 return E_FAIL; 2010 } 2011 2012 return flush_output_data(&out) ? S_OK : E_FAIL; 2013 } 2014 2015 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface) 2016 { 2017 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 2018 HRESULT hr; 2019 2020 TRACE("%p\n", iface); 2021 2022 EnterCriticalSection(&This->encoder->lock); 2023 2024 if (This->image_data && This->lines == This->height && !This->committed) 2025 { 2026 BYTE gif_palette[256][3]; 2027 2028 hr = S_OK; 2029 2030 if (!This->encoder->info_written) 2031 { 2032 struct logical_screen_descriptor lsd; 2033 2034 /* Logical Screen Descriptor */ 2035 memcpy(lsd.signature, "GIF89a", 6); 2036 lsd.width = This->width; 2037 lsd.height = This->height; 2038 lsd.packed = 0; 2039 if (This->encoder->colors) 2040 lsd.packed |= 0x80; /* global color table flag */ 2041 lsd.packed |= 0x07 << 4; /* color resolution */ 2042 lsd.packed |= 0x07; /* global color table size */ 2043 lsd.background_color_index = 0; /* FIXME */ 2044 lsd.pixel_aspect_ratio = 0; 2045 hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL); 2046 if (hr == S_OK && This->encoder->colors) 2047 { 2048 UINT i; 2049 2050 /* Global Color Table */ 2051 memset(gif_palette, 0, sizeof(gif_palette)); 2052 for (i = 0; i < This->encoder->colors; i++) 2053 { 2054 gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff; 2055 gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff; 2056 gif_palette[i][2] = This->encoder->palette[i] & 0xff; 2057 } 2058 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); 2059 } 2060 2061 /* FIXME: write GCE, APE, etc. GIF extensions */ 2062 2063 if (hr == S_OK) 2064 This->encoder->info_written = TRUE; 2065 } 2066 2067 if (hr == S_OK) 2068 { 2069 char image_separator = 0x2c; 2070 2071 hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL); 2072 if (hr == S_OK) 2073 { 2074 struct image_descriptor imd; 2075 2076 /* Image Descriptor */ 2077 imd.left = 0; 2078 imd.top = 0; 2079 imd.width = This->width; 2080 imd.height = This->height; 2081 imd.packed = 0; 2082 if (This->colors) 2083 { 2084 imd.packed |= 0x80; /* local color table flag */ 2085 imd.packed |= 0x07; /* local color table size */ 2086 } 2087 /* FIXME: interlace flag */ 2088 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL); 2089 if (hr == S_OK && This->colors) 2090 { 2091 UINT i; 2092 2093 /* Local Color Table */ 2094 memset(gif_palette, 0, sizeof(gif_palette)); 2095 for (i = 0; i < This->colors; i++) 2096 { 2097 gif_palette[i][0] = (This->palette[i] >> 16) & 0xff; 2098 gif_palette[i][1] = (This->palette[i] >> 8) & 0xff; 2099 gif_palette[i][2] = This->palette[i] & 0xff; 2100 } 2101 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); 2102 if (hr == S_OK) 2103 { 2104 /* Image Data */ 2105 hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height); 2106 if (hr == S_OK) 2107 This->committed = TRUE; 2108 } 2109 } 2110 } 2111 } 2112 } 2113 else 2114 hr = WINCODEC_ERR_WRONGSTATE; 2115 2116 LeaveCriticalSection(&This->encoder->lock); 2117 return hr; 2118 } 2119 2120 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer) 2121 { 2122 FIXME("%p, %p: stub\n", iface, writer); 2123 return E_NOTIMPL; 2124 } 2125 2126 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl = 2127 { 2128 GifFrameEncode_QueryInterface, 2129 GifFrameEncode_AddRef, 2130 GifFrameEncode_Release, 2131 GifFrameEncode_Initialize, 2132 GifFrameEncode_SetSize, 2133 GifFrameEncode_SetResolution, 2134 GifFrameEncode_SetPixelFormat, 2135 GifFrameEncode_SetColorContexts, 2136 GifFrameEncode_SetPalette, 2137 GifFrameEncode_SetThumbnail, 2138 GifFrameEncode_WritePixels, 2139 GifFrameEncode_WriteSource, 2140 GifFrameEncode_Commit, 2141 GifFrameEncode_GetMetadataQueryWriter 2142 }; 2143 2144 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv) 2145 { 2146 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); 2147 2148 if (!ppv) return E_INVALIDARG; 2149 2150 if (IsEqualIID(&IID_IUnknown, iid) || 2151 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 2152 { 2153 IWICBitmapEncoder_AddRef(iface); 2154 *ppv = iface; 2155 return S_OK; 2156 } 2157 2158 *ppv = NULL; 2159 return E_NOINTERFACE; 2160 } 2161 2162 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface) 2163 { 2164 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2165 ULONG ref = InterlockedIncrement(&This->ref); 2166 2167 TRACE("%p -> %u\n", iface, ref); 2168 return ref; 2169 } 2170 2171 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface) 2172 { 2173 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2174 ULONG ref = InterlockedDecrement(&This->ref); 2175 2176 TRACE("%p -> %u\n", iface, ref); 2177 2178 if (!ref) 2179 { 2180 if (This->stream) IStream_Release(This->stream); 2181 This->lock.DebugInfo->Spare[0] = 0; 2182 DeleteCriticalSection(&This->lock); 2183 HeapFree(GetProcessHeap(), 0, This); 2184 } 2185 2186 return ref; 2187 } 2188 2189 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option) 2190 { 2191 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2192 HRESULT hr; 2193 2194 TRACE("%p,%p,%#x\n", iface, stream, option); 2195 2196 if (!stream) return E_INVALIDARG; 2197 2198 EnterCriticalSection(&This->lock); 2199 2200 if (!This->initialized) 2201 { 2202 IStream_AddRef(stream); 2203 This->stream = stream; 2204 This->initialized = TRUE; 2205 hr = S_OK; 2206 } 2207 else 2208 hr = WINCODEC_ERR_WRONGSTATE; 2209 2210 LeaveCriticalSection(&This->lock); 2211 2212 return hr; 2213 } 2214 2215 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format) 2216 { 2217 if (!format) return E_INVALIDARG; 2218 2219 *format = GUID_ContainerFormatGif; 2220 return S_OK; 2221 } 2222 2223 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 2224 { 2225 IWICComponentInfo *comp_info; 2226 HRESULT hr; 2227 2228 TRACE("%p,%p\n", iface, info); 2229 2230 if (!info) return E_INVALIDARG; 2231 2232 hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info); 2233 if (hr == S_OK) 2234 { 2235 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 2236 IWICComponentInfo_Release(comp_info); 2237 } 2238 return hr; 2239 } 2240 2241 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context) 2242 { 2243 FIXME("%p,%u,%p: stub\n", iface, count, context); 2244 return E_NOTIMPL; 2245 } 2246 2247 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 2248 { 2249 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2250 HRESULT hr; 2251 2252 TRACE("%p,%p\n", iface, palette); 2253 2254 if (!palette) return E_INVALIDARG; 2255 2256 EnterCriticalSection(&This->lock); 2257 2258 if (This->initialized) 2259 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 2260 else 2261 hr = WINCODEC_ERR_NOTINITIALIZED; 2262 2263 LeaveCriticalSection(&This->lock); 2264 return hr; 2265 } 2266 2267 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail) 2268 { 2269 TRACE("%p,%p\n", iface, thumbnail); 2270 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2271 } 2272 2273 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview) 2274 { 2275 TRACE("%p,%p\n", iface, preview); 2276 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2277 } 2278 2279 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options) 2280 { 2281 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2282 HRESULT hr; 2283 2284 TRACE("%p,%p,%p\n", iface, frame, options); 2285 2286 if (!frame) return E_INVALIDARG; 2287 2288 EnterCriticalSection(&This->lock); 2289 2290 if (This->initialized && !This->committed) 2291 { 2292 GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); 2293 if (ret) 2294 { 2295 This->n_frames++; 2296 2297 ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl; 2298 ret->ref = 1; 2299 ret->encoder = This; 2300 ret->initialized = FALSE; 2301 ret->interlace = FALSE; /* FIXME: read from the properties */ 2302 ret->committed = FALSE; 2303 ret->width = 0; 2304 ret->height = 0; 2305 ret->lines = 0; 2306 ret->xres = 0.0; 2307 ret->yres = 0.0; 2308 ret->colors = 0; 2309 ret->image_data = NULL; 2310 IWICBitmapEncoder_AddRef(iface); 2311 *frame = &ret->IWICBitmapFrameEncode_iface; 2312 2313 hr = S_OK; 2314 2315 if (options) 2316 { 2317 hr = CreatePropertyBag2(NULL, 0, options); 2318 if (hr != S_OK) 2319 { 2320 IWICBitmapFrameEncode_Release(*frame); 2321 *frame = NULL; 2322 } 2323 } 2324 } 2325 else 2326 hr = E_OUTOFMEMORY; 2327 } 2328 else 2329 hr = WINCODEC_ERR_WRONGSTATE; 2330 2331 LeaveCriticalSection(&This->lock); 2332 2333 return hr; 2334 2335 } 2336 2337 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface) 2338 { 2339 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2340 HRESULT hr; 2341 2342 TRACE("%p\n", iface); 2343 2344 EnterCriticalSection(&This->lock); 2345 2346 if (This->initialized && !This->committed) 2347 { 2348 char gif_trailer = 0x3b; 2349 2350 /* FIXME: write text, comment GIF extensions */ 2351 2352 hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL); 2353 if (hr == S_OK) 2354 This->committed = TRUE; 2355 } 2356 else 2357 hr = WINCODEC_ERR_WRONGSTATE; 2358 2359 LeaveCriticalSection(&This->lock); 2360 return hr; 2361 } 2362 2363 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer) 2364 { 2365 FIXME("%p,%p: stub\n", iface, writer); 2366 return E_NOTIMPL; 2367 } 2368 2369 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl = 2370 { 2371 GifEncoder_QueryInterface, 2372 GifEncoder_AddRef, 2373 GifEncoder_Release, 2374 GifEncoder_Initialize, 2375 GifEncoder_GetContainerFormat, 2376 GifEncoder_GetEncoderInfo, 2377 GifEncoder_SetColorContexts, 2378 GifEncoder_SetPalette, 2379 GifEncoder_SetThumbnail, 2380 GifEncoder_SetPreview, 2381 GifEncoder_CreateNewFrame, 2382 GifEncoder_Commit, 2383 GifEncoder_GetMetadataQueryWriter 2384 }; 2385 2386 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv) 2387 { 2388 GifEncoder *This; 2389 HRESULT ret; 2390 2391 TRACE("%s,%p\n", debugstr_guid(iid), ppv); 2392 2393 *ppv = NULL; 2394 2395 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 2396 if (!This) return E_OUTOFMEMORY; 2397 2398 This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl; 2399 This->ref = 1; 2400 This->stream = NULL; 2401 InitializeCriticalSection(&This->lock); 2402 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock"); 2403 This->initialized = FALSE; 2404 This->info_written = FALSE; 2405 This->committed = FALSE; 2406 This->n_frames = 0; 2407 This->colors = 0; 2408 2409 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 2410 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 2411 2412 return ret; 2413 } 2414