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