makefiles: Always use the global SOURCES variable for .l files.
[wine.git] / dlls / windowscodecs / gifformat.c
blobadecf1752ee6259c78aca7df0729894abaf8bdbf
1 /*
2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012,2016 Dmitry Timoshkov
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.
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.
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
20 #include <stdarg.h>
22 #define COBJMACROS
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
26 #include "shlwapi.h"
28 #include "ungif.h"
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
36 #include "pshpack1.h"
38 struct logical_screen_descriptor
40 char signature[6];
41 USHORT width;
42 USHORT height;
43 BYTE packed;
44 /* global_color_table_flag : 1;
45 * color_resolution : 3;
46 * sort_flag : 1;
47 * global_color_table_size : 3;
49 BYTE background_color_index;
50 BYTE pixel_aspect_ratio;
53 struct image_descriptor
55 USHORT left;
56 USHORT top;
57 USHORT width;
58 USHORT height;
59 BYTE packed;
60 /* local_color_table_flag : 1;
61 * interlace_flag : 1;
62 * sort_flag : 1;
63 * reserved : 2;
64 * local_color_table_size : 3;
68 #include "poppack.h"
70 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
71 MetadataItem **items, DWORD *count)
73 struct logical_screen_descriptor lsd_data;
74 HRESULT hr;
75 ULONG bytesread, i;
76 MetadataItem *result;
78 *items = NULL;
79 *count = 0;
81 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
82 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
84 result = calloc(9, sizeof(MetadataItem));
85 if (!result) return E_OUTOFMEMORY;
87 for (i = 0; i < 9; i++)
89 PropVariantInit(&result[i].schema);
90 PropVariantInit(&result[i].id);
91 PropVariantInit(&result[i].value);
94 result[0].id.vt = VT_LPWSTR;
95 SHStrDupW(L"Signature", &result[0].id.pwszVal);
96 result[0].value.vt = VT_UI1|VT_VECTOR;
97 result[0].value.caub.cElems = sizeof(lsd_data.signature);
98 result[0].value.caub.pElems = CoTaskMemAlloc(sizeof(lsd_data.signature));
99 memcpy(result[0].value.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
101 result[1].id.vt = VT_LPWSTR;
102 SHStrDupW(L"Width", &result[1].id.pwszVal);
103 result[1].value.vt = VT_UI2;
104 result[1].value.uiVal = lsd_data.width;
106 result[2].id.vt = VT_LPWSTR;
107 SHStrDupW(L"Height", &result[2].id.pwszVal);
108 result[2].value.vt = VT_UI2;
109 result[2].value.uiVal = lsd_data.height;
111 result[3].id.vt = VT_LPWSTR;
112 SHStrDupW(L"GlobalColorTableFlag", &result[3].id.pwszVal);
113 result[3].value.vt = VT_BOOL;
114 result[3].value.boolVal = (lsd_data.packed >> 7) & 1;
116 result[4].id.vt = VT_LPWSTR;
117 SHStrDupW(L"ColorResolution", &result[4].id.pwszVal);
118 result[4].value.vt = VT_UI1;
119 result[4].value.bVal = (lsd_data.packed >> 4) & 7;
121 result[5].id.vt = VT_LPWSTR;
122 SHStrDupW(L"SortFlag", &result[5].id.pwszVal);
123 result[5].value.vt = VT_BOOL;
124 result[5].value.boolVal = (lsd_data.packed >> 3) & 1;
126 result[6].id.vt = VT_LPWSTR;
127 SHStrDupW(L"GlobalColorTableSize", &result[6].id.pwszVal);
128 result[6].value.vt = VT_UI1;
129 result[6].value.bVal = lsd_data.packed & 7;
131 result[7].id.vt = VT_LPWSTR;
132 SHStrDupW(L"BackgroundColorIndex", &result[7].id.pwszVal);
133 result[7].value.vt = VT_UI1;
134 result[7].value.bVal = lsd_data.background_color_index;
136 result[8].id.vt = VT_LPWSTR;
137 SHStrDupW(L"PixelAspectRatio", &result[8].id.pwszVal);
138 result[8].value.vt = VT_UI1;
139 result[8].value.bVal = lsd_data.pixel_aspect_ratio;
141 *items = result;
142 *count = 9;
144 return S_OK;
147 static const MetadataHandlerVtbl LSDReader_Vtbl = {
149 &CLSID_WICLSDMetadataReader,
150 load_LSD_metadata
153 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
155 return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
158 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
159 MetadataItem **items, DWORD *count)
161 struct image_descriptor imd_data;
162 HRESULT hr;
163 ULONG bytesread, i;
164 MetadataItem *result;
166 *items = NULL;
167 *count = 0;
169 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
170 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
172 result = calloc(8, sizeof(MetadataItem));
173 if (!result) return E_OUTOFMEMORY;
175 for (i = 0; i < 8; i++)
177 PropVariantInit(&result[i].schema);
178 PropVariantInit(&result[i].id);
179 PropVariantInit(&result[i].value);
182 result[0].id.vt = VT_LPWSTR;
183 SHStrDupW(L"Left", &result[0].id.pwszVal);
184 result[0].value.vt = VT_UI2;
185 result[0].value.uiVal = imd_data.left;
187 result[1].id.vt = VT_LPWSTR;
188 SHStrDupW(L"Top", &result[1].id.pwszVal);
189 result[1].value.vt = VT_UI2;
190 result[1].value.uiVal = imd_data.top;
192 result[2].id.vt = VT_LPWSTR;
193 SHStrDupW(L"Width", &result[2].id.pwszVal);
194 result[2].value.vt = VT_UI2;
195 result[2].value.uiVal = imd_data.width;
197 result[3].id.vt = VT_LPWSTR;
198 SHStrDupW(L"Height", &result[3].id.pwszVal);
199 result[3].value.vt = VT_UI2;
200 result[3].value.uiVal = imd_data.height;
202 result[4].id.vt = VT_LPWSTR;
203 SHStrDupW(L"LocalColorTableFlag", &result[4].id.pwszVal);
204 result[4].value.vt = VT_BOOL;
205 result[4].value.boolVal = (imd_data.packed >> 7) & 1;
207 result[5].id.vt = VT_LPWSTR;
208 SHStrDupW(L"InterlaceFlag", &result[5].id.pwszVal);
209 result[5].value.vt = VT_BOOL;
210 result[5].value.boolVal = (imd_data.packed >> 6) & 1;
212 result[6].id.vt = VT_LPWSTR;
213 SHStrDupW(L"SortFlag", &result[6].id.pwszVal);
214 result[6].value.vt = VT_BOOL;
215 result[6].value.boolVal = (imd_data.packed >> 5) & 1;
217 result[7].id.vt = VT_LPWSTR;
218 SHStrDupW(L"LocalColorTableSize", &result[7].id.pwszVal);
219 result[7].value.vt = VT_UI1;
220 result[7].value.bVal = imd_data.packed & 7;
222 *items = result;
223 *count = 8;
225 return S_OK;
228 static const MetadataHandlerVtbl IMDReader_Vtbl = {
230 &CLSID_WICIMDMetadataReader,
231 load_IMD_metadata
234 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv)
236 return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv);
239 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
240 MetadataItem **items, DWORD *count)
242 #include "pshpack1.h"
243 struct graphic_control_extension
245 BYTE packed;
246 /* reservred: 3;
247 * disposal : 3;
248 * user_input_flag : 1;
249 * transparency_flag : 1;
251 USHORT delay;
252 BYTE transparent_color_index;
253 } gce_data;
254 #include "poppack.h"
255 HRESULT hr;
256 ULONG bytesread, i;
257 MetadataItem *result;
259 *items = NULL;
260 *count = 0;
262 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
263 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
265 result = calloc(5, sizeof(MetadataItem));
266 if (!result) return E_OUTOFMEMORY;
268 for (i = 0; i < 5; i++)
270 PropVariantInit(&result[i].schema);
271 PropVariantInit(&result[i].id);
272 PropVariantInit(&result[i].value);
275 result[0].id.vt = VT_LPWSTR;
276 SHStrDupW(L"Disposal", &result[0].id.pwszVal);
277 result[0].value.vt = VT_UI1;
278 result[0].value.bVal = (gce_data.packed >> 2) & 7;
280 result[1].id.vt = VT_LPWSTR;
281 SHStrDupW(L"UserInputFlag", &result[1].id.pwszVal);
282 result[1].value.vt = VT_BOOL;
283 result[1].value.boolVal = (gce_data.packed >> 1) & 1;
285 result[2].id.vt = VT_LPWSTR;
286 SHStrDupW(L"TransparencyFlag", &result[2].id.pwszVal);
287 result[2].value.vt = VT_BOOL;
288 result[2].value.boolVal = gce_data.packed & 1;
290 result[3].id.vt = VT_LPWSTR;
291 SHStrDupW(L"Delay", &result[3].id.pwszVal);
292 result[3].value.vt = VT_UI2;
293 result[3].value.uiVal = gce_data.delay;
295 result[4].id.vt = VT_LPWSTR;
296 SHStrDupW(L"TransparentColorIndex", &result[4].id.pwszVal);
297 result[4].value.vt = VT_UI1;
298 result[4].value.bVal = gce_data.transparent_color_index;
300 *items = result;
301 *count = 5;
303 return S_OK;
306 static const MetadataHandlerVtbl GCEReader_Vtbl = {
308 &CLSID_WICGCEMetadataReader,
309 load_GCE_metadata
312 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv)
314 return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv);
317 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
318 MetadataItem **items, DWORD *count)
320 #include "pshpack1.h"
321 struct application_extension
323 BYTE extension_introducer;
324 BYTE extension_label;
325 BYTE block_size;
326 BYTE application[11];
327 } ape_data;
328 #include "poppack.h"
329 HRESULT hr;
330 ULONG bytesread, data_size, i;
331 MetadataItem *result;
332 BYTE subblock_size;
333 BYTE *data;
335 *items = NULL;
336 *count = 0;
338 hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
339 if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
340 if (ape_data.extension_introducer != 0x21 ||
341 ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
342 ape_data.block_size != 11)
343 return S_OK;
345 data = NULL;
346 data_size = 0;
348 for (;;)
350 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
351 if (FAILED(hr) || bytesread != sizeof(subblock_size))
353 CoTaskMemFree(data);
354 return S_OK;
356 if (!subblock_size) break;
358 if (!data)
359 data = CoTaskMemAlloc(subblock_size + 1);
360 else
362 BYTE *new_data = CoTaskMemRealloc(data, data_size + subblock_size + 1);
363 if (!new_data)
365 CoTaskMemFree(data);
366 return S_OK;
368 data = new_data;
370 data[data_size] = subblock_size;
371 hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
372 if (FAILED(hr) || bytesread != subblock_size)
374 CoTaskMemFree(data);
375 return S_OK;
377 data_size += subblock_size + 1;
380 result = calloc(2, sizeof(MetadataItem));
381 if (!result)
383 CoTaskMemFree(data);
384 return E_OUTOFMEMORY;
387 for (i = 0; i < 2; i++)
389 PropVariantInit(&result[i].schema);
390 PropVariantInit(&result[i].id);
391 PropVariantInit(&result[i].value);
394 result[0].id.vt = VT_LPWSTR;
395 SHStrDupW(L"Application", &result[0].id.pwszVal);
396 result[0].value.vt = VT_UI1|VT_VECTOR;
397 result[0].value.caub.cElems = sizeof(ape_data.application);
398 result[0].value.caub.pElems = CoTaskMemAlloc(sizeof(ape_data.application));
399 memcpy(result[0].value.caub.pElems, ape_data.application, sizeof(ape_data.application));
401 result[1].id.vt = VT_LPWSTR;
402 SHStrDupW(L"Data", &result[1].id.pwszVal);
403 result[1].value.vt = VT_UI1|VT_VECTOR;
404 result[1].value.caub.cElems = data_size;
405 result[1].value.caub.pElems = data;
407 *items = result;
408 *count = 2;
410 return S_OK;
413 static const MetadataHandlerVtbl APEReader_Vtbl = {
415 &CLSID_WICAPEMetadataReader,
416 load_APE_metadata
419 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv)
421 return MetadataReader_Create(&APEReader_Vtbl, iid, ppv);
424 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
425 MetadataItem **items, DWORD *count)
427 #include "pshpack1.h"
428 struct gif_extension
430 BYTE extension_introducer;
431 BYTE extension_label;
432 } ext_data;
433 #include "poppack.h"
434 HRESULT hr;
435 ULONG bytesread, data_size;
436 MetadataItem *result;
437 BYTE subblock_size;
438 char *data;
440 *items = NULL;
441 *count = 0;
443 hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
444 if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
445 if (ext_data.extension_introducer != 0x21 ||
446 ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
447 return S_OK;
449 data = NULL;
450 data_size = 0;
452 for (;;)
454 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
455 if (FAILED(hr) || bytesread != sizeof(subblock_size))
457 CoTaskMemFree(data);
458 return S_OK;
460 if (!subblock_size) break;
462 if (!data)
463 data = CoTaskMemAlloc(subblock_size + 1);
464 else
466 char *new_data = CoTaskMemRealloc(data, data_size + subblock_size + 1);
467 if (!new_data)
469 CoTaskMemFree(data);
470 return S_OK;
472 data = new_data;
474 hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
475 if (FAILED(hr) || bytesread != subblock_size)
477 CoTaskMemFree(data);
478 return S_OK;
480 data_size += subblock_size;
483 data[data_size] = 0;
485 result = calloc(1, sizeof(MetadataItem));
486 if (!result)
488 CoTaskMemFree(data);
489 return E_OUTOFMEMORY;
492 PropVariantInit(&result->schema);
493 PropVariantInit(&result->id);
494 PropVariantInit(&result->value);
496 result->id.vt = VT_LPWSTR;
497 SHStrDupW(L"TextEntry", &result->id.pwszVal);
498 result->value.vt = VT_LPSTR;
499 result->value.pszVal = data;
501 *items = result;
502 *count = 1;
504 return S_OK;
507 static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
509 &CLSID_WICGifCommentMetadataReader,
510 load_GifComment_metadata
513 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv)
515 return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv);
518 static IStream *create_stream(const void *data, int data_size)
520 HRESULT hr;
521 IStream *stream;
522 HGLOBAL hdata;
523 void *locked_data;
525 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
526 if (!hdata) return NULL;
528 locked_data = GlobalLock(hdata);
529 memcpy(locked_data, data, data_size);
530 GlobalUnlock(hdata);
532 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
533 return FAILED(hr) ? NULL : stream;
536 static HRESULT create_metadata_reader(const void *data, int data_size,
537 class_constructor constructor,
538 IWICMetadataReader **reader)
540 HRESULT hr;
541 IWICMetadataReader *metadata_reader;
542 IWICPersistStream *persist;
543 IStream *stream;
545 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
547 hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader);
548 if (FAILED(hr)) return hr;
550 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
551 if (FAILED(hr))
553 IWICMetadataReader_Release(metadata_reader);
554 return hr;
557 stream = create_stream(data, data_size);
558 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
559 IStream_Release(stream);
561 IWICPersistStream_Release(persist);
563 *reader = metadata_reader;
564 return S_OK;
567 typedef struct {
568 IWICBitmapDecoder IWICBitmapDecoder_iface;
569 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
570 IStream *stream;
571 BYTE LSD_data[13]; /* Logical Screen Descriptor */
572 LONG ref;
573 BOOL initialized;
574 GifFileType *gif;
575 UINT current_frame;
576 CRITICAL_SECTION lock;
577 } GifDecoder;
579 typedef struct {
580 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
581 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
582 LONG ref;
583 SavedImage *frame;
584 GifDecoder *parent;
585 } GifFrameDecode;
587 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
589 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
592 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
594 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
597 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
599 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
602 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
604 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
607 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
608 void **ppv)
610 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
611 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
613 if (!ppv) return E_INVALIDARG;
615 if (IsEqualIID(&IID_IUnknown, iid) ||
616 IsEqualIID(&IID_IWICBitmapSource, iid) ||
617 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
619 *ppv = &This->IWICBitmapFrameDecode_iface;
621 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
623 *ppv = &This->IWICMetadataBlockReader_iface;
625 else
627 *ppv = NULL;
628 return E_NOINTERFACE;
631 IUnknown_AddRef((IUnknown*)*ppv);
632 return S_OK;
635 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
637 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
638 ULONG ref = InterlockedIncrement(&This->ref);
640 TRACE("(%p) refcount=%lu\n", iface, ref);
642 return ref;
645 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
647 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
648 ULONG ref = InterlockedDecrement(&This->ref);
650 TRACE("(%p) refcount=%lu\n", iface, ref);
652 if (ref == 0)
654 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
655 free(This);
658 return ref;
661 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
662 UINT *puiWidth, UINT *puiHeight)
664 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
665 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
667 *puiWidth = This->frame->ImageDesc.Width;
668 *puiHeight = This->frame->ImageDesc.Height;
670 return S_OK;
673 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
674 WICPixelFormatGUID *pPixelFormat)
676 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
678 return S_OK;
681 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
682 double *pDpiX, double *pDpiY)
684 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
685 const GifWord aspect_word = This->parent->gif->SAspectRatio;
686 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
687 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
689 *pDpiX = 96.0 / aspect;
690 *pDpiY = 96.0;
692 return S_OK;
695 static void copy_palette(ColorMapObject *cm, Extensions *extensions, int count, WICColor *colors)
697 int i;
699 if (cm)
701 for (i = 0; i < count; i++)
703 colors[i] = 0xff000000 | /* alpha */
704 cm->Colors[i].Red << 16 |
705 cm->Colors[i].Green << 8 |
706 cm->Colors[i].Blue;
709 else
711 colors[0] = 0xff000000;
712 colors[1] = 0xffffffff;
713 for (i = 2; i < count; i++)
714 colors[i] = 0xff000000;
717 /* look for the transparent color extension */
718 for (i = 0; i < extensions->ExtensionBlockCount; i++)
720 ExtensionBlock *eb = extensions->ExtensionBlocks + i;
721 if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
722 eb->ByteCount == 8 && eb->Bytes[3] & 1)
724 int trans = (unsigned char)eb->Bytes[6];
725 colors[trans] &= 0xffffff; /* set alpha to 0 */
726 break;
731 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
732 IWICPalette *pIPalette)
734 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
735 WICColor colors[256];
736 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
737 int count;
739 TRACE("(%p,%p)\n", iface, pIPalette);
741 if (cm)
742 count = cm->ColorCount;
743 else
745 cm = This->parent->gif->SColorMap;
746 count = This->parent->gif->SColorTableSize;
749 if (count > 256)
751 ERR("GIF contains %i colors???\n", count);
752 return E_FAIL;
755 copy_palette(cm, &This->frame->Extensions, count, colors);
757 return IWICPalette_InitializeCustom(pIPalette, colors, count);
760 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
761 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
762 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
764 UINT row_offset; /* number of bytes into the source rows where the data starts */
765 const BYTE *src;
766 BYTE *dst;
767 UINT y;
768 WICRect rect;
770 if (!rc)
772 rect.X = 0;
773 rect.Y = 0;
774 rect.Width = srcwidth;
775 rect.Height = srcheight;
776 rc = &rect;
778 else
780 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
781 return E_INVALIDARG;
784 if (dststride < rc->Width)
785 return E_INVALIDARG;
787 if ((dststride * rc->Height) > dstbuffersize)
788 return E_INVALIDARG;
790 row_offset = rc->X;
792 dst = dstbuffer;
793 for (y=rc->Y; y-rc->Y < rc->Height; y++)
795 if (y%8 == 0)
796 src = srcbuffer + srcstride * (y/8);
797 else if (y%4 == 0)
798 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
799 else if (y%2 == 0)
800 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
801 else /* y%2 == 1 */
802 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
803 src += row_offset;
804 memcpy(dst, src, rc->Width);
805 dst += dststride;
807 return S_OK;
810 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
811 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
813 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
814 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
816 if (This->frame->ImageDesc.Interlace)
818 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
819 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
820 prc, cbStride, cbBufferSize, pbBuffer);
822 else
824 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
825 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
826 prc, cbStride, cbBufferSize, pbBuffer);
830 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
831 IWICMetadataQueryReader **ppIMetadataQueryReader)
833 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
835 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
837 if (!ppIMetadataQueryReader)
838 return E_INVALIDARG;
840 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
843 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
844 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
846 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
847 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
850 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
851 IWICBitmapSource **ppIThumbnail)
853 TRACE("(%p,%p)\n", iface, ppIThumbnail);
854 return WINCODEC_ERR_CODECNOTHUMBNAIL;
857 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
858 GifFrameDecode_QueryInterface,
859 GifFrameDecode_AddRef,
860 GifFrameDecode_Release,
861 GifFrameDecode_GetSize,
862 GifFrameDecode_GetPixelFormat,
863 GifFrameDecode_GetResolution,
864 GifFrameDecode_CopyPalette,
865 GifFrameDecode_CopyPixels,
866 GifFrameDecode_GetMetadataQueryReader,
867 GifFrameDecode_GetColorContexts,
868 GifFrameDecode_GetThumbnail
871 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
872 REFIID iid, void **ppv)
874 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
875 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
878 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
880 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
881 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
884 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
886 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
887 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
890 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
891 GUID *guid)
893 TRACE("(%p,%p)\n", iface, guid);
895 if (!guid) return E_INVALIDARG;
897 *guid = GUID_ContainerFormatGif;
898 return S_OK;
901 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
902 UINT *count)
904 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
906 TRACE("%p,%p\n", iface, count);
908 if (!count) return E_INVALIDARG;
910 *count = This->frame->Extensions.ExtensionBlockCount + 1;
911 return S_OK;
914 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
916 HRESULT hr;
917 IWICMetadataReader *metadata_reader;
918 IWICPersistStream *persist;
919 IStream *stream;
920 struct image_descriptor IMD_data;
922 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
924 hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader);
925 if (FAILED(hr)) return hr;
927 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
928 if (FAILED(hr))
930 IWICMetadataReader_Release(metadata_reader);
931 return hr;
934 /* recreate IMD structure from GIF decoder data */
935 IMD_data.left = This->frame->ImageDesc.Left;
936 IMD_data.top = This->frame->ImageDesc.Top;
937 IMD_data.width = This->frame->ImageDesc.Width;
938 IMD_data.height = This->frame->ImageDesc.Height;
939 IMD_data.packed = 0;
940 /* interlace_flag */
941 IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0;
942 if (This->frame->ImageDesc.ColorMap)
944 /* local_color_table_flag */
945 IMD_data.packed |= 1 << 7;
946 /* local_color_table_size */
947 IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1;
948 /* sort_flag */
949 IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
952 stream = create_stream(&IMD_data, sizeof(IMD_data));
953 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
954 IStream_Release(stream);
956 IWICPersistStream_Release(persist);
958 *reader = metadata_reader;
959 return S_OK;
962 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
963 UINT index, IWICMetadataReader **reader)
965 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
966 class_constructor constructor;
967 ExtensionBlock *ext;
968 const void *data;
969 int data_size;
971 TRACE("(%p,%u,%p)\n", iface, index, reader);
973 if (!reader) return E_INVALIDARG;
975 if (index == 0)
976 return create_IMD_metadata_reader(This, reader);
978 if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
979 return E_INVALIDARG;
981 ext = This->frame->Extensions.ExtensionBlocks + index - 1;
982 if (ext->Function == GRAPHICS_EXT_FUNC_CODE)
984 constructor = GCEReader_CreateInstance;
985 data = ext->Bytes + 3;
986 data_size = ext->ByteCount - 4;
988 else if (ext->Function == COMMENT_EXT_FUNC_CODE)
990 constructor = GifCommentReader_CreateInstance;
991 data = ext->Bytes;
992 data_size = ext->ByteCount;
994 else
996 constructor = UnknownMetadataReader_CreateInstance;
997 data = ext->Bytes;
998 data_size = ext->ByteCount;
1001 return create_metadata_reader(data, data_size, constructor, reader);
1004 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1005 IEnumUnknown **enumerator)
1007 FIXME("(%p,%p): stub\n", iface, enumerator);
1008 return E_NOTIMPL;
1011 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl =
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
1022 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1023 void **ppv)
1025 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1026 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1028 if (!ppv) return E_INVALIDARG;
1030 if (IsEqualIID(&IID_IUnknown, iid) ||
1031 IsEqualIID(&IID_IWICBitmapDecoder, iid))
1033 *ppv = &This->IWICBitmapDecoder_iface;
1035 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
1037 *ppv = &This->IWICMetadataBlockReader_iface;
1039 else
1041 *ppv = NULL;
1042 return E_NOINTERFACE;
1045 IUnknown_AddRef((IUnknown*)*ppv);
1046 return S_OK;
1049 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
1051 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1052 ULONG ref = InterlockedIncrement(&This->ref);
1054 TRACE("(%p) refcount=%lu\n", iface, ref);
1056 return ref;
1059 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
1061 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1062 ULONG ref = InterlockedDecrement(&This->ref);
1064 TRACE("(%p) refcount=%lu\n", iface, ref);
1066 if (ref == 0)
1068 if (This->stream)
1070 IStream_Release(This->stream);
1071 DGifCloseFile(This->gif);
1073 This->lock.DebugInfo->Spare[0] = 0;
1074 DeleteCriticalSection(&This->lock);
1075 free(This);
1078 return ref;
1081 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1082 DWORD *capability)
1084 HRESULT hr;
1086 TRACE("(%p,%p,%p)\n", iface, stream, capability);
1088 if (!stream || !capability) return E_INVALIDARG;
1090 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1091 if (hr != S_OK) return hr;
1093 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
1094 WICBitmapDecoderCapabilityCanDecodeSomeImages |
1095 WICBitmapDecoderCapabilityCanEnumerateMetadata;
1096 return S_OK;
1099 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1100 IStream *stream = gif->UserData;
1101 ULONG bytesread;
1102 HRESULT hr;
1104 if (!stream)
1106 ERR("attempting to read file after initialization\n");
1107 return 0;
1110 hr = IStream_Read(stream, data, len, &bytesread);
1111 if (FAILED(hr)) bytesread = 0;
1112 return bytesread;
1115 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1116 WICDecodeOptions cacheOptions)
1118 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1119 LARGE_INTEGER seek;
1120 int ret;
1122 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1124 EnterCriticalSection(&This->lock);
1126 if (This->initialized || This->gif)
1128 WARN("already initialized\n");
1129 LeaveCriticalSection(&This->lock);
1130 return WINCODEC_ERR_WRONGSTATE;
1133 /* seek to start of stream */
1134 seek.QuadPart = 0;
1135 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1137 /* read all data from the stream */
1138 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1139 if (!This->gif)
1141 LeaveCriticalSection(&This->lock);
1142 return E_FAIL;
1145 ret = DGifSlurp(This->gif);
1146 if (ret == GIF_ERROR)
1148 LeaveCriticalSection(&This->lock);
1149 return E_FAIL;
1152 /* make sure we don't use the stream after this method returns */
1153 This->gif->UserData = NULL;
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);
1159 This->stream = pIStream;
1160 IStream_AddRef(This->stream);
1162 This->initialized = TRUE;
1164 LeaveCriticalSection(&This->lock);
1166 return S_OK;
1169 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1170 GUID *pguidContainerFormat)
1172 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1173 return S_OK;
1176 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1177 IWICBitmapDecoderInfo **ppIDecoderInfo)
1179 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1181 return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo);
1184 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1186 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1187 WICColor colors[256];
1188 ColorMapObject *cm;
1189 int count;
1191 TRACE("(%p,%p)\n", iface, palette);
1193 if (!This->gif)
1194 return WINCODEC_ERR_WRONGSTATE;
1196 cm = This->gif->SColorMap;
1197 count = This->gif->SColorTableSize;
1199 if (count > 256)
1201 ERR("GIF contains invalid number of colors: %d\n", count);
1202 return E_FAIL;
1205 copy_palette(cm, &This->gif->SavedImages[This->current_frame].Extensions, count, colors);
1207 return IWICPalette_InitializeCustom(palette, colors, count);
1210 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1211 IWICMetadataQueryReader **ppIMetadataQueryReader)
1213 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1215 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1217 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1219 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1222 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1223 IWICBitmapSource **ppIBitmapSource)
1225 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1226 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1229 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1230 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1232 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1233 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1236 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1237 IWICBitmapSource **ppIThumbnail)
1239 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1240 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1243 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1244 UINT *pCount)
1246 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1248 if (!pCount) return E_INVALIDARG;
1250 EnterCriticalSection(&This->lock);
1251 *pCount = This->gif ? This->gif->ImageCount : 0;
1252 LeaveCriticalSection(&This->lock);
1254 TRACE("(%p) <-- %d\n", iface, *pCount);
1256 return S_OK;
1259 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1260 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1262 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1263 GifFrameDecode *result;
1264 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1266 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1268 if (index >= This->gif->ImageCount) return E_INVALIDARG;
1270 result = malloc(sizeof(GifFrameDecode));
1271 if (!result) return E_OUTOFMEMORY;
1273 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1274 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1275 result->ref = 1;
1276 result->frame = &This->gif->SavedImages[index];
1277 IWICBitmapDecoder_AddRef(iface);
1278 result->parent = This;
1279 This->current_frame = index;
1281 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1283 return S_OK;
1286 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1287 GifDecoder_QueryInterface,
1288 GifDecoder_AddRef,
1289 GifDecoder_Release,
1290 GifDecoder_QueryCapability,
1291 GifDecoder_Initialize,
1292 GifDecoder_GetContainerFormat,
1293 GifDecoder_GetDecoderInfo,
1294 GifDecoder_CopyPalette,
1295 GifDecoder_GetMetadataQueryReader,
1296 GifDecoder_GetPreview,
1297 GifDecoder_GetColorContexts,
1298 GifDecoder_GetThumbnail,
1299 GifDecoder_GetFrameCount,
1300 GifDecoder_GetFrame
1303 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1304 REFIID iid, void **ppv)
1306 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1307 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1310 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1312 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1313 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1316 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1318 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1319 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1322 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1323 GUID *guid)
1325 TRACE("(%p,%p)\n", iface, guid);
1327 if (!guid) return E_INVALIDARG;
1329 *guid = GUID_ContainerFormatGif;
1330 return S_OK;
1333 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1334 UINT *count)
1336 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1338 TRACE("%p,%p\n", iface, count);
1340 if (!count) return E_INVALIDARG;
1342 *count = This->gif->Extensions.ExtensionBlockCount + 1;
1343 return S_OK;
1346 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1347 UINT index, IWICMetadataReader **reader)
1349 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1350 int i;
1352 TRACE("(%p,%u,%p)\n", iface, index, reader);
1354 if (!reader) return E_INVALIDARG;
1356 if (index == 0)
1357 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1358 LSDReader_CreateInstance, reader);
1360 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1362 class_constructor constructor;
1364 if (index != i + 1) continue;
1366 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1367 constructor = APEReader_CreateInstance;
1368 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1369 constructor = GifCommentReader_CreateInstance;
1370 else
1371 constructor = UnknownMetadataReader_CreateInstance;
1373 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1374 This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1375 constructor, reader);
1378 return E_INVALIDARG;
1381 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1382 IEnumUnknown **enumerator)
1384 FIXME("(%p,%p): stub\n", iface, enumerator);
1385 return E_NOTIMPL;
1388 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1390 GifDecoder_Block_QueryInterface,
1391 GifDecoder_Block_AddRef,
1392 GifDecoder_Block_Release,
1393 GifDecoder_Block_GetContainerFormat,
1394 GifDecoder_Block_GetCount,
1395 GifDecoder_Block_GetReaderByIndex,
1396 GifDecoder_Block_GetEnumerator
1399 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
1401 GifDecoder *This;
1402 HRESULT ret;
1404 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1406 *ppv = NULL;
1408 This = malloc(sizeof(GifDecoder));
1409 if (!This) return E_OUTOFMEMORY;
1411 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1412 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1413 This->stream = NULL;
1414 This->ref = 1;
1415 This->initialized = FALSE;
1416 This->gif = NULL;
1417 This->current_frame = 0;
1418 InitializeCriticalSection(&This->lock);
1419 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1421 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1422 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1424 return ret;
1427 typedef struct GifEncoder
1429 IWICBitmapEncoder IWICBitmapEncoder_iface;
1430 LONG ref;
1431 IStream *stream;
1432 CRITICAL_SECTION lock;
1433 BOOL initialized, info_written, committed;
1434 UINT n_frames;
1435 WICColor palette[256];
1436 UINT colors;
1437 } GifEncoder;
1439 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1441 return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
1444 typedef struct GifFrameEncode
1446 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1447 IWICMetadataBlockWriter IWICMetadataBlockWriter_iface;
1448 LONG ref;
1449 GifEncoder *encoder;
1450 BOOL initialized, interlace, committed;
1451 UINT width, height, lines;
1452 double xres, yres;
1453 WICColor palette[256];
1454 UINT colors;
1455 BYTE *image_data;
1456 } GifFrameEncode;
1458 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1460 return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
1463 static inline GifFrameEncode *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface)
1465 return CONTAINING_RECORD(iface, GifFrameEncode, IWICMetadataBlockWriter_iface);
1468 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1470 GifFrameEncode *encoder = impl_from_IWICBitmapFrameEncode(iface);
1472 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
1474 if (!ppv) return E_INVALIDARG;
1476 if (IsEqualIID(&IID_IUnknown, iid) ||
1477 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1479 *ppv = iface;
1481 else if (IsEqualIID(&IID_IWICMetadataBlockWriter, iid))
1483 *ppv = &encoder->IWICMetadataBlockWriter_iface;
1485 else
1487 *ppv = NULL;
1488 return E_NOINTERFACE;
1491 IUnknown_AddRef((IUnknown *)*ppv);
1492 return S_OK;
1495 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1497 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1498 ULONG ref = InterlockedIncrement(&This->ref);
1500 TRACE("%p -> %lu\n", iface, ref);
1501 return ref;
1504 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
1506 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1507 ULONG ref = InterlockedDecrement(&This->ref);
1509 TRACE("%p -> %lu\n", iface, ref);
1511 if (!ref)
1513 IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
1514 free(This->image_data);
1515 free(This);
1518 return ref;
1521 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
1523 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1524 HRESULT hr;
1526 TRACE("%p,%p\n", iface, options);
1528 EnterCriticalSection(&This->encoder->lock);
1530 if (!This->initialized)
1532 This->initialized = TRUE;
1533 hr = S_OK;
1535 else
1536 hr = WINCODEC_ERR_WRONGSTATE;
1538 LeaveCriticalSection(&This->encoder->lock);
1540 return hr;
1543 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
1545 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1546 HRESULT hr;
1548 TRACE("%p,%u,%u\n", iface, width, height);
1550 if (!width || !height) return E_INVALIDARG;
1552 EnterCriticalSection(&This->encoder->lock);
1554 if (This->initialized)
1556 free(This->image_data);
1558 This->image_data = malloc(width * height);
1559 if (This->image_data)
1561 This->width = width;
1562 This->height = height;
1563 hr = S_OK;
1565 else
1566 hr = E_OUTOFMEMORY;
1568 else
1569 hr = WINCODEC_ERR_WRONGSTATE;
1571 LeaveCriticalSection(&This->encoder->lock);
1573 return hr;
1576 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
1578 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1579 HRESULT hr;
1581 TRACE("%p,%f,%f\n", iface, xres, yres);
1583 EnterCriticalSection(&This->encoder->lock);
1585 if (This->initialized)
1587 This->xres = xres;
1588 This->yres = yres;
1589 hr = S_OK;
1591 else
1592 hr = WINCODEC_ERR_WRONGSTATE;
1594 LeaveCriticalSection(&This->encoder->lock);
1596 return hr;
1599 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
1601 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1602 HRESULT hr;
1604 TRACE("%p,%s\n", iface, debugstr_guid(format));
1606 if (!format) return E_INVALIDARG;
1608 EnterCriticalSection(&This->encoder->lock);
1610 if (This->initialized)
1612 *format = GUID_WICPixelFormat8bppIndexed;
1613 hr = S_OK;
1615 else
1616 hr = WINCODEC_ERR_WRONGSTATE;
1618 LeaveCriticalSection(&This->encoder->lock);
1620 return hr;
1623 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
1625 FIXME("%p,%u,%p: stub\n", iface, count, context);
1626 return E_NOTIMPL;
1629 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
1631 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1632 HRESULT hr;
1634 TRACE("%p,%p\n", iface, palette);
1636 if (!palette) return E_INVALIDARG;
1638 EnterCriticalSection(&This->encoder->lock);
1640 if (This->initialized)
1641 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1642 else
1643 hr = WINCODEC_ERR_NOTINITIALIZED;
1645 LeaveCriticalSection(&This->encoder->lock);
1646 return hr;
1649 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
1651 FIXME("%p,%p: stub\n", iface, thumbnail);
1652 return E_NOTIMPL;
1655 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
1657 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1658 HRESULT hr;
1660 TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
1662 if (!pixels) return E_INVALIDARG;
1664 EnterCriticalSection(&This->encoder->lock);
1666 if (This->initialized && This->image_data)
1668 if (This->lines + lines <= This->height)
1670 UINT i;
1671 BYTE *src, *dst;
1673 src = pixels;
1674 dst = This->image_data + This->lines * This->width;
1676 for (i = 0; i < lines; i++)
1678 memcpy(dst, src, This->width);
1679 src += stride;
1680 dst += This->width;
1683 This->lines += lines;
1684 hr = S_OK;
1686 else
1687 hr = E_INVALIDARG;
1689 else
1690 hr = WINCODEC_ERR_WRONGSTATE;
1692 LeaveCriticalSection(&This->encoder->lock);
1693 return hr;
1696 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
1698 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1699 HRESULT hr;
1701 TRACE("%p,%p,%p\n", iface, source, rc);
1703 if (!source) return E_INVALIDARG;
1705 EnterCriticalSection(&This->encoder->lock);
1707 if (This->initialized)
1709 const GUID *format = &GUID_WICPixelFormat8bppIndexed;
1711 hr = configure_write_source(iface, source, rc, format,
1712 This->width, This->height, This->xres, This->yres);
1713 if (hr == S_OK)
1714 hr = write_source(iface, source, rc, format, 8, !This->colors, This->width, This->height);
1716 else
1717 hr = WINCODEC_ERR_WRONGSTATE;
1719 LeaveCriticalSection(&This->encoder->lock);
1720 return hr;
1723 #define LZW_DICT_SIZE (1 << 12)
1725 struct lzw_dict
1727 short prefix[LZW_DICT_SIZE];
1728 unsigned char suffix[LZW_DICT_SIZE];
1731 struct lzw_state
1733 struct lzw_dict dict;
1734 short init_code_bits, code_bits, next_code, clear_code, eof_code;
1735 unsigned bits_buf;
1736 int bits_count;
1737 int (*user_write_data)(void *user_ptr, void *data, int length);
1738 void *user_ptr;
1741 struct input_stream
1743 unsigned len;
1744 const BYTE *in;
1747 struct output_stream
1749 struct
1751 unsigned char len;
1752 char data[255];
1753 } gif_block;
1754 IStream *out;
1757 static int lzw_output_code(struct lzw_state *state, short code)
1759 state->bits_buf |= code << state->bits_count;
1760 state->bits_count += state->code_bits;
1762 while (state->bits_count >= 8)
1764 unsigned char byte = (unsigned char)state->bits_buf;
1765 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1766 return 0;
1767 state->bits_buf >>= 8;
1768 state->bits_count -= 8;
1771 return 1;
1774 static inline int lzw_output_clear_code(struct lzw_state *state)
1776 return lzw_output_code(state, state->clear_code);
1779 static inline int lzw_output_eof_code(struct lzw_state *state)
1781 return lzw_output_code(state, state->eof_code);
1784 static int lzw_flush_bits(struct lzw_state *state)
1786 unsigned char byte;
1788 while (state->bits_count >= 8)
1790 byte = (unsigned char)state->bits_buf;
1791 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1792 return 0;
1793 state->bits_buf >>= 8;
1794 state->bits_count -= 8;
1797 if (state->bits_count)
1799 static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1801 byte = (unsigned char)state->bits_buf & mask[state->bits_count];
1802 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1803 return 0;
1806 state->bits_buf = 0;
1807 state->bits_count = 0;
1809 return 1;
1812 static void lzw_dict_reset(struct lzw_state *state)
1814 int i;
1816 state->code_bits = state->init_code_bits + 1;
1817 state->next_code = (1 << state->init_code_bits) + 2;
1819 for(i = 0; i < LZW_DICT_SIZE; i++)
1821 state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
1822 state->dict.suffix[i] = 0;
1826 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
1828 state->init_code_bits = init_code_bits;
1829 state->clear_code = 1 << init_code_bits;
1830 state->eof_code = state->clear_code + 1;
1831 state->bits_buf = 0;
1832 state->bits_count = 0;
1833 state->user_write_data = user_write_data;
1834 state->user_ptr = user_ptr;
1836 lzw_dict_reset(state);
1839 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
1841 if (state->next_code < LZW_DICT_SIZE)
1843 state->dict.prefix[state->next_code] = prefix;
1844 state->dict.suffix[state->next_code] = suffix;
1846 if ((state->next_code & (state->next_code - 1)) == 0)
1847 state->code_bits++;
1849 state->next_code++;
1850 return state->next_code;
1853 return -1;
1856 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
1858 short i;
1860 for (i = 0; i < state->next_code; i++)
1862 if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
1863 return i;
1866 return -1;
1869 static inline int write_byte(struct output_stream *out, char byte)
1871 if (out->gif_block.len == 255)
1873 if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
1874 return 0;
1876 out->gif_block.len = 0;
1879 out->gif_block.data[out->gif_block.len++] = byte;
1881 return 1;
1884 static int write_data(void *user_ptr, void *user_data, int length)
1886 unsigned char *data = user_data;
1887 struct output_stream *out = user_ptr;
1888 int len = length;
1890 while (len-- > 0)
1892 if (!write_byte(out, *data++)) return 0;
1895 return length;
1898 static int flush_output_data(void *user_ptr)
1900 struct output_stream *out = user_ptr;
1902 if (out->gif_block.len)
1904 if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
1905 return 0;
1908 /* write GIF block terminator */
1909 out->gif_block.len = 0;
1910 return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
1913 static inline int read_byte(struct input_stream *in, unsigned char *byte)
1915 if (in->len)
1917 in->len--;
1918 *byte = *in->in++;
1919 return 1;
1922 return 0;
1925 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
1927 struct input_stream in;
1928 struct output_stream out;
1929 struct lzw_state state;
1930 short init_code_bits, prefix, code;
1931 unsigned char suffix;
1933 in.in = in_data;
1934 in.len = in_size;
1936 out.gif_block.len = 0;
1937 out.out = out_stream;
1939 init_code_bits = suffix = 8;
1940 if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
1941 return E_FAIL;
1943 lzw_state_init(&state, init_code_bits, write_data, &out);
1945 if (!lzw_output_clear_code(&state))
1946 return E_FAIL;
1948 if (read_byte(&in, &suffix))
1950 prefix = suffix;
1952 while (read_byte(&in, &suffix))
1954 code = lzw_dict_lookup(&state, prefix, suffix);
1955 if (code == -1)
1957 if (!lzw_output_code(&state, prefix))
1958 return E_FAIL;
1960 if (lzw_dict_add(&state, prefix, suffix) == -1)
1962 if (!lzw_output_clear_code(&state))
1963 return E_FAIL;
1964 lzw_dict_reset(&state);
1967 prefix = suffix;
1969 else
1970 prefix = code;
1973 if (!lzw_output_code(&state, prefix))
1974 return E_FAIL;
1975 if (!lzw_output_eof_code(&state))
1976 return E_FAIL;
1977 if (!lzw_flush_bits(&state))
1978 return E_FAIL;
1981 return flush_output_data(&out) ? S_OK : E_FAIL;
1984 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1986 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1987 HRESULT hr;
1989 TRACE("%p\n", iface);
1991 EnterCriticalSection(&This->encoder->lock);
1993 if (This->image_data && This->lines == This->height && !This->committed)
1995 BYTE gif_palette[256][3];
1997 hr = S_OK;
1999 if (!This->encoder->info_written)
2001 struct logical_screen_descriptor lsd;
2003 /* Logical Screen Descriptor */
2004 memcpy(lsd.signature, "GIF89a", 6);
2005 lsd.width = This->width;
2006 lsd.height = This->height;
2007 lsd.packed = 0;
2008 if (This->encoder->colors)
2009 lsd.packed |= 0x80; /* global color table flag */
2010 lsd.packed |= 0x07 << 4; /* color resolution */
2011 lsd.packed |= 0x07; /* global color table size */
2012 lsd.background_color_index = 0; /* FIXME */
2013 lsd.pixel_aspect_ratio = 0;
2014 hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
2015 if (hr == S_OK && This->encoder->colors)
2017 UINT i;
2019 /* Global Color Table */
2020 memset(gif_palette, 0, sizeof(gif_palette));
2021 for (i = 0; i < This->encoder->colors; i++)
2023 gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
2024 gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
2025 gif_palette[i][2] = This->encoder->palette[i] & 0xff;
2027 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2030 /* FIXME: write GCE, APE, etc. GIF extensions */
2032 if (hr == S_OK)
2033 This->encoder->info_written = TRUE;
2036 if (hr == S_OK)
2038 char image_separator = 0x2c;
2040 hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
2041 if (hr == S_OK)
2043 struct image_descriptor imd;
2045 /* Image Descriptor */
2046 imd.left = 0;
2047 imd.top = 0;
2048 imd.width = This->width;
2049 imd.height = This->height;
2050 imd.packed = 0;
2051 if (This->colors)
2053 imd.packed |= 0x80; /* local color table flag */
2054 imd.packed |= 0x07; /* local color table size */
2056 /* FIXME: interlace flag */
2057 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
2058 if (hr == S_OK && This->colors)
2060 UINT i;
2062 /* Local Color Table */
2063 memset(gif_palette, 0, sizeof(gif_palette));
2064 for (i = 0; i < This->colors; i++)
2066 gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
2067 gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
2068 gif_palette[i][2] = This->palette[i] & 0xff;
2070 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2071 if (hr == S_OK)
2073 /* Image Data */
2074 hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
2075 if (hr == S_OK)
2076 This->committed = TRUE;
2082 else
2083 hr = WINCODEC_ERR_WRONGSTATE;
2085 LeaveCriticalSection(&This->encoder->lock);
2086 return hr;
2089 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
2091 GifFrameEncode *encode = impl_from_IWICBitmapFrameEncode(iface);
2093 TRACE("iface, %p, writer %p.\n", iface, writer);
2095 if (!writer)
2096 return E_INVALIDARG;
2098 if (!encode->initialized)
2099 return WINCODEC_ERR_NOTINITIALIZED;
2101 return MetadataQueryWriter_CreateInstance(&encode->IWICMetadataBlockWriter_iface, NULL, writer);
2104 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
2106 GifFrameEncode_QueryInterface,
2107 GifFrameEncode_AddRef,
2108 GifFrameEncode_Release,
2109 GifFrameEncode_Initialize,
2110 GifFrameEncode_SetSize,
2111 GifFrameEncode_SetResolution,
2112 GifFrameEncode_SetPixelFormat,
2113 GifFrameEncode_SetColorContexts,
2114 GifFrameEncode_SetPalette,
2115 GifFrameEncode_SetThumbnail,
2116 GifFrameEncode_WritePixels,
2117 GifFrameEncode_WriteSource,
2118 GifFrameEncode_Commit,
2119 GifFrameEncode_GetMetadataQueryWriter
2122 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
2124 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
2126 if (!ppv) return E_INVALIDARG;
2128 if (IsEqualIID(&IID_IUnknown, iid) ||
2129 IsEqualIID(&IID_IWICBitmapEncoder, iid))
2131 IWICBitmapEncoder_AddRef(iface);
2132 *ppv = iface;
2133 return S_OK;
2136 *ppv = NULL;
2137 return E_NOINTERFACE;
2140 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
2142 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2143 ULONG ref = InterlockedIncrement(&This->ref);
2145 TRACE("%p -> %lu\n", iface, ref);
2146 return ref;
2149 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
2151 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2152 ULONG ref = InterlockedDecrement(&This->ref);
2154 TRACE("%p -> %lu\n", iface, ref);
2156 if (!ref)
2158 if (This->stream) IStream_Release(This->stream);
2159 This->lock.DebugInfo->Spare[0] = 0;
2160 DeleteCriticalSection(&This->lock);
2161 free(This);
2164 return ref;
2167 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
2169 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2170 HRESULT hr;
2172 TRACE("%p,%p,%#x\n", iface, stream, option);
2174 if (!stream) return E_INVALIDARG;
2176 EnterCriticalSection(&This->lock);
2178 if (!This->initialized)
2180 IStream_AddRef(stream);
2181 This->stream = stream;
2182 This->initialized = TRUE;
2183 hr = S_OK;
2185 else
2186 hr = WINCODEC_ERR_WRONGSTATE;
2188 LeaveCriticalSection(&This->lock);
2190 return hr;
2193 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
2195 if (!format) return E_INVALIDARG;
2197 *format = GUID_ContainerFormatGif;
2198 return S_OK;
2201 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
2203 IWICComponentInfo *comp_info;
2204 HRESULT hr;
2206 TRACE("%p,%p\n", iface, info);
2208 if (!info) return E_INVALIDARG;
2210 hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
2211 if (hr == S_OK)
2213 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2214 IWICComponentInfo_Release(comp_info);
2216 return hr;
2219 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
2221 FIXME("%p,%u,%p: stub\n", iface, count, context);
2222 return E_NOTIMPL;
2225 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2227 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2228 HRESULT hr;
2230 TRACE("%p,%p\n", iface, palette);
2232 if (!palette) return E_INVALIDARG;
2234 EnterCriticalSection(&This->lock);
2236 if (This->initialized)
2237 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
2238 else
2239 hr = WINCODEC_ERR_NOTINITIALIZED;
2241 LeaveCriticalSection(&This->lock);
2242 return hr;
2245 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
2247 TRACE("%p,%p\n", iface, thumbnail);
2248 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2251 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
2253 TRACE("%p,%p\n", iface, preview);
2254 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2257 static HRESULT WINAPI GifEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **ppv)
2259 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2261 return IWICBitmapFrameEncode_QueryInterface(&frame_encoder->IWICBitmapFrameEncode_iface, iid, ppv);
2264 static ULONG WINAPI GifEncoderFrame_Block_AddRef(IWICMetadataBlockWriter *iface)
2266 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2268 return IWICBitmapFrameEncode_AddRef(&frame_encoder->IWICBitmapFrameEncode_iface);
2271 static ULONG WINAPI GifEncoderFrame_Block_Release(IWICMetadataBlockWriter *iface)
2273 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2275 return IWICBitmapFrameEncode_Release(&frame_encoder->IWICBitmapFrameEncode_iface);
2278 static HRESULT WINAPI GifEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter *iface, GUID *container_format)
2280 FIXME("iface %p, container_format %p stub.\n", iface, container_format);
2282 return E_NOTIMPL;
2285 static HRESULT WINAPI GifEncoderFrame_Block_GetCount(IWICMetadataBlockWriter *iface, UINT *count)
2287 FIXME("iface %p, count %p stub.\n", iface, count);
2289 return E_NOTIMPL;
2292 static HRESULT WINAPI GifEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter *iface,
2293 UINT index, IWICMetadataReader **metadata_reader)
2295 FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface, index, metadata_reader);
2297 return E_NOTIMPL;
2300 static HRESULT WINAPI GifEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enum_metadata)
2302 FIXME("iface %p, enum_metadata %p stub.\n", iface, enum_metadata);
2304 return E_NOTIMPL;
2307 static HRESULT WINAPI GifEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter *iface,
2308 IWICMetadataBlockReader *block_reader)
2310 FIXME("iface %p, block_reader %p stub.\n", iface, block_reader);
2312 return E_NOTIMPL;
2315 static HRESULT WINAPI GifEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
2316 IWICMetadataWriter **metadata_writer)
2318 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
2320 return E_NOTIMPL;
2323 static HRESULT WINAPI GifEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter *iface, IWICMetadataWriter *metadata_writer)
2325 FIXME("iface %p, metadata_writer %p stub.\n", iface, metadata_writer);
2327 return E_NOTIMPL;
2330 static HRESULT WINAPI GifEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
2331 IWICMetadataWriter *metadata_writer)
2333 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
2335 return E_NOTIMPL;
2338 static HRESULT WINAPI GifEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter *iface, UINT index)
2340 FIXME("iface %p, index %u stub.\n", iface, index);
2342 return E_NOTIMPL;
2345 static const IWICMetadataBlockWriterVtbl GifFrameEncode_BlockVtbl = {
2346 GifEncoderFrame_Block_QueryInterface,
2347 GifEncoderFrame_Block_AddRef,
2348 GifEncoderFrame_Block_Release,
2349 GifEncoderFrame_Block_GetContainerFormat,
2350 GifEncoderFrame_Block_GetCount,
2351 GifEncoderFrame_Block_GetReaderByIndex,
2352 GifEncoderFrame_Block_GetEnumerator,
2353 GifEncoderFrame_Block_InitializeFromBlockReader,
2354 GifEncoderFrame_Block_GetWriterByIndex,
2355 GifEncoderFrame_Block_AddWriter,
2356 GifEncoderFrame_Block_SetWriterByIndex,
2357 GifEncoderFrame_Block_RemoveWriterByIndex,
2360 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
2362 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2363 HRESULT hr;
2365 TRACE("%p,%p,%p\n", iface, frame, options);
2367 if (!frame) return E_INVALIDARG;
2369 EnterCriticalSection(&This->lock);
2371 if (This->initialized && !This->committed)
2373 GifFrameEncode *ret = malloc(sizeof(*ret));
2374 if (ret)
2376 This->n_frames++;
2378 ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
2379 ret->IWICMetadataBlockWriter_iface.lpVtbl = &GifFrameEncode_BlockVtbl;
2381 ret->ref = 1;
2382 ret->encoder = This;
2383 ret->initialized = FALSE;
2384 ret->interlace = FALSE; /* FIXME: read from the properties */
2385 ret->committed = FALSE;
2386 ret->width = 0;
2387 ret->height = 0;
2388 ret->lines = 0;
2389 ret->xres = 0.0;
2390 ret->yres = 0.0;
2391 ret->colors = 0;
2392 ret->image_data = NULL;
2393 IWICBitmapEncoder_AddRef(iface);
2394 *frame = &ret->IWICBitmapFrameEncode_iface;
2396 hr = S_OK;
2398 if (options)
2400 hr = CreatePropertyBag2(NULL, 0, options);
2401 if (hr != S_OK)
2403 IWICBitmapFrameEncode_Release(*frame);
2404 *frame = NULL;
2408 else
2409 hr = E_OUTOFMEMORY;
2411 else
2412 hr = WINCODEC_ERR_WRONGSTATE;
2414 LeaveCriticalSection(&This->lock);
2416 return hr;
2420 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
2422 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2423 HRESULT hr;
2425 TRACE("%p\n", iface);
2427 EnterCriticalSection(&This->lock);
2429 if (This->initialized && !This->committed)
2431 char gif_trailer = 0x3b;
2433 /* FIXME: write text, comment GIF extensions */
2435 hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
2436 if (hr == S_OK)
2437 This->committed = TRUE;
2439 else
2440 hr = WINCODEC_ERR_WRONGSTATE;
2442 LeaveCriticalSection(&This->lock);
2443 return hr;
2446 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
2448 FIXME("%p,%p: stub\n", iface, writer);
2449 return E_NOTIMPL;
2452 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
2454 GifEncoder_QueryInterface,
2455 GifEncoder_AddRef,
2456 GifEncoder_Release,
2457 GifEncoder_Initialize,
2458 GifEncoder_GetContainerFormat,
2459 GifEncoder_GetEncoderInfo,
2460 GifEncoder_SetColorContexts,
2461 GifEncoder_SetPalette,
2462 GifEncoder_SetThumbnail,
2463 GifEncoder_SetPreview,
2464 GifEncoder_CreateNewFrame,
2465 GifEncoder_Commit,
2466 GifEncoder_GetMetadataQueryWriter
2469 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
2471 GifEncoder *This;
2472 HRESULT ret;
2474 TRACE("%s,%p\n", debugstr_guid(iid), ppv);
2476 *ppv = NULL;
2478 This = malloc(sizeof(*This));
2479 if (!This) return E_OUTOFMEMORY;
2481 This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
2482 This->ref = 1;
2483 This->stream = NULL;
2484 InitializeCriticalSection(&This->lock);
2485 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
2486 This->initialized = FALSE;
2487 This->info_written = FALSE;
2488 This->committed = FALSE;
2489 This->n_frames = 0;
2490 This->colors = 0;
2492 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2493 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2495 return ret;