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 TRACE("(%p,%p)\n", iface, ppIDecoderInfo); 1180 1181 return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo); 1182 } 1183 1184 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette) 1185 { 1186 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1187 WICColor colors[256]; 1188 ColorMapObject *cm; 1189 int i, trans, count; 1190 ExtensionBlock *eb; 1191 1192 TRACE("(%p,%p)\n", iface, palette); 1193 1194 if (!This->gif) 1195 return WINCODEC_ERR_WRONGSTATE; 1196 1197 cm = This->gif->SColorMap; 1198 if (cm) 1199 { 1200 if (cm->ColorCount > 256) 1201 { 1202 ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount); 1203 return E_FAIL; 1204 } 1205 1206 for (i = 0; i < cm->ColorCount; i++) 1207 { 1208 colors[i] = 0xff000000 | /* alpha */ 1209 cm->Colors[i].Red << 16 | 1210 cm->Colors[i].Green << 8 | 1211 cm->Colors[i].Blue; 1212 } 1213 1214 count = cm->ColorCount; 1215 } 1216 else 1217 { 1218 colors[0] = 0xff000000; 1219 colors[1] = 0xffffffff; 1220 1221 for (i = 2; i < 256; i++) 1222 colors[i] = 0xff000000; 1223 1224 count = 256; 1225 } 1226 1227 /* look for the transparent color extension */ 1228 for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++) 1229 { 1230 eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i; 1231 if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) 1232 { 1233 if (eb->Bytes[3] & 1) 1234 { 1235 trans = (unsigned char)eb->Bytes[6]; 1236 colors[trans] &= 0xffffff; /* set alpha to 0 */ 1237 break; 1238 } 1239 } 1240 } 1241 1242 return IWICPalette_InitializeCustom(palette, colors, count); 1243 } 1244 1245 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, 1246 IWICMetadataQueryReader **ppIMetadataQueryReader) 1247 { 1248 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1249 1250 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); 1251 1252 if (!ppIMetadataQueryReader) return E_INVALIDARG; 1253 1254 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); 1255 } 1256 1257 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface, 1258 IWICBitmapSource **ppIBitmapSource) 1259 { 1260 TRACE("(%p,%p)\n", iface, ppIBitmapSource); 1261 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1262 } 1263 1264 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface, 1265 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) 1266 { 1267 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); 1268 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 1269 } 1270 1271 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface, 1272 IWICBitmapSource **ppIThumbnail) 1273 { 1274 TRACE("(%p,%p)\n", iface, ppIThumbnail); 1275 return WINCODEC_ERR_CODECNOTHUMBNAIL; 1276 } 1277 1278 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface, 1279 UINT *pCount) 1280 { 1281 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1282 1283 if (!pCount) return E_INVALIDARG; 1284 1285 EnterCriticalSection(&This->lock); 1286 *pCount = This->gif ? This->gif->ImageCount : 0; 1287 LeaveCriticalSection(&This->lock); 1288 1289 TRACE("(%p) <-- %d\n", iface, *pCount); 1290 1291 return S_OK; 1292 } 1293 1294 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface, 1295 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) 1296 { 1297 GifDecoder *This = impl_from_IWICBitmapDecoder(iface); 1298 GifFrameDecode *result; 1299 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); 1300 1301 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; 1302 1303 if (index >= This->gif->ImageCount) return E_INVALIDARG; 1304 1305 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode)); 1306 if (!result) return E_OUTOFMEMORY; 1307 1308 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl; 1309 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl; 1310 result->ref = 1; 1311 result->frame = &This->gif->SavedImages[index]; 1312 IWICBitmapDecoder_AddRef(iface); 1313 result->parent = This; 1314 This->current_frame = index; 1315 1316 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; 1317 1318 return S_OK; 1319 } 1320 1321 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = { 1322 GifDecoder_QueryInterface, 1323 GifDecoder_AddRef, 1324 GifDecoder_Release, 1325 GifDecoder_QueryCapability, 1326 GifDecoder_Initialize, 1327 GifDecoder_GetContainerFormat, 1328 GifDecoder_GetDecoderInfo, 1329 GifDecoder_CopyPalette, 1330 GifDecoder_GetMetadataQueryReader, 1331 GifDecoder_GetPreview, 1332 GifDecoder_GetColorContexts, 1333 GifDecoder_GetThumbnail, 1334 GifDecoder_GetFrameCount, 1335 GifDecoder_GetFrame 1336 }; 1337 1338 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, 1339 REFIID iid, void **ppv) 1340 { 1341 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1342 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1343 } 1344 1345 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface) 1346 { 1347 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1348 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); 1349 } 1350 1351 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface) 1352 { 1353 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1354 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1355 } 1356 1357 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, 1358 GUID *guid) 1359 { 1360 TRACE("(%p,%p)\n", iface, guid); 1361 1362 if (!guid) return E_INVALIDARG; 1363 1364 *guid = GUID_ContainerFormatGif; 1365 return S_OK; 1366 } 1367 1368 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface, 1369 UINT *count) 1370 { 1371 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1372 1373 TRACE("%p,%p\n", iface, count); 1374 1375 if (!count) return E_INVALIDARG; 1376 1377 *count = This->gif->Extensions.ExtensionBlockCount + 1; 1378 return S_OK; 1379 } 1380 1381 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, 1382 UINT index, IWICMetadataReader **reader) 1383 { 1384 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface); 1385 int i; 1386 1387 TRACE("(%p,%u,%p)\n", iface, index, reader); 1388 1389 if (!reader) return E_INVALIDARG; 1390 1391 if (index == 0) 1392 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data), 1393 LSDReader_CreateInstance, reader); 1394 1395 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) 1396 { 1397 class_constructor constructor; 1398 1399 if (index != i + 1) continue; 1400 1401 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE) 1402 constructor = APEReader_CreateInstance; 1403 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) 1404 constructor = GifCommentReader_CreateInstance; 1405 else 1406 constructor = UnknownMetadataReader_CreateInstance; 1407 1408 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, 1409 This->gif->Extensions.ExtensionBlocks[i].ByteCount, 1410 constructor, reader); 1411 } 1412 1413 return E_INVALIDARG; 1414 } 1415 1416 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, 1417 IEnumUnknown **enumerator) 1418 { 1419 FIXME("(%p,%p): stub\n", iface, enumerator); 1420 return E_NOTIMPL; 1421 } 1422 1423 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl = 1424 { 1425 GifDecoder_Block_QueryInterface, 1426 GifDecoder_Block_AddRef, 1427 GifDecoder_Block_Release, 1428 GifDecoder_Block_GetContainerFormat, 1429 GifDecoder_Block_GetCount, 1430 GifDecoder_Block_GetReaderByIndex, 1431 GifDecoder_Block_GetEnumerator 1432 }; 1433 1434 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv) 1435 { 1436 GifDecoder *This; 1437 HRESULT ret; 1438 1439 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); 1440 1441 *ppv = NULL; 1442 1443 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder)); 1444 if (!This) return E_OUTOFMEMORY; 1445 1446 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl; 1447 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl; 1448 This->stream = NULL; 1449 This->ref = 1; 1450 This->initialized = FALSE; 1451 This->gif = NULL; 1452 This->current_frame = 0; 1453 InitializeCriticalSection(&This->lock); 1454 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock"); 1455 1456 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); 1457 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); 1458 1459 return ret; 1460 } 1461 1462 typedef struct GifEncoder 1463 { 1464 IWICBitmapEncoder IWICBitmapEncoder_iface; 1465 LONG ref; 1466 IStream *stream; 1467 CRITICAL_SECTION lock; 1468 BOOL initialized, info_written, committed; 1469 UINT n_frames; 1470 WICColor palette[256]; 1471 UINT colors; 1472 } GifEncoder; 1473 1474 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) 1475 { 1476 return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface); 1477 } 1478 1479 typedef struct GifFrameEncode 1480 { 1481 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; 1482 LONG ref; 1483 GifEncoder *encoder; 1484 BOOL initialized, interlace, committed; 1485 UINT width, height, lines; 1486 double xres, yres; 1487 WICColor palette[256]; 1488 UINT colors; 1489 BYTE *image_data; 1490 } GifFrameEncode; 1491 1492 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) 1493 { 1494 return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface); 1495 } 1496 1497 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv) 1498 { 1499 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); 1500 1501 if (!ppv) return E_INVALIDARG; 1502 1503 if (IsEqualIID(&IID_IUnknown, iid) || 1504 IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) 1505 { 1506 IWICBitmapFrameEncode_AddRef(iface); 1507 *ppv = iface; 1508 return S_OK; 1509 } 1510 1511 *ppv = NULL; 1512 return E_NOINTERFACE; 1513 } 1514 1515 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface) 1516 { 1517 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1518 ULONG ref = InterlockedIncrement(&This->ref); 1519 1520 TRACE("%p -> %u\n", iface, ref); 1521 return ref; 1522 } 1523 1524 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface) 1525 { 1526 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1527 ULONG ref = InterlockedDecrement(&This->ref); 1528 1529 TRACE("%p -> %u\n", iface, ref); 1530 1531 if (!ref) 1532 { 1533 IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface); 1534 HeapFree(GetProcessHeap(), 0, This->image_data); 1535 HeapFree(GetProcessHeap(), 0, This); 1536 } 1537 1538 return ref; 1539 } 1540 1541 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options) 1542 { 1543 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1544 HRESULT hr; 1545 1546 TRACE("%p,%p\n", iface, options); 1547 1548 EnterCriticalSection(&This->encoder->lock); 1549 1550 if (!This->initialized) 1551 { 1552 This->initialized = TRUE; 1553 hr = S_OK; 1554 } 1555 else 1556 hr = WINCODEC_ERR_WRONGSTATE; 1557 1558 LeaveCriticalSection(&This->encoder->lock); 1559 1560 return hr; 1561 } 1562 1563 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height) 1564 { 1565 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1566 HRESULT hr; 1567 1568 TRACE("%p,%u,%u\n", iface, width, height); 1569 1570 if (!width || !height) return E_INVALIDARG; 1571 1572 EnterCriticalSection(&This->encoder->lock); 1573 1574 if (This->initialized) 1575 { 1576 HeapFree(GetProcessHeap(), 0, This->image_data); 1577 1578 This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height); 1579 if (This->image_data) 1580 { 1581 This->width = width; 1582 This->height = height; 1583 hr = S_OK; 1584 } 1585 else 1586 hr = E_OUTOFMEMORY; 1587 } 1588 else 1589 hr = WINCODEC_ERR_WRONGSTATE; 1590 1591 LeaveCriticalSection(&This->encoder->lock); 1592 1593 return hr; 1594 } 1595 1596 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres) 1597 { 1598 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1599 HRESULT hr; 1600 1601 TRACE("%p,%f,%f\n", iface, xres, yres); 1602 1603 EnterCriticalSection(&This->encoder->lock); 1604 1605 if (This->initialized) 1606 { 1607 This->xres = xres; 1608 This->yres = yres; 1609 hr = S_OK; 1610 } 1611 else 1612 hr = WINCODEC_ERR_WRONGSTATE; 1613 1614 LeaveCriticalSection(&This->encoder->lock); 1615 1616 return hr; 1617 } 1618 1619 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format) 1620 { 1621 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1622 HRESULT hr; 1623 1624 TRACE("%p,%s\n", iface, debugstr_guid(format)); 1625 1626 if (!format) return E_INVALIDARG; 1627 1628 EnterCriticalSection(&This->encoder->lock); 1629 1630 if (This->initialized) 1631 { 1632 *format = GUID_WICPixelFormat8bppIndexed; 1633 hr = S_OK; 1634 } 1635 else 1636 hr = WINCODEC_ERR_WRONGSTATE; 1637 1638 LeaveCriticalSection(&This->encoder->lock); 1639 1640 return hr; 1641 } 1642 1643 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context) 1644 { 1645 FIXME("%p,%u,%p: stub\n", iface, count, context); 1646 return E_NOTIMPL; 1647 } 1648 1649 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette) 1650 { 1651 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1652 HRESULT hr; 1653 1654 TRACE("%p,%p\n", iface, palette); 1655 1656 if (!palette) return E_INVALIDARG; 1657 1658 EnterCriticalSection(&This->encoder->lock); 1659 1660 if (This->initialized) 1661 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 1662 else 1663 hr = WINCODEC_ERR_NOTINITIALIZED; 1664 1665 LeaveCriticalSection(&This->encoder->lock); 1666 return hr; 1667 } 1668 1669 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail) 1670 { 1671 FIXME("%p,%p: stub\n", iface, thumbnail); 1672 return E_NOTIMPL; 1673 } 1674 1675 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels) 1676 { 1677 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1678 HRESULT hr; 1679 1680 TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels); 1681 1682 if (!pixels) return E_INVALIDARG; 1683 1684 EnterCriticalSection(&This->encoder->lock); 1685 1686 if (This->initialized && This->image_data) 1687 { 1688 if (This->lines + lines <= This->height) 1689 { 1690 UINT i; 1691 BYTE *src, *dst; 1692 1693 src = pixels; 1694 dst = This->image_data + This->lines * This->width; 1695 1696 for (i = 0; i < lines; i++) 1697 { 1698 memcpy(dst, src, This->width); 1699 src += stride; 1700 dst += This->width; 1701 } 1702 1703 This->lines += lines; 1704 hr = S_OK; 1705 } 1706 else 1707 hr = E_INVALIDARG; 1708 } 1709 else 1710 hr = WINCODEC_ERR_WRONGSTATE; 1711 1712 LeaveCriticalSection(&This->encoder->lock); 1713 return hr; 1714 } 1715 1716 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc) 1717 { 1718 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 1719 HRESULT hr; 1720 1721 TRACE("%p,%p,%p\n", iface, source, rc); 1722 1723 if (!source) return E_INVALIDARG; 1724 1725 EnterCriticalSection(&This->encoder->lock); 1726 1727 if (This->initialized) 1728 { 1729 const GUID *format = &GUID_WICPixelFormat8bppIndexed; 1730 1731 hr = configure_write_source(iface, source, rc, format, 1732 This->width, This->height, This->xres, This->yres); 1733 if (hr == S_OK) 1734 hr = write_source(iface, source, rc, format, 8, This->width, This->height); 1735 } 1736 else 1737 hr = WINCODEC_ERR_WRONGSTATE; 1738 1739 LeaveCriticalSection(&This->encoder->lock); 1740 return hr; 1741 } 1742 1743 #define LZW_DICT_SIZE (1 << 12) 1744 1745 struct lzw_dict 1746 { 1747 short prefix[LZW_DICT_SIZE]; 1748 unsigned char suffix[LZW_DICT_SIZE]; 1749 }; 1750 1751 struct lzw_state 1752 { 1753 struct lzw_dict dict; 1754 short init_code_bits, code_bits, next_code, clear_code, eof_code; 1755 unsigned bits_buf; 1756 int bits_count; 1757 int (*user_write_data)(void *user_ptr, void *data, int length); 1758 void *user_ptr; 1759 }; 1760 1761 struct input_stream 1762 { 1763 unsigned len; 1764 const BYTE *in; 1765 }; 1766 1767 struct output_stream 1768 { 1769 struct 1770 { 1771 unsigned char len; 1772 char data[255]; 1773 } gif_block; 1774 IStream *out; 1775 }; 1776 1777 static int lzw_output_code(struct lzw_state *state, short code) 1778 { 1779 state->bits_buf |= code << state->bits_count; 1780 state->bits_count += state->code_bits; 1781 1782 while (state->bits_count >= 8) 1783 { 1784 unsigned char byte = (unsigned char)state->bits_buf; 1785 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1786 return 0; 1787 state->bits_buf >>= 8; 1788 state->bits_count -= 8; 1789 } 1790 1791 return 1; 1792 } 1793 1794 static inline int lzw_output_clear_code(struct lzw_state *state) 1795 { 1796 return lzw_output_code(state, state->clear_code); 1797 } 1798 1799 static inline int lzw_output_eof_code(struct lzw_state *state) 1800 { 1801 return lzw_output_code(state, state->eof_code); 1802 } 1803 1804 static int lzw_flush_bits(struct lzw_state *state) 1805 { 1806 unsigned char byte; 1807 1808 while (state->bits_count >= 8) 1809 { 1810 byte = (unsigned char)state->bits_buf; 1811 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1812 return 0; 1813 state->bits_buf >>= 8; 1814 state->bits_count -= 8; 1815 } 1816 1817 if (state->bits_count) 1818 { 1819 static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f }; 1820 1821 byte = (unsigned char)state->bits_buf & mask[state->bits_count]; 1822 if (state->user_write_data(state->user_ptr, &byte, 1) != 1) 1823 return 0; 1824 } 1825 1826 state->bits_buf = 0; 1827 state->bits_count = 0; 1828 1829 return 1; 1830 } 1831 1832 static void lzw_dict_reset(struct lzw_state *state) 1833 { 1834 int i; 1835 1836 state->code_bits = state->init_code_bits + 1; 1837 state->next_code = (1 << state->init_code_bits) + 2; 1838 1839 for(i = 0; i < LZW_DICT_SIZE; i++) 1840 { 1841 state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */ 1842 state->dict.suffix[i] = 0; 1843 } 1844 } 1845 1846 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr) 1847 { 1848 state->init_code_bits = init_code_bits; 1849 state->clear_code = 1 << init_code_bits; 1850 state->eof_code = state->clear_code + 1; 1851 state->bits_buf = 0; 1852 state->bits_count = 0; 1853 state->user_write_data = user_write_data; 1854 state->user_ptr = user_ptr; 1855 1856 lzw_dict_reset(state); 1857 } 1858 1859 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix) 1860 { 1861 if (state->next_code < LZW_DICT_SIZE) 1862 { 1863 state->dict.prefix[state->next_code] = prefix; 1864 state->dict.suffix[state->next_code] = suffix; 1865 1866 if ((state->next_code & (state->next_code - 1)) == 0) 1867 state->code_bits++; 1868 1869 state->next_code++; 1870 return state->next_code; 1871 } 1872 1873 return -1; 1874 } 1875 1876 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix) 1877 { 1878 short i; 1879 1880 for (i = 0; i < state->next_code; i++) 1881 { 1882 if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix) 1883 return i; 1884 } 1885 1886 return -1; 1887 } 1888 1889 static inline int write_byte(struct output_stream *out, char byte) 1890 { 1891 if (out->gif_block.len == 255) 1892 { 1893 if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK) 1894 return 0; 1895 1896 out->gif_block.len = 0; 1897 } 1898 1899 out->gif_block.data[out->gif_block.len++] = byte; 1900 1901 return 1; 1902 } 1903 1904 static int write_data(void *user_ptr, void *user_data, int length) 1905 { 1906 unsigned char *data = user_data; 1907 struct output_stream *out = user_ptr; 1908 int len = length; 1909 1910 while (len-- > 0) 1911 { 1912 if (!write_byte(out, *data++)) return 0; 1913 } 1914 1915 return length; 1916 } 1917 1918 static int flush_output_data(void *user_ptr) 1919 { 1920 struct output_stream *out = user_ptr; 1921 1922 if (out->gif_block.len) 1923 { 1924 if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK) 1925 return 0; 1926 } 1927 1928 /* write GIF block terminator */ 1929 out->gif_block.len = 0; 1930 return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK; 1931 } 1932 1933 static inline int read_byte(struct input_stream *in, unsigned char *byte) 1934 { 1935 if (in->len) 1936 { 1937 in->len--; 1938 *byte = *in->in++; 1939 return 1; 1940 } 1941 1942 return 0; 1943 } 1944 1945 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size) 1946 { 1947 struct input_stream in; 1948 struct output_stream out; 1949 struct lzw_state state; 1950 short init_code_bits, prefix, code; 1951 unsigned char suffix; 1952 1953 in.in = in_data; 1954 in.len = in_size; 1955 1956 out.gif_block.len = 0; 1957 out.out = out_stream; 1958 1959 init_code_bits = suffix = 8; 1960 if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK) 1961 return E_FAIL; 1962 1963 lzw_state_init(&state, init_code_bits, write_data, &out); 1964 1965 if (!lzw_output_clear_code(&state)) 1966 return E_FAIL; 1967 1968 if (read_byte(&in, &suffix)) 1969 { 1970 prefix = suffix; 1971 1972 while (read_byte(&in, &suffix)) 1973 { 1974 code = lzw_dict_lookup(&state, prefix, suffix); 1975 if (code == -1) 1976 { 1977 if (!lzw_output_code(&state, prefix)) 1978 return E_FAIL; 1979 1980 if (lzw_dict_add(&state, prefix, suffix) == -1) 1981 { 1982 if (!lzw_output_clear_code(&state)) 1983 return E_FAIL; 1984 lzw_dict_reset(&state); 1985 } 1986 1987 prefix = suffix; 1988 } 1989 else 1990 prefix = code; 1991 } 1992 1993 if (!lzw_output_code(&state, prefix)) 1994 return E_FAIL; 1995 if (!lzw_output_eof_code(&state)) 1996 return E_FAIL; 1997 if (!lzw_flush_bits(&state)) 1998 return E_FAIL; 1999 } 2000 2001 return flush_output_data(&out) ? S_OK : E_FAIL; 2002 } 2003 2004 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface) 2005 { 2006 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); 2007 HRESULT hr; 2008 2009 TRACE("%p\n", iface); 2010 2011 EnterCriticalSection(&This->encoder->lock); 2012 2013 if (This->image_data && This->lines == This->height && !This->committed) 2014 { 2015 BYTE gif_palette[256][3]; 2016 2017 hr = S_OK; 2018 2019 if (!This->encoder->info_written) 2020 { 2021 struct logical_screen_descriptor lsd; 2022 2023 /* Logical Screen Descriptor */ 2024 memcpy(lsd.signature, "GIF89a", 6); 2025 lsd.width = This->width; 2026 lsd.height = This->height; 2027 lsd.packed = 0; 2028 if (This->encoder->colors) 2029 lsd.packed |= 0x80; /* global color table flag */ 2030 lsd.packed |= 0x07 << 4; /* color resolution */ 2031 lsd.packed |= 0x07; /* global color table size */ 2032 lsd.background_color_index = 0; /* FIXME */ 2033 lsd.pixel_aspect_ratio = 0; 2034 hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL); 2035 if (hr == S_OK && This->encoder->colors) 2036 { 2037 UINT i; 2038 2039 /* Global Color Table */ 2040 memset(gif_palette, 0, sizeof(gif_palette)); 2041 for (i = 0; i < This->encoder->colors; i++) 2042 { 2043 gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff; 2044 gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff; 2045 gif_palette[i][2] = This->encoder->palette[i] & 0xff; 2046 } 2047 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); 2048 } 2049 2050 /* FIXME: write GCE, APE, etc. GIF extensions */ 2051 2052 if (hr == S_OK) 2053 This->encoder->info_written = TRUE; 2054 } 2055 2056 if (hr == S_OK) 2057 { 2058 char image_separator = 0x2c; 2059 2060 hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL); 2061 if (hr == S_OK) 2062 { 2063 struct image_descriptor imd; 2064 2065 /* Image Descriptor */ 2066 imd.left = 0; 2067 imd.top = 0; 2068 imd.width = This->width; 2069 imd.height = This->height; 2070 imd.packed = 0; 2071 if (This->colors) 2072 { 2073 imd.packed |= 0x80; /* local color table flag */ 2074 imd.packed |= 0x07; /* local color table size */ 2075 } 2076 /* FIXME: interlace flag */ 2077 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL); 2078 if (hr == S_OK && This->colors) 2079 { 2080 UINT i; 2081 2082 /* Local Color Table */ 2083 memset(gif_palette, 0, sizeof(gif_palette)); 2084 for (i = 0; i < This->colors; i++) 2085 { 2086 gif_palette[i][0] = (This->palette[i] >> 16) & 0xff; 2087 gif_palette[i][1] = (This->palette[i] >> 8) & 0xff; 2088 gif_palette[i][2] = This->palette[i] & 0xff; 2089 } 2090 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); 2091 if (hr == S_OK) 2092 { 2093 /* Image Data */ 2094 hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height); 2095 if (hr == S_OK) 2096 This->committed = TRUE; 2097 } 2098 } 2099 } 2100 } 2101 } 2102 else 2103 hr = WINCODEC_ERR_WRONGSTATE; 2104 2105 LeaveCriticalSection(&This->encoder->lock); 2106 return hr; 2107 } 2108 2109 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer) 2110 { 2111 FIXME("%p, %p: stub\n", iface, writer); 2112 return E_NOTIMPL; 2113 } 2114 2115 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl = 2116 { 2117 GifFrameEncode_QueryInterface, 2118 GifFrameEncode_AddRef, 2119 GifFrameEncode_Release, 2120 GifFrameEncode_Initialize, 2121 GifFrameEncode_SetSize, 2122 GifFrameEncode_SetResolution, 2123 GifFrameEncode_SetPixelFormat, 2124 GifFrameEncode_SetColorContexts, 2125 GifFrameEncode_SetPalette, 2126 GifFrameEncode_SetThumbnail, 2127 GifFrameEncode_WritePixels, 2128 GifFrameEncode_WriteSource, 2129 GifFrameEncode_Commit, 2130 GifFrameEncode_GetMetadataQueryWriter 2131 }; 2132 2133 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv) 2134 { 2135 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); 2136 2137 if (!ppv) return E_INVALIDARG; 2138 2139 if (IsEqualIID(&IID_IUnknown, iid) || 2140 IsEqualIID(&IID_IWICBitmapEncoder, iid)) 2141 { 2142 IWICBitmapEncoder_AddRef(iface); 2143 *ppv = iface; 2144 return S_OK; 2145 } 2146 2147 *ppv = NULL; 2148 return E_NOINTERFACE; 2149 } 2150 2151 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface) 2152 { 2153 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2154 ULONG ref = InterlockedIncrement(&This->ref); 2155 2156 TRACE("%p -> %u\n", iface, ref); 2157 return ref; 2158 } 2159 2160 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface) 2161 { 2162 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2163 ULONG ref = InterlockedDecrement(&This->ref); 2164 2165 TRACE("%p -> %u\n", iface, ref); 2166 2167 if (!ref) 2168 { 2169 if (This->stream) IStream_Release(This->stream); 2170 This->lock.DebugInfo->Spare[0] = 0; 2171 DeleteCriticalSection(&This->lock); 2172 HeapFree(GetProcessHeap(), 0, This); 2173 } 2174 2175 return ref; 2176 } 2177 2178 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option) 2179 { 2180 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2181 HRESULT hr; 2182 2183 TRACE("%p,%p,%#x\n", iface, stream, option); 2184 2185 if (!stream) return E_INVALIDARG; 2186 2187 EnterCriticalSection(&This->lock); 2188 2189 if (!This->initialized) 2190 { 2191 IStream_AddRef(stream); 2192 This->stream = stream; 2193 This->initialized = TRUE; 2194 hr = S_OK; 2195 } 2196 else 2197 hr = WINCODEC_ERR_WRONGSTATE; 2198 2199 LeaveCriticalSection(&This->lock); 2200 2201 return hr; 2202 } 2203 2204 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format) 2205 { 2206 if (!format) return E_INVALIDARG; 2207 2208 *format = GUID_ContainerFormatGif; 2209 return S_OK; 2210 } 2211 2212 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) 2213 { 2214 IWICComponentInfo *comp_info; 2215 HRESULT hr; 2216 2217 TRACE("%p,%p\n", iface, info); 2218 2219 if (!info) return E_INVALIDARG; 2220 2221 hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info); 2222 if (hr == S_OK) 2223 { 2224 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); 2225 IWICComponentInfo_Release(comp_info); 2226 } 2227 return hr; 2228 } 2229 2230 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context) 2231 { 2232 FIXME("%p,%u,%p: stub\n", iface, count, context); 2233 return E_NOTIMPL; 2234 } 2235 2236 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) 2237 { 2238 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2239 HRESULT hr; 2240 2241 TRACE("%p,%p\n", iface, palette); 2242 2243 if (!palette) return E_INVALIDARG; 2244 2245 EnterCriticalSection(&This->lock); 2246 2247 if (This->initialized) 2248 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); 2249 else 2250 hr = WINCODEC_ERR_NOTINITIALIZED; 2251 2252 LeaveCriticalSection(&This->lock); 2253 return hr; 2254 } 2255 2256 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail) 2257 { 2258 TRACE("%p,%p\n", iface, thumbnail); 2259 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2260 } 2261 2262 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview) 2263 { 2264 TRACE("%p,%p\n", iface, preview); 2265 return WINCODEC_ERR_UNSUPPORTEDOPERATION; 2266 } 2267 2268 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options) 2269 { 2270 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2271 HRESULT hr; 2272 2273 TRACE("%p,%p,%p\n", iface, frame, options); 2274 2275 if (!frame) return E_INVALIDARG; 2276 2277 EnterCriticalSection(&This->lock); 2278 2279 if (This->initialized && !This->committed) 2280 { 2281 GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); 2282 if (ret) 2283 { 2284 This->n_frames++; 2285 2286 ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl; 2287 ret->ref = 1; 2288 ret->encoder = This; 2289 ret->initialized = FALSE; 2290 ret->interlace = FALSE; /* FIXME: read from the properties */ 2291 ret->committed = FALSE; 2292 ret->width = 0; 2293 ret->height = 0; 2294 ret->lines = 0; 2295 ret->xres = 0.0; 2296 ret->yres = 0.0; 2297 ret->colors = 0; 2298 ret->image_data = NULL; 2299 IWICBitmapEncoder_AddRef(iface); 2300 *frame = &ret->IWICBitmapFrameEncode_iface; 2301 2302 hr = S_OK; 2303 2304 if (options) 2305 { 2306 hr = CreatePropertyBag2(NULL, 0, options); 2307 if (hr != S_OK) 2308 { 2309 IWICBitmapFrameEncode_Release(*frame); 2310 *frame = NULL; 2311 } 2312 } 2313 } 2314 else 2315 hr = E_OUTOFMEMORY; 2316 } 2317 else 2318 hr = WINCODEC_ERR_WRONGSTATE; 2319 2320 LeaveCriticalSection(&This->lock); 2321 2322 return hr; 2323 2324 } 2325 2326 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface) 2327 { 2328 GifEncoder *This = impl_from_IWICBitmapEncoder(iface); 2329 HRESULT hr; 2330 2331 TRACE("%p\n", iface); 2332 2333 EnterCriticalSection(&This->lock); 2334 2335 if (This->initialized && !This->committed) 2336 { 2337 char gif_trailer = 0x3b; 2338 2339 /* FIXME: write text, comment GIF extensions */ 2340 2341 hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL); 2342 if (hr == S_OK) 2343 This->committed = TRUE; 2344 } 2345 else 2346 hr = WINCODEC_ERR_WRONGSTATE; 2347 2348 LeaveCriticalSection(&This->lock); 2349 return hr; 2350 } 2351 2352 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer) 2353 { 2354 FIXME("%p,%p: stub\n", iface, writer); 2355 return E_NOTIMPL; 2356 } 2357 2358 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl = 2359 { 2360 GifEncoder_QueryInterface, 2361 GifEncoder_AddRef, 2362 GifEncoder_Release, 2363 GifEncoder_Initialize, 2364 GifEncoder_GetContainerFormat, 2365 GifEncoder_GetEncoderInfo, 2366 GifEncoder_SetColorContexts, 2367 GifEncoder_SetPalette, 2368 GifEncoder_SetThumbnail, 2369 GifEncoder_SetPreview, 2370 GifEncoder_CreateNewFrame, 2371 GifEncoder_Commit, 2372 GifEncoder_GetMetadataQueryWriter 2373 }; 2374 2375 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv) 2376 { 2377 GifEncoder *This; 2378 HRESULT ret; 2379 2380 TRACE("%s,%p\n", debugstr_guid(iid), ppv); 2381 2382 *ppv = NULL; 2383 2384 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); 2385 if (!This) return E_OUTOFMEMORY; 2386 2387 This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl; 2388 This->ref = 1; 2389 This->stream = NULL; 2390 InitializeCriticalSection(&This->lock); 2391 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock"); 2392 This->initialized = FALSE; 2393 This->info_written = FALSE; 2394 This->committed = FALSE; 2395 This->n_frames = 0; 2396 This->colors = 0; 2397 2398 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); 2399 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); 2400 2401 return ret; 2402 } 2403