winecoreaudio: Remove GetAudioSessionWrapper.
[wine.git] / dlls / windowscodecs / gifformat.c
blob152c51eac765571d93d72decb2b0aa763756cba4
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 #define NONAMELESSUNION
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
29 #include "ungif.h"
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
37 #include "pshpack1.h"
39 struct logical_screen_descriptor
41 char signature[6];
42 USHORT width;
43 USHORT height;
44 BYTE packed;
45 /* global_color_table_flag : 1;
46 * color_resolution : 3;
47 * sort_flag : 1;
48 * global_color_table_size : 3;
50 BYTE background_color_index;
51 BYTE pixel_aspect_ratio;
54 struct image_descriptor
56 USHORT left;
57 USHORT top;
58 USHORT width;
59 USHORT height;
60 BYTE packed;
61 /* local_color_table_flag : 1;
62 * interlace_flag : 1;
63 * sort_flag : 1;
64 * reserved : 2;
65 * local_color_table_size : 3;
69 #include "poppack.h"
71 static LPWSTR strdupAtoW(const char *src)
73 int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
74 LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
75 if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
76 return dst;
79 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
80 MetadataItem **items, DWORD *count)
82 struct logical_screen_descriptor lsd_data;
83 HRESULT hr;
84 ULONG bytesread, i;
85 MetadataItem *result;
87 *items = NULL;
88 *count = 0;
90 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
91 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
93 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9);
94 if (!result) return E_OUTOFMEMORY;
96 for (i = 0; i < 9; i++)
98 PropVariantInit(&result[i].schema);
99 PropVariantInit(&result[i].id);
100 PropVariantInit(&result[i].value);
103 result[0].id.vt = VT_LPWSTR;
104 result[0].id.pwszVal = strdupAtoW("Signature");
105 result[0].value.vt = VT_UI1|VT_VECTOR;
106 result[0].value.caub.cElems = sizeof(lsd_data.signature);
107 result[0].value.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
108 memcpy(result[0].value.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
110 result[1].id.vt = VT_LPWSTR;
111 result[1].id.pwszVal = strdupAtoW("Width");
112 result[1].value.vt = VT_UI2;
113 result[1].value.uiVal = lsd_data.width;
115 result[2].id.vt = VT_LPWSTR;
116 result[2].id.pwszVal = strdupAtoW("Height");
117 result[2].value.vt = VT_UI2;
118 result[2].value.uiVal = lsd_data.height;
120 result[3].id.vt = VT_LPWSTR;
121 result[3].id.pwszVal = strdupAtoW("GlobalColorTableFlag");
122 result[3].value.vt = VT_BOOL;
123 result[3].value.boolVal = (lsd_data.packed >> 7) & 1;
125 result[4].id.vt = VT_LPWSTR;
126 result[4].id.pwszVal = strdupAtoW("ColorResolution");
127 result[4].value.vt = VT_UI1;
128 result[4].value.bVal = (lsd_data.packed >> 4) & 7;
130 result[5].id.vt = VT_LPWSTR;
131 result[5].id.pwszVal = strdupAtoW("SortFlag");
132 result[5].value.vt = VT_BOOL;
133 result[5].value.boolVal = (lsd_data.packed >> 3) & 1;
135 result[6].id.vt = VT_LPWSTR;
136 result[6].id.pwszVal = strdupAtoW("GlobalColorTableSize");
137 result[6].value.vt = VT_UI1;
138 result[6].value.bVal = lsd_data.packed & 7;
140 result[7].id.vt = VT_LPWSTR;
141 result[7].id.pwszVal = strdupAtoW("BackgroundColorIndex");
142 result[7].value.vt = VT_UI1;
143 result[7].value.bVal = lsd_data.background_color_index;
145 result[8].id.vt = VT_LPWSTR;
146 result[8].id.pwszVal = strdupAtoW("PixelAspectRatio");
147 result[8].value.vt = VT_UI1;
148 result[8].value.bVal = lsd_data.pixel_aspect_ratio;
150 *items = result;
151 *count = 9;
153 return S_OK;
156 static const MetadataHandlerVtbl LSDReader_Vtbl = {
158 &CLSID_WICLSDMetadataReader,
159 load_LSD_metadata
162 HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv)
164 return MetadataReader_Create(&LSDReader_Vtbl, iid, ppv);
167 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
168 MetadataItem **items, DWORD *count)
170 struct image_descriptor imd_data;
171 HRESULT hr;
172 ULONG bytesread, i;
173 MetadataItem *result;
175 *items = NULL;
176 *count = 0;
178 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
179 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
181 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8);
182 if (!result) return E_OUTOFMEMORY;
184 for (i = 0; i < 8; i++)
186 PropVariantInit(&result[i].schema);
187 PropVariantInit(&result[i].id);
188 PropVariantInit(&result[i].value);
191 result[0].id.vt = VT_LPWSTR;
192 result[0].id.pwszVal = strdupAtoW("Left");
193 result[0].value.vt = VT_UI2;
194 result[0].value.uiVal = imd_data.left;
196 result[1].id.vt = VT_LPWSTR;
197 result[1].id.pwszVal = strdupAtoW("Top");
198 result[1].value.vt = VT_UI2;
199 result[1].value.uiVal = imd_data.top;
201 result[2].id.vt = VT_LPWSTR;
202 result[2].id.pwszVal = strdupAtoW("Width");
203 result[2].value.vt = VT_UI2;
204 result[2].value.uiVal = imd_data.width;
206 result[3].id.vt = VT_LPWSTR;
207 result[3].id.pwszVal = strdupAtoW("Height");
208 result[3].value.vt = VT_UI2;
209 result[3].value.uiVal = imd_data.height;
211 result[4].id.vt = VT_LPWSTR;
212 result[4].id.pwszVal = strdupAtoW("LocalColorTableFlag");
213 result[4].value.vt = VT_BOOL;
214 result[4].value.boolVal = (imd_data.packed >> 7) & 1;
216 result[5].id.vt = VT_LPWSTR;
217 result[5].id.pwszVal = strdupAtoW("InterlaceFlag");
218 result[5].value.vt = VT_BOOL;
219 result[5].value.boolVal = (imd_data.packed >> 6) & 1;
221 result[6].id.vt = VT_LPWSTR;
222 result[6].id.pwszVal = strdupAtoW("SortFlag");
223 result[6].value.vt = VT_BOOL;
224 result[6].value.boolVal = (imd_data.packed >> 5) & 1;
226 result[7].id.vt = VT_LPWSTR;
227 result[7].id.pwszVal = strdupAtoW("LocalColorTableSize");
228 result[7].value.vt = VT_UI1;
229 result[7].value.bVal = imd_data.packed & 7;
231 *items = result;
232 *count = 8;
234 return S_OK;
237 static const MetadataHandlerVtbl IMDReader_Vtbl = {
239 &CLSID_WICIMDMetadataReader,
240 load_IMD_metadata
243 HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv)
245 return MetadataReader_Create(&IMDReader_Vtbl, iid, ppv);
248 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
249 MetadataItem **items, DWORD *count)
251 #include "pshpack1.h"
252 struct graphic_control_extension
254 BYTE packed;
255 /* reservred: 3;
256 * disposal : 3;
257 * user_input_flag : 1;
258 * transparency_flag : 1;
260 USHORT delay;
261 BYTE transparent_color_index;
262 } gce_data;
263 #include "poppack.h"
264 HRESULT hr;
265 ULONG bytesread, i;
266 MetadataItem *result;
268 *items = NULL;
269 *count = 0;
271 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
272 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
274 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5);
275 if (!result) return E_OUTOFMEMORY;
277 for (i = 0; i < 5; i++)
279 PropVariantInit(&result[i].schema);
280 PropVariantInit(&result[i].id);
281 PropVariantInit(&result[i].value);
284 result[0].id.vt = VT_LPWSTR;
285 result[0].id.pwszVal = strdupAtoW("Disposal");
286 result[0].value.vt = VT_UI1;
287 result[0].value.bVal = (gce_data.packed >> 2) & 7;
289 result[1].id.vt = VT_LPWSTR;
290 result[1].id.pwszVal = strdupAtoW("UserInputFlag");
291 result[1].value.vt = VT_BOOL;
292 result[1].value.boolVal = (gce_data.packed >> 1) & 1;
294 result[2].id.vt = VT_LPWSTR;
295 result[2].id.pwszVal = strdupAtoW("TransparencyFlag");
296 result[2].value.vt = VT_BOOL;
297 result[2].value.boolVal = gce_data.packed & 1;
299 result[3].id.vt = VT_LPWSTR;
300 result[3].id.pwszVal = strdupAtoW("Delay");
301 result[3].value.vt = VT_UI2;
302 result[3].value.uiVal = gce_data.delay;
304 result[4].id.vt = VT_LPWSTR;
305 result[4].id.pwszVal = strdupAtoW("TransparentColorIndex");
306 result[4].value.vt = VT_UI1;
307 result[4].value.bVal = gce_data.transparent_color_index;
309 *items = result;
310 *count = 5;
312 return S_OK;
315 static const MetadataHandlerVtbl GCEReader_Vtbl = {
317 &CLSID_WICGCEMetadataReader,
318 load_GCE_metadata
321 HRESULT GCEReader_CreateInstance(REFIID iid, void **ppv)
323 return MetadataReader_Create(&GCEReader_Vtbl, iid, ppv);
326 static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
327 MetadataItem **items, DWORD *count)
329 #include "pshpack1.h"
330 struct application_extension
332 BYTE extension_introducer;
333 BYTE extension_label;
334 BYTE block_size;
335 BYTE application[11];
336 } ape_data;
337 #include "poppack.h"
338 HRESULT hr;
339 ULONG bytesread, data_size, i;
340 MetadataItem *result;
341 BYTE subblock_size;
342 BYTE *data;
344 *items = NULL;
345 *count = 0;
347 hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
348 if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
349 if (ape_data.extension_introducer != 0x21 ||
350 ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
351 ape_data.block_size != 11)
352 return S_OK;
354 data = NULL;
355 data_size = 0;
357 for (;;)
359 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
360 if (FAILED(hr) || bytesread != sizeof(subblock_size))
362 HeapFree(GetProcessHeap(), 0, data);
363 return S_OK;
365 if (!subblock_size) break;
367 if (!data)
368 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
369 else
371 BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
372 if (!new_data)
374 HeapFree(GetProcessHeap(), 0, data);
375 return S_OK;
377 data = new_data;
379 data[data_size] = subblock_size;
380 hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
381 if (FAILED(hr) || bytesread != subblock_size)
383 HeapFree(GetProcessHeap(), 0, data);
384 return S_OK;
386 data_size += subblock_size + 1;
389 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2);
390 if (!result)
392 HeapFree(GetProcessHeap(), 0, data);
393 return E_OUTOFMEMORY;
396 for (i = 0; i < 2; i++)
398 PropVariantInit(&result[i].schema);
399 PropVariantInit(&result[i].id);
400 PropVariantInit(&result[i].value);
403 result[0].id.vt = VT_LPWSTR;
404 result[0].id.pwszVal = strdupAtoW("Application");
405 result[0].value.vt = VT_UI1|VT_VECTOR;
406 result[0].value.caub.cElems = sizeof(ape_data.application);
407 result[0].value.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application));
408 memcpy(result[0].value.caub.pElems, ape_data.application, sizeof(ape_data.application));
410 result[1].id.vt = VT_LPWSTR;
411 result[1].id.pwszVal = strdupAtoW("Data");
412 result[1].value.vt = VT_UI1|VT_VECTOR;
413 result[1].value.caub.cElems = data_size;
414 result[1].value.caub.pElems = data;
416 *items = result;
417 *count = 2;
419 return S_OK;
422 static const MetadataHandlerVtbl APEReader_Vtbl = {
424 &CLSID_WICAPEMetadataReader,
425 load_APE_metadata
428 HRESULT APEReader_CreateInstance(REFIID iid, void **ppv)
430 return MetadataReader_Create(&APEReader_Vtbl, iid, ppv);
433 static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
434 MetadataItem **items, DWORD *count)
436 #include "pshpack1.h"
437 struct gif_extension
439 BYTE extension_introducer;
440 BYTE extension_label;
441 } ext_data;
442 #include "poppack.h"
443 HRESULT hr;
444 ULONG bytesread, data_size;
445 MetadataItem *result;
446 BYTE subblock_size;
447 char *data;
449 *items = NULL;
450 *count = 0;
452 hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
453 if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
454 if (ext_data.extension_introducer != 0x21 ||
455 ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
456 return S_OK;
458 data = NULL;
459 data_size = 0;
461 for (;;)
463 hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
464 if (FAILED(hr) || bytesread != sizeof(subblock_size))
466 HeapFree(GetProcessHeap(), 0, data);
467 return S_OK;
469 if (!subblock_size) break;
471 if (!data)
472 data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
473 else
475 char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
476 if (!new_data)
478 HeapFree(GetProcessHeap(), 0, data);
479 return S_OK;
481 data = new_data;
483 hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
484 if (FAILED(hr) || bytesread != subblock_size)
486 HeapFree(GetProcessHeap(), 0, data);
487 return S_OK;
489 data_size += subblock_size;
492 data[data_size] = 0;
494 result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem));
495 if (!result)
497 HeapFree(GetProcessHeap(), 0, data);
498 return E_OUTOFMEMORY;
501 PropVariantInit(&result->schema);
502 PropVariantInit(&result->id);
503 PropVariantInit(&result->value);
505 result->id.vt = VT_LPWSTR;
506 result->id.pwszVal = strdupAtoW("TextEntry");
507 result->value.vt = VT_LPSTR;
508 result->value.pszVal = data;
510 *items = result;
511 *count = 1;
513 return S_OK;
516 static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
518 &CLSID_WICGifCommentMetadataReader,
519 load_GifComment_metadata
522 HRESULT GifCommentReader_CreateInstance(REFIID iid, void **ppv)
524 return MetadataReader_Create(&GifCommentReader_Vtbl, iid, ppv);
527 static IStream *create_stream(const void *data, int data_size)
529 HRESULT hr;
530 IStream *stream;
531 HGLOBAL hdata;
532 void *locked_data;
534 hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
535 if (!hdata) return NULL;
537 locked_data = GlobalLock(hdata);
538 memcpy(locked_data, data, data_size);
539 GlobalUnlock(hdata);
541 hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
542 return FAILED(hr) ? NULL : stream;
545 static HRESULT create_metadata_reader(const void *data, int data_size,
546 class_constructor constructor,
547 IWICMetadataReader **reader)
549 HRESULT hr;
550 IWICMetadataReader *metadata_reader;
551 IWICPersistStream *persist;
552 IStream *stream;
554 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
556 hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader);
557 if (FAILED(hr)) return hr;
559 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
560 if (FAILED(hr))
562 IWICMetadataReader_Release(metadata_reader);
563 return hr;
566 stream = create_stream(data, data_size);
567 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
568 IStream_Release(stream);
570 IWICPersistStream_Release(persist);
572 *reader = metadata_reader;
573 return S_OK;
576 typedef struct {
577 IWICBitmapDecoder IWICBitmapDecoder_iface;
578 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
579 IStream *stream;
580 BYTE LSD_data[13]; /* Logical Screen Descriptor */
581 LONG ref;
582 BOOL initialized;
583 GifFileType *gif;
584 UINT current_frame;
585 CRITICAL_SECTION lock;
586 } GifDecoder;
588 typedef struct {
589 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
590 IWICMetadataBlockReader IWICMetadataBlockReader_iface;
591 LONG ref;
592 SavedImage *frame;
593 GifDecoder *parent;
594 } GifFrameDecode;
596 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
598 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
601 static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
603 return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
606 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
608 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
611 static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
613 return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface);
616 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
617 void **ppv)
619 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
620 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
622 if (!ppv) return E_INVALIDARG;
624 if (IsEqualIID(&IID_IUnknown, iid) ||
625 IsEqualIID(&IID_IWICBitmapSource, iid) ||
626 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
628 *ppv = &This->IWICBitmapFrameDecode_iface;
630 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
632 *ppv = &This->IWICMetadataBlockReader_iface;
634 else
636 *ppv = NULL;
637 return E_NOINTERFACE;
640 IUnknown_AddRef((IUnknown*)*ppv);
641 return S_OK;
644 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
646 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
647 ULONG ref = InterlockedIncrement(&This->ref);
649 TRACE("(%p) refcount=%lu\n", iface, ref);
651 return ref;
654 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
656 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
657 ULONG ref = InterlockedDecrement(&This->ref);
659 TRACE("(%p) refcount=%lu\n", iface, ref);
661 if (ref == 0)
663 IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
664 HeapFree(GetProcessHeap(), 0, This);
667 return ref;
670 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
671 UINT *puiWidth, UINT *puiHeight)
673 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
674 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
676 *puiWidth = This->frame->ImageDesc.Width;
677 *puiHeight = This->frame->ImageDesc.Height;
679 return S_OK;
682 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
683 WICPixelFormatGUID *pPixelFormat)
685 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
687 return S_OK;
690 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
691 double *pDpiX, double *pDpiY)
693 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
694 const GifWord aspect_word = This->parent->gif->SAspectRatio;
695 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
696 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
698 *pDpiX = 96.0 / aspect;
699 *pDpiY = 96.0;
701 return S_OK;
704 static void copy_palette(ColorMapObject *cm, Extensions *extensions, int count, WICColor *colors)
706 int i;
708 if (cm)
710 for (i = 0; i < count; i++)
712 colors[i] = 0xff000000 | /* alpha */
713 cm->Colors[i].Red << 16 |
714 cm->Colors[i].Green << 8 |
715 cm->Colors[i].Blue;
718 else
720 colors[0] = 0xff000000;
721 colors[1] = 0xffffffff;
722 for (i = 2; i < count; i++)
723 colors[i] = 0xff000000;
726 /* look for the transparent color extension */
727 for (i = 0; i < extensions->ExtensionBlockCount; i++)
729 ExtensionBlock *eb = extensions->ExtensionBlocks + i;
730 if (eb->Function == GRAPHICS_EXT_FUNC_CODE &&
731 eb->ByteCount == 8 && eb->Bytes[3] & 1)
733 int trans = (unsigned char)eb->Bytes[6];
734 colors[trans] &= 0xffffff; /* set alpha to 0 */
735 break;
740 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
741 IWICPalette *pIPalette)
743 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
744 WICColor colors[256];
745 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
746 int count;
748 TRACE("(%p,%p)\n", iface, pIPalette);
750 if (cm)
751 count = cm->ColorCount;
752 else
754 cm = This->parent->gif->SColorMap;
755 count = This->parent->gif->SColorTableSize;
758 if (count > 256)
760 ERR("GIF contains %i colors???\n", count);
761 return E_FAIL;
764 copy_palette(cm, &This->frame->Extensions, count, colors);
766 return IWICPalette_InitializeCustom(pIPalette, colors, count);
769 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
770 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
771 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
773 UINT row_offset; /* number of bytes into the source rows where the data starts */
774 const BYTE *src;
775 BYTE *dst;
776 UINT y;
777 WICRect rect;
779 if (!rc)
781 rect.X = 0;
782 rect.Y = 0;
783 rect.Width = srcwidth;
784 rect.Height = srcheight;
785 rc = &rect;
787 else
789 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
790 return E_INVALIDARG;
793 if (dststride < rc->Width)
794 return E_INVALIDARG;
796 if ((dststride * rc->Height) > dstbuffersize)
797 return E_INVALIDARG;
799 row_offset = rc->X;
801 dst = dstbuffer;
802 for (y=rc->Y; y-rc->Y < rc->Height; y++)
804 if (y%8 == 0)
805 src = srcbuffer + srcstride * (y/8);
806 else if (y%4 == 0)
807 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
808 else if (y%2 == 0)
809 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
810 else /* y%2 == 1 */
811 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
812 src += row_offset;
813 memcpy(dst, src, rc->Width);
814 dst += dststride;
816 return S_OK;
819 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
820 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
822 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
823 TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer);
825 if (This->frame->ImageDesc.Interlace)
827 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
828 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
829 prc, cbStride, cbBufferSize, pbBuffer);
831 else
833 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
834 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
835 prc, cbStride, cbBufferSize, pbBuffer);
839 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
840 IWICMetadataQueryReader **ppIMetadataQueryReader)
842 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
844 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
846 if (!ppIMetadataQueryReader)
847 return E_INVALIDARG;
849 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
852 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
853 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
855 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
856 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
859 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
860 IWICBitmapSource **ppIThumbnail)
862 TRACE("(%p,%p)\n", iface, ppIThumbnail);
863 return WINCODEC_ERR_CODECNOTHUMBNAIL;
866 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
867 GifFrameDecode_QueryInterface,
868 GifFrameDecode_AddRef,
869 GifFrameDecode_Release,
870 GifFrameDecode_GetSize,
871 GifFrameDecode_GetPixelFormat,
872 GifFrameDecode_GetResolution,
873 GifFrameDecode_CopyPalette,
874 GifFrameDecode_CopyPixels,
875 GifFrameDecode_GetMetadataQueryReader,
876 GifFrameDecode_GetColorContexts,
877 GifFrameDecode_GetThumbnail
880 static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface,
881 REFIID iid, void **ppv)
883 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
884 return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv);
887 static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface)
889 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
890 return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface);
893 static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface)
895 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
896 return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface);
899 static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
900 GUID *guid)
902 TRACE("(%p,%p)\n", iface, guid);
904 if (!guid) return E_INVALIDARG;
906 *guid = GUID_ContainerFormatGif;
907 return S_OK;
910 static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface,
911 UINT *count)
913 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
915 TRACE("%p,%p\n", iface, count);
917 if (!count) return E_INVALIDARG;
919 *count = This->frame->Extensions.ExtensionBlockCount + 1;
920 return S_OK;
923 static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader)
925 HRESULT hr;
926 IWICMetadataReader *metadata_reader;
927 IWICPersistStream *persist;
928 IStream *stream;
929 struct image_descriptor IMD_data;
931 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
933 hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader);
934 if (FAILED(hr)) return hr;
936 hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist);
937 if (FAILED(hr))
939 IWICMetadataReader_Release(metadata_reader);
940 return hr;
943 /* recreate IMD structure from GIF decoder data */
944 IMD_data.left = This->frame->ImageDesc.Left;
945 IMD_data.top = This->frame->ImageDesc.Top;
946 IMD_data.width = This->frame->ImageDesc.Width;
947 IMD_data.height = This->frame->ImageDesc.Height;
948 IMD_data.packed = 0;
949 /* interlace_flag */
950 IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0;
951 if (This->frame->ImageDesc.ColorMap)
953 /* local_color_table_flag */
954 IMD_data.packed |= 1 << 7;
955 /* local_color_table_size */
956 IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel - 1;
957 /* sort_flag */
958 IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
961 stream = create_stream(&IMD_data, sizeof(IMD_data));
962 IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionDefault);
963 IStream_Release(stream);
965 IWICPersistStream_Release(persist);
967 *reader = metadata_reader;
968 return S_OK;
971 static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
972 UINT index, IWICMetadataReader **reader)
974 GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
975 class_constructor constructor;
976 ExtensionBlock *ext;
977 const void *data;
978 int data_size;
980 TRACE("(%p,%u,%p)\n", iface, index, reader);
982 if (!reader) return E_INVALIDARG;
984 if (index == 0)
985 return create_IMD_metadata_reader(This, reader);
987 if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
988 return E_INVALIDARG;
990 ext = This->frame->Extensions.ExtensionBlocks + index - 1;
991 if (ext->Function == GRAPHICS_EXT_FUNC_CODE)
993 constructor = GCEReader_CreateInstance;
994 data = ext->Bytes + 3;
995 data_size = ext->ByteCount - 4;
997 else if (ext->Function == COMMENT_EXT_FUNC_CODE)
999 constructor = GifCommentReader_CreateInstance;
1000 data = ext->Bytes;
1001 data_size = ext->ByteCount;
1003 else
1005 constructor = UnknownMetadataReader_CreateInstance;
1006 data = ext->Bytes;
1007 data_size = ext->ByteCount;
1010 return create_metadata_reader(data, data_size, constructor, reader);
1013 static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1014 IEnumUnknown **enumerator)
1016 FIXME("(%p,%p): stub\n", iface, enumerator);
1017 return E_NOTIMPL;
1020 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl =
1022 GifFrameDecode_Block_QueryInterface,
1023 GifFrameDecode_Block_AddRef,
1024 GifFrameDecode_Block_Release,
1025 GifFrameDecode_Block_GetContainerFormat,
1026 GifFrameDecode_Block_GetCount,
1027 GifFrameDecode_Block_GetReaderByIndex,
1028 GifFrameDecode_Block_GetEnumerator
1031 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
1032 void **ppv)
1034 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1035 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
1037 if (!ppv) return E_INVALIDARG;
1039 if (IsEqualIID(&IID_IUnknown, iid) ||
1040 IsEqualIID(&IID_IWICBitmapDecoder, iid))
1042 *ppv = &This->IWICBitmapDecoder_iface;
1044 else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
1046 *ppv = &This->IWICMetadataBlockReader_iface;
1048 else
1050 *ppv = NULL;
1051 return E_NOINTERFACE;
1054 IUnknown_AddRef((IUnknown*)*ppv);
1055 return S_OK;
1058 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
1060 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1061 ULONG ref = InterlockedIncrement(&This->ref);
1063 TRACE("(%p) refcount=%lu\n", iface, ref);
1065 return ref;
1068 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
1070 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1071 ULONG ref = InterlockedDecrement(&This->ref);
1073 TRACE("(%p) refcount=%lu\n", iface, ref);
1075 if (ref == 0)
1077 if (This->stream)
1079 IStream_Release(This->stream);
1080 DGifCloseFile(This->gif);
1082 This->lock.DebugInfo->Spare[0] = 0;
1083 DeleteCriticalSection(&This->lock);
1084 HeapFree(GetProcessHeap(), 0, This);
1087 return ref;
1090 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
1091 DWORD *capability)
1093 HRESULT hr;
1095 TRACE("(%p,%p,%p)\n", iface, stream, capability);
1097 if (!stream || !capability) return E_INVALIDARG;
1099 hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
1100 if (hr != S_OK) return hr;
1102 *capability = WICBitmapDecoderCapabilityCanDecodeAllImages |
1103 WICBitmapDecoderCapabilityCanDecodeSomeImages |
1104 WICBitmapDecoderCapabilityCanEnumerateMetadata;
1105 return S_OK;
1108 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
1109 IStream *stream = gif->UserData;
1110 ULONG bytesread;
1111 HRESULT hr;
1113 if (!stream)
1115 ERR("attempting to read file after initialization\n");
1116 return 0;
1119 hr = IStream_Read(stream, data, len, &bytesread);
1120 if (FAILED(hr)) bytesread = 0;
1121 return bytesread;
1124 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
1125 WICDecodeOptions cacheOptions)
1127 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1128 LARGE_INTEGER seek;
1129 int ret;
1131 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
1133 EnterCriticalSection(&This->lock);
1135 if (This->initialized || This->gif)
1137 WARN("already initialized\n");
1138 LeaveCriticalSection(&This->lock);
1139 return WINCODEC_ERR_WRONGSTATE;
1142 /* seek to start of stream */
1143 seek.QuadPart = 0;
1144 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1146 /* read all data from the stream */
1147 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
1148 if (!This->gif)
1150 LeaveCriticalSection(&This->lock);
1151 return E_FAIL;
1154 ret = DGifSlurp(This->gif);
1155 if (ret == GIF_ERROR)
1157 LeaveCriticalSection(&This->lock);
1158 return E_FAIL;
1161 /* make sure we don't use the stream after this method returns */
1162 This->gif->UserData = NULL;
1164 seek.QuadPart = 0;
1165 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
1166 IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL);
1168 This->stream = pIStream;
1169 IStream_AddRef(This->stream);
1171 This->initialized = TRUE;
1173 LeaveCriticalSection(&This->lock);
1175 return S_OK;
1178 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
1179 GUID *pguidContainerFormat)
1181 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
1182 return S_OK;
1185 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
1186 IWICBitmapDecoderInfo **ppIDecoderInfo)
1188 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
1190 return get_decoder_info(&CLSID_WICGifDecoder, ppIDecoderInfo);
1193 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
1195 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1196 WICColor colors[256];
1197 ColorMapObject *cm;
1198 int count;
1200 TRACE("(%p,%p)\n", iface, palette);
1202 if (!This->gif)
1203 return WINCODEC_ERR_WRONGSTATE;
1205 cm = This->gif->SColorMap;
1206 count = This->gif->SColorTableSize;
1208 if (count > 256)
1210 ERR("GIF contains invalid number of colors: %d\n", count);
1211 return E_FAIL;
1214 copy_palette(cm, &This->gif->SavedImages[This->current_frame].Extensions, count, colors);
1216 return IWICPalette_InitializeCustom(palette, colors, count);
1219 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
1220 IWICMetadataQueryReader **ppIMetadataQueryReader)
1222 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1224 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
1226 if (!ppIMetadataQueryReader) return E_INVALIDARG;
1228 return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader);
1231 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
1232 IWICBitmapSource **ppIBitmapSource)
1234 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
1235 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1238 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
1239 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
1241 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
1242 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
1245 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
1246 IWICBitmapSource **ppIThumbnail)
1248 TRACE("(%p,%p)\n", iface, ppIThumbnail);
1249 return WINCODEC_ERR_CODECNOTHUMBNAIL;
1252 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
1253 UINT *pCount)
1255 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1257 if (!pCount) return E_INVALIDARG;
1259 EnterCriticalSection(&This->lock);
1260 *pCount = This->gif ? This->gif->ImageCount : 0;
1261 LeaveCriticalSection(&This->lock);
1263 TRACE("(%p) <-- %d\n", iface, *pCount);
1265 return S_OK;
1268 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
1269 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
1271 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
1272 GifFrameDecode *result;
1273 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
1275 if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
1277 if (index >= This->gif->ImageCount) return E_INVALIDARG;
1279 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
1280 if (!result) return E_OUTOFMEMORY;
1282 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
1283 result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
1284 result->ref = 1;
1285 result->frame = &This->gif->SavedImages[index];
1286 IWICBitmapDecoder_AddRef(iface);
1287 result->parent = This;
1288 This->current_frame = index;
1290 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
1292 return S_OK;
1295 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
1296 GifDecoder_QueryInterface,
1297 GifDecoder_AddRef,
1298 GifDecoder_Release,
1299 GifDecoder_QueryCapability,
1300 GifDecoder_Initialize,
1301 GifDecoder_GetContainerFormat,
1302 GifDecoder_GetDecoderInfo,
1303 GifDecoder_CopyPalette,
1304 GifDecoder_GetMetadataQueryReader,
1305 GifDecoder_GetPreview,
1306 GifDecoder_GetColorContexts,
1307 GifDecoder_GetThumbnail,
1308 GifDecoder_GetFrameCount,
1309 GifDecoder_GetFrame
1312 static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
1313 REFIID iid, void **ppv)
1315 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1316 return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1319 static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
1321 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1322 return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
1325 static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
1327 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1328 return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1331 static HRESULT WINAPI GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface,
1332 GUID *guid)
1334 TRACE("(%p,%p)\n", iface, guid);
1336 if (!guid) return E_INVALIDARG;
1338 *guid = GUID_ContainerFormatGif;
1339 return S_OK;
1342 static HRESULT WINAPI GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
1343 UINT *count)
1345 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1347 TRACE("%p,%p\n", iface, count);
1349 if (!count) return E_INVALIDARG;
1351 *count = This->gif->Extensions.ExtensionBlockCount + 1;
1352 return S_OK;
1355 static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
1356 UINT index, IWICMetadataReader **reader)
1358 GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
1359 int i;
1361 TRACE("(%p,%u,%p)\n", iface, index, reader);
1363 if (!reader) return E_INVALIDARG;
1365 if (index == 0)
1366 return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
1367 LSDReader_CreateInstance, reader);
1369 for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
1371 class_constructor constructor;
1373 if (index != i + 1) continue;
1375 if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
1376 constructor = APEReader_CreateInstance;
1377 else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
1378 constructor = GifCommentReader_CreateInstance;
1379 else
1380 constructor = UnknownMetadataReader_CreateInstance;
1382 return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
1383 This->gif->Extensions.ExtensionBlocks[i].ByteCount,
1384 constructor, reader);
1387 return E_INVALIDARG;
1390 static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
1391 IEnumUnknown **enumerator)
1393 FIXME("(%p,%p): stub\n", iface, enumerator);
1394 return E_NOTIMPL;
1397 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
1399 GifDecoder_Block_QueryInterface,
1400 GifDecoder_Block_AddRef,
1401 GifDecoder_Block_Release,
1402 GifDecoder_Block_GetContainerFormat,
1403 GifDecoder_Block_GetCount,
1404 GifDecoder_Block_GetReaderByIndex,
1405 GifDecoder_Block_GetEnumerator
1408 HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv)
1410 GifDecoder *This;
1411 HRESULT ret;
1413 TRACE("(%s,%p)\n", debugstr_guid(iid), ppv);
1415 *ppv = NULL;
1417 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
1418 if (!This) return E_OUTOFMEMORY;
1420 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
1421 This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
1422 This->stream = NULL;
1423 This->ref = 1;
1424 This->initialized = FALSE;
1425 This->gif = NULL;
1426 This->current_frame = 0;
1427 InitializeCriticalSection(&This->lock);
1428 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
1430 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
1431 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
1433 return ret;
1436 typedef struct GifEncoder
1438 IWICBitmapEncoder IWICBitmapEncoder_iface;
1439 LONG ref;
1440 IStream *stream;
1441 CRITICAL_SECTION lock;
1442 BOOL initialized, info_written, committed;
1443 UINT n_frames;
1444 WICColor palette[256];
1445 UINT colors;
1446 } GifEncoder;
1448 static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
1450 return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface);
1453 typedef struct GifFrameEncode
1455 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
1456 IWICMetadataBlockWriter IWICMetadataBlockWriter_iface;
1457 LONG ref;
1458 GifEncoder *encoder;
1459 BOOL initialized, interlace, committed;
1460 UINT width, height, lines;
1461 double xres, yres;
1462 WICColor palette[256];
1463 UINT colors;
1464 BYTE *image_data;
1465 } GifFrameEncode;
1467 static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
1469 return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface);
1472 static inline GifFrameEncode *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface)
1474 return CONTAINING_RECORD(iface, GifFrameEncode, IWICMetadataBlockWriter_iface);
1477 static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv)
1479 GifFrameEncode *encoder = impl_from_IWICBitmapFrameEncode(iface);
1481 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
1483 if (!ppv) return E_INVALIDARG;
1485 if (IsEqualIID(&IID_IUnknown, iid) ||
1486 IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
1488 *ppv = iface;
1490 else if (IsEqualIID(&IID_IWICMetadataBlockWriter, iid))
1492 *ppv = &encoder->IWICMetadataBlockWriter_iface;
1494 else
1496 *ppv = NULL;
1497 return E_NOINTERFACE;
1500 IUnknown_AddRef((IUnknown *)*ppv);
1501 return S_OK;
1504 static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
1506 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1507 ULONG ref = InterlockedIncrement(&This->ref);
1509 TRACE("%p -> %lu\n", iface, ref);
1510 return ref;
1513 static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface)
1515 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1516 ULONG ref = InterlockedDecrement(&This->ref);
1518 TRACE("%p -> %lu\n", iface, ref);
1520 if (!ref)
1522 IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface);
1523 HeapFree(GetProcessHeap(), 0, This->image_data);
1524 HeapFree(GetProcessHeap(), 0, This);
1527 return ref;
1530 static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options)
1532 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1533 HRESULT hr;
1535 TRACE("%p,%p\n", iface, options);
1537 EnterCriticalSection(&This->encoder->lock);
1539 if (!This->initialized)
1541 This->initialized = TRUE;
1542 hr = S_OK;
1544 else
1545 hr = WINCODEC_ERR_WRONGSTATE;
1547 LeaveCriticalSection(&This->encoder->lock);
1549 return hr;
1552 static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height)
1554 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1555 HRESULT hr;
1557 TRACE("%p,%u,%u\n", iface, width, height);
1559 if (!width || !height) return E_INVALIDARG;
1561 EnterCriticalSection(&This->encoder->lock);
1563 if (This->initialized)
1565 HeapFree(GetProcessHeap(), 0, This->image_data);
1567 This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height);
1568 if (This->image_data)
1570 This->width = width;
1571 This->height = height;
1572 hr = S_OK;
1574 else
1575 hr = E_OUTOFMEMORY;
1577 else
1578 hr = WINCODEC_ERR_WRONGSTATE;
1580 LeaveCriticalSection(&This->encoder->lock);
1582 return hr;
1585 static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres)
1587 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1588 HRESULT hr;
1590 TRACE("%p,%f,%f\n", iface, xres, yres);
1592 EnterCriticalSection(&This->encoder->lock);
1594 if (This->initialized)
1596 This->xres = xres;
1597 This->yres = yres;
1598 hr = S_OK;
1600 else
1601 hr = WINCODEC_ERR_WRONGSTATE;
1603 LeaveCriticalSection(&This->encoder->lock);
1605 return hr;
1608 static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format)
1610 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1611 HRESULT hr;
1613 TRACE("%p,%s\n", iface, debugstr_guid(format));
1615 if (!format) return E_INVALIDARG;
1617 EnterCriticalSection(&This->encoder->lock);
1619 if (This->initialized)
1621 *format = GUID_WICPixelFormat8bppIndexed;
1622 hr = S_OK;
1624 else
1625 hr = WINCODEC_ERR_WRONGSTATE;
1627 LeaveCriticalSection(&This->encoder->lock);
1629 return hr;
1632 static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context)
1634 FIXME("%p,%u,%p: stub\n", iface, count, context);
1635 return E_NOTIMPL;
1638 static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette)
1640 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1641 HRESULT hr;
1643 TRACE("%p,%p\n", iface, palette);
1645 if (!palette) return E_INVALIDARG;
1647 EnterCriticalSection(&This->encoder->lock);
1649 if (This->initialized)
1650 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
1651 else
1652 hr = WINCODEC_ERR_NOTINITIALIZED;
1654 LeaveCriticalSection(&This->encoder->lock);
1655 return hr;
1658 static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail)
1660 FIXME("%p,%p: stub\n", iface, thumbnail);
1661 return E_NOTIMPL;
1664 static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels)
1666 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1667 HRESULT hr;
1669 TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels);
1671 if (!pixels) return E_INVALIDARG;
1673 EnterCriticalSection(&This->encoder->lock);
1675 if (This->initialized && This->image_data)
1677 if (This->lines + lines <= This->height)
1679 UINT i;
1680 BYTE *src, *dst;
1682 src = pixels;
1683 dst = This->image_data + This->lines * This->width;
1685 for (i = 0; i < lines; i++)
1687 memcpy(dst, src, This->width);
1688 src += stride;
1689 dst += This->width;
1692 This->lines += lines;
1693 hr = S_OK;
1695 else
1696 hr = E_INVALIDARG;
1698 else
1699 hr = WINCODEC_ERR_WRONGSTATE;
1701 LeaveCriticalSection(&This->encoder->lock);
1702 return hr;
1705 static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc)
1707 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1708 HRESULT hr;
1710 TRACE("%p,%p,%p\n", iface, source, rc);
1712 if (!source) return E_INVALIDARG;
1714 EnterCriticalSection(&This->encoder->lock);
1716 if (This->initialized)
1718 const GUID *format = &GUID_WICPixelFormat8bppIndexed;
1720 hr = configure_write_source(iface, source, rc, format,
1721 This->width, This->height, This->xres, This->yres);
1722 if (hr == S_OK)
1723 hr = write_source(iface, source, rc, format, 8, !This->colors, This->width, This->height);
1725 else
1726 hr = WINCODEC_ERR_WRONGSTATE;
1728 LeaveCriticalSection(&This->encoder->lock);
1729 return hr;
1732 #define LZW_DICT_SIZE (1 << 12)
1734 struct lzw_dict
1736 short prefix[LZW_DICT_SIZE];
1737 unsigned char suffix[LZW_DICT_SIZE];
1740 struct lzw_state
1742 struct lzw_dict dict;
1743 short init_code_bits, code_bits, next_code, clear_code, eof_code;
1744 unsigned bits_buf;
1745 int bits_count;
1746 int (*user_write_data)(void *user_ptr, void *data, int length);
1747 void *user_ptr;
1750 struct input_stream
1752 unsigned len;
1753 const BYTE *in;
1756 struct output_stream
1758 struct
1760 unsigned char len;
1761 char data[255];
1762 } gif_block;
1763 IStream *out;
1766 static int lzw_output_code(struct lzw_state *state, short code)
1768 state->bits_buf |= code << state->bits_count;
1769 state->bits_count += state->code_bits;
1771 while (state->bits_count >= 8)
1773 unsigned char byte = (unsigned char)state->bits_buf;
1774 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1775 return 0;
1776 state->bits_buf >>= 8;
1777 state->bits_count -= 8;
1780 return 1;
1783 static inline int lzw_output_clear_code(struct lzw_state *state)
1785 return lzw_output_code(state, state->clear_code);
1788 static inline int lzw_output_eof_code(struct lzw_state *state)
1790 return lzw_output_code(state, state->eof_code);
1793 static int lzw_flush_bits(struct lzw_state *state)
1795 unsigned char byte;
1797 while (state->bits_count >= 8)
1799 byte = (unsigned char)state->bits_buf;
1800 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1801 return 0;
1802 state->bits_buf >>= 8;
1803 state->bits_count -= 8;
1806 if (state->bits_count)
1808 static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1810 byte = (unsigned char)state->bits_buf & mask[state->bits_count];
1811 if (state->user_write_data(state->user_ptr, &byte, 1) != 1)
1812 return 0;
1815 state->bits_buf = 0;
1816 state->bits_count = 0;
1818 return 1;
1821 static void lzw_dict_reset(struct lzw_state *state)
1823 int i;
1825 state->code_bits = state->init_code_bits + 1;
1826 state->next_code = (1 << state->init_code_bits) + 2;
1828 for(i = 0; i < LZW_DICT_SIZE; i++)
1830 state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */
1831 state->dict.suffix[i] = 0;
1835 static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr)
1837 state->init_code_bits = init_code_bits;
1838 state->clear_code = 1 << init_code_bits;
1839 state->eof_code = state->clear_code + 1;
1840 state->bits_buf = 0;
1841 state->bits_count = 0;
1842 state->user_write_data = user_write_data;
1843 state->user_ptr = user_ptr;
1845 lzw_dict_reset(state);
1848 static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix)
1850 if (state->next_code < LZW_DICT_SIZE)
1852 state->dict.prefix[state->next_code] = prefix;
1853 state->dict.suffix[state->next_code] = suffix;
1855 if ((state->next_code & (state->next_code - 1)) == 0)
1856 state->code_bits++;
1858 state->next_code++;
1859 return state->next_code;
1862 return -1;
1865 static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix)
1867 short i;
1869 for (i = 0; i < state->next_code; i++)
1871 if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix)
1872 return i;
1875 return -1;
1878 static inline int write_byte(struct output_stream *out, char byte)
1880 if (out->gif_block.len == 255)
1882 if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK)
1883 return 0;
1885 out->gif_block.len = 0;
1888 out->gif_block.data[out->gif_block.len++] = byte;
1890 return 1;
1893 static int write_data(void *user_ptr, void *user_data, int length)
1895 unsigned char *data = user_data;
1896 struct output_stream *out = user_ptr;
1897 int len = length;
1899 while (len-- > 0)
1901 if (!write_byte(out, *data++)) return 0;
1904 return length;
1907 static int flush_output_data(void *user_ptr)
1909 struct output_stream *out = user_ptr;
1911 if (out->gif_block.len)
1913 if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK)
1914 return 0;
1917 /* write GIF block terminator */
1918 out->gif_block.len = 0;
1919 return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK;
1922 static inline int read_byte(struct input_stream *in, unsigned char *byte)
1924 if (in->len)
1926 in->len--;
1927 *byte = *in->in++;
1928 return 1;
1931 return 0;
1934 static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size)
1936 struct input_stream in;
1937 struct output_stream out;
1938 struct lzw_state state;
1939 short init_code_bits, prefix, code;
1940 unsigned char suffix;
1942 in.in = in_data;
1943 in.len = in_size;
1945 out.gif_block.len = 0;
1946 out.out = out_stream;
1948 init_code_bits = suffix = 8;
1949 if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK)
1950 return E_FAIL;
1952 lzw_state_init(&state, init_code_bits, write_data, &out);
1954 if (!lzw_output_clear_code(&state))
1955 return E_FAIL;
1957 if (read_byte(&in, &suffix))
1959 prefix = suffix;
1961 while (read_byte(&in, &suffix))
1963 code = lzw_dict_lookup(&state, prefix, suffix);
1964 if (code == -1)
1966 if (!lzw_output_code(&state, prefix))
1967 return E_FAIL;
1969 if (lzw_dict_add(&state, prefix, suffix) == -1)
1971 if (!lzw_output_clear_code(&state))
1972 return E_FAIL;
1973 lzw_dict_reset(&state);
1976 prefix = suffix;
1978 else
1979 prefix = code;
1982 if (!lzw_output_code(&state, prefix))
1983 return E_FAIL;
1984 if (!lzw_output_eof_code(&state))
1985 return E_FAIL;
1986 if (!lzw_flush_bits(&state))
1987 return E_FAIL;
1990 return flush_output_data(&out) ? S_OK : E_FAIL;
1993 static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface)
1995 GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
1996 HRESULT hr;
1998 TRACE("%p\n", iface);
2000 EnterCriticalSection(&This->encoder->lock);
2002 if (This->image_data && This->lines == This->height && !This->committed)
2004 BYTE gif_palette[256][3];
2006 hr = S_OK;
2008 if (!This->encoder->info_written)
2010 struct logical_screen_descriptor lsd;
2012 /* Logical Screen Descriptor */
2013 memcpy(lsd.signature, "GIF89a", 6);
2014 lsd.width = This->width;
2015 lsd.height = This->height;
2016 lsd.packed = 0;
2017 if (This->encoder->colors)
2018 lsd.packed |= 0x80; /* global color table flag */
2019 lsd.packed |= 0x07 << 4; /* color resolution */
2020 lsd.packed |= 0x07; /* global color table size */
2021 lsd.background_color_index = 0; /* FIXME */
2022 lsd.pixel_aspect_ratio = 0;
2023 hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL);
2024 if (hr == S_OK && This->encoder->colors)
2026 UINT i;
2028 /* Global Color Table */
2029 memset(gif_palette, 0, sizeof(gif_palette));
2030 for (i = 0; i < This->encoder->colors; i++)
2032 gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff;
2033 gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff;
2034 gif_palette[i][2] = This->encoder->palette[i] & 0xff;
2036 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2039 /* FIXME: write GCE, APE, etc. GIF extensions */
2041 if (hr == S_OK)
2042 This->encoder->info_written = TRUE;
2045 if (hr == S_OK)
2047 char image_separator = 0x2c;
2049 hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL);
2050 if (hr == S_OK)
2052 struct image_descriptor imd;
2054 /* Image Descriptor */
2055 imd.left = 0;
2056 imd.top = 0;
2057 imd.width = This->width;
2058 imd.height = This->height;
2059 imd.packed = 0;
2060 if (This->colors)
2062 imd.packed |= 0x80; /* local color table flag */
2063 imd.packed |= 0x07; /* local color table size */
2065 /* FIXME: interlace flag */
2066 hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL);
2067 if (hr == S_OK && This->colors)
2069 UINT i;
2071 /* Local Color Table */
2072 memset(gif_palette, 0, sizeof(gif_palette));
2073 for (i = 0; i < This->colors; i++)
2075 gif_palette[i][0] = (This->palette[i] >> 16) & 0xff;
2076 gif_palette[i][1] = (This->palette[i] >> 8) & 0xff;
2077 gif_palette[i][2] = This->palette[i] & 0xff;
2079 hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL);
2080 if (hr == S_OK)
2082 /* Image Data */
2083 hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height);
2084 if (hr == S_OK)
2085 This->committed = TRUE;
2091 else
2092 hr = WINCODEC_ERR_WRONGSTATE;
2094 LeaveCriticalSection(&This->encoder->lock);
2095 return hr;
2098 static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer)
2100 GifFrameEncode *encode = impl_from_IWICBitmapFrameEncode(iface);
2102 TRACE("iface, %p, writer %p.\n", iface, writer);
2104 if (!writer)
2105 return E_INVALIDARG;
2107 if (!encode->initialized)
2108 return WINCODEC_ERR_NOTINITIALIZED;
2110 return MetadataQueryWriter_CreateInstance(&encode->IWICMetadataBlockWriter_iface, NULL, writer);
2113 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl =
2115 GifFrameEncode_QueryInterface,
2116 GifFrameEncode_AddRef,
2117 GifFrameEncode_Release,
2118 GifFrameEncode_Initialize,
2119 GifFrameEncode_SetSize,
2120 GifFrameEncode_SetResolution,
2121 GifFrameEncode_SetPixelFormat,
2122 GifFrameEncode_SetColorContexts,
2123 GifFrameEncode_SetPalette,
2124 GifFrameEncode_SetThumbnail,
2125 GifFrameEncode_WritePixels,
2126 GifFrameEncode_WriteSource,
2127 GifFrameEncode_Commit,
2128 GifFrameEncode_GetMetadataQueryWriter
2131 static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv)
2133 TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv);
2135 if (!ppv) return E_INVALIDARG;
2137 if (IsEqualIID(&IID_IUnknown, iid) ||
2138 IsEqualIID(&IID_IWICBitmapEncoder, iid))
2140 IWICBitmapEncoder_AddRef(iface);
2141 *ppv = iface;
2142 return S_OK;
2145 *ppv = NULL;
2146 return E_NOINTERFACE;
2149 static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface)
2151 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2152 ULONG ref = InterlockedIncrement(&This->ref);
2154 TRACE("%p -> %lu\n", iface, ref);
2155 return ref;
2158 static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface)
2160 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2161 ULONG ref = InterlockedDecrement(&This->ref);
2163 TRACE("%p -> %lu\n", iface, ref);
2165 if (!ref)
2167 if (This->stream) IStream_Release(This->stream);
2168 This->lock.DebugInfo->Spare[0] = 0;
2169 DeleteCriticalSection(&This->lock);
2170 HeapFree(GetProcessHeap(), 0, This);
2173 return ref;
2176 static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option)
2178 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2179 HRESULT hr;
2181 TRACE("%p,%p,%#x\n", iface, stream, option);
2183 if (!stream) return E_INVALIDARG;
2185 EnterCriticalSection(&This->lock);
2187 if (!This->initialized)
2189 IStream_AddRef(stream);
2190 This->stream = stream;
2191 This->initialized = TRUE;
2192 hr = S_OK;
2194 else
2195 hr = WINCODEC_ERR_WRONGSTATE;
2197 LeaveCriticalSection(&This->lock);
2199 return hr;
2202 static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format)
2204 if (!format) return E_INVALIDARG;
2206 *format = GUID_ContainerFormatGif;
2207 return S_OK;
2210 static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info)
2212 IWICComponentInfo *comp_info;
2213 HRESULT hr;
2215 TRACE("%p,%p\n", iface, info);
2217 if (!info) return E_INVALIDARG;
2219 hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info);
2220 if (hr == S_OK)
2222 hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info);
2223 IWICComponentInfo_Release(comp_info);
2225 return hr;
2228 static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context)
2230 FIXME("%p,%u,%p: stub\n", iface, count, context);
2231 return E_NOTIMPL;
2234 static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette)
2236 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2237 HRESULT hr;
2239 TRACE("%p,%p\n", iface, palette);
2241 if (!palette) return E_INVALIDARG;
2243 EnterCriticalSection(&This->lock);
2245 if (This->initialized)
2246 hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors);
2247 else
2248 hr = WINCODEC_ERR_NOTINITIALIZED;
2250 LeaveCriticalSection(&This->lock);
2251 return hr;
2254 static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail)
2256 TRACE("%p,%p\n", iface, thumbnail);
2257 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2260 static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview)
2262 TRACE("%p,%p\n", iface, preview);
2263 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
2266 static HRESULT WINAPI GifEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter *iface, REFIID iid, void **ppv)
2268 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2270 return IWICBitmapFrameEncode_QueryInterface(&frame_encoder->IWICBitmapFrameEncode_iface, iid, ppv);
2273 static ULONG WINAPI GifEncoderFrame_Block_AddRef(IWICMetadataBlockWriter *iface)
2275 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2277 return IWICBitmapFrameEncode_AddRef(&frame_encoder->IWICBitmapFrameEncode_iface);
2280 static ULONG WINAPI GifEncoderFrame_Block_Release(IWICMetadataBlockWriter *iface)
2282 GifFrameEncode *frame_encoder = impl_from_IWICMetadataBlockWriter(iface);
2284 return IWICBitmapFrameEncode_Release(&frame_encoder->IWICBitmapFrameEncode_iface);
2287 static HRESULT WINAPI GifEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter *iface, GUID *container_format)
2289 FIXME("iface %p, container_format %p stub.\n", iface, container_format);
2291 return E_NOTIMPL;
2294 static HRESULT WINAPI GifEncoderFrame_Block_GetCount(IWICMetadataBlockWriter *iface, UINT *count)
2296 FIXME("iface %p, count %p stub.\n", iface, count);
2298 return E_NOTIMPL;
2301 static HRESULT WINAPI GifEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter *iface,
2302 UINT index, IWICMetadataReader **metadata_reader)
2304 FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface, index, metadata_reader);
2306 return E_NOTIMPL;
2309 static HRESULT WINAPI GifEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter *iface, IEnumUnknown **enum_metadata)
2311 FIXME("iface %p, enum_metadata %p stub.\n", iface, enum_metadata);
2313 return E_NOTIMPL;
2316 static HRESULT WINAPI GifEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter *iface,
2317 IWICMetadataBlockReader *block_reader)
2319 FIXME("iface %p, block_reader %p stub.\n", iface, block_reader);
2321 return E_NOTIMPL;
2324 static HRESULT WINAPI GifEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
2325 IWICMetadataWriter **metadata_writer)
2327 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
2329 return E_NOTIMPL;
2332 static HRESULT WINAPI GifEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter *iface, IWICMetadataWriter *metadata_writer)
2334 FIXME("iface %p, metadata_writer %p stub.\n", iface, metadata_writer);
2336 return E_NOTIMPL;
2339 static HRESULT WINAPI GifEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter *iface, UINT index,
2340 IWICMetadataWriter *metadata_writer)
2342 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface, index, metadata_writer);
2344 return E_NOTIMPL;
2347 static HRESULT WINAPI GifEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter *iface, UINT index)
2349 FIXME("iface %p, index %u stub.\n", iface, index);
2351 return E_NOTIMPL;
2354 static const IWICMetadataBlockWriterVtbl GifFrameEncode_BlockVtbl = {
2355 GifEncoderFrame_Block_QueryInterface,
2356 GifEncoderFrame_Block_AddRef,
2357 GifEncoderFrame_Block_Release,
2358 GifEncoderFrame_Block_GetContainerFormat,
2359 GifEncoderFrame_Block_GetCount,
2360 GifEncoderFrame_Block_GetReaderByIndex,
2361 GifEncoderFrame_Block_GetEnumerator,
2362 GifEncoderFrame_Block_InitializeFromBlockReader,
2363 GifEncoderFrame_Block_GetWriterByIndex,
2364 GifEncoderFrame_Block_AddWriter,
2365 GifEncoderFrame_Block_SetWriterByIndex,
2366 GifEncoderFrame_Block_RemoveWriterByIndex,
2369 static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options)
2371 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2372 HRESULT hr;
2374 TRACE("%p,%p,%p\n", iface, frame, options);
2376 if (!frame) return E_INVALIDARG;
2378 EnterCriticalSection(&This->lock);
2380 if (This->initialized && !This->committed)
2382 GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret));
2383 if (ret)
2385 This->n_frames++;
2387 ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl;
2388 ret->IWICMetadataBlockWriter_iface.lpVtbl = &GifFrameEncode_BlockVtbl;
2390 ret->ref = 1;
2391 ret->encoder = This;
2392 ret->initialized = FALSE;
2393 ret->interlace = FALSE; /* FIXME: read from the properties */
2394 ret->committed = FALSE;
2395 ret->width = 0;
2396 ret->height = 0;
2397 ret->lines = 0;
2398 ret->xres = 0.0;
2399 ret->yres = 0.0;
2400 ret->colors = 0;
2401 ret->image_data = NULL;
2402 IWICBitmapEncoder_AddRef(iface);
2403 *frame = &ret->IWICBitmapFrameEncode_iface;
2405 hr = S_OK;
2407 if (options)
2409 hr = CreatePropertyBag2(NULL, 0, options);
2410 if (hr != S_OK)
2412 IWICBitmapFrameEncode_Release(*frame);
2413 *frame = NULL;
2417 else
2418 hr = E_OUTOFMEMORY;
2420 else
2421 hr = WINCODEC_ERR_WRONGSTATE;
2423 LeaveCriticalSection(&This->lock);
2425 return hr;
2429 static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface)
2431 GifEncoder *This = impl_from_IWICBitmapEncoder(iface);
2432 HRESULT hr;
2434 TRACE("%p\n", iface);
2436 EnterCriticalSection(&This->lock);
2438 if (This->initialized && !This->committed)
2440 char gif_trailer = 0x3b;
2442 /* FIXME: write text, comment GIF extensions */
2444 hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL);
2445 if (hr == S_OK)
2446 This->committed = TRUE;
2448 else
2449 hr = WINCODEC_ERR_WRONGSTATE;
2451 LeaveCriticalSection(&This->lock);
2452 return hr;
2455 static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer)
2457 FIXME("%p,%p: stub\n", iface, writer);
2458 return E_NOTIMPL;
2461 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl =
2463 GifEncoder_QueryInterface,
2464 GifEncoder_AddRef,
2465 GifEncoder_Release,
2466 GifEncoder_Initialize,
2467 GifEncoder_GetContainerFormat,
2468 GifEncoder_GetEncoderInfo,
2469 GifEncoder_SetColorContexts,
2470 GifEncoder_SetPalette,
2471 GifEncoder_SetThumbnail,
2472 GifEncoder_SetPreview,
2473 GifEncoder_CreateNewFrame,
2474 GifEncoder_Commit,
2475 GifEncoder_GetMetadataQueryWriter
2478 HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv)
2480 GifEncoder *This;
2481 HRESULT ret;
2483 TRACE("%s,%p\n", debugstr_guid(iid), ppv);
2485 *ppv = NULL;
2487 This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
2488 if (!This) return E_OUTOFMEMORY;
2490 This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl;
2491 This->ref = 1;
2492 This->stream = NULL;
2493 InitializeCriticalSection(&This->lock);
2494 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock");
2495 This->initialized = FALSE;
2496 This->info_written = FALSE;
2497 This->committed = FALSE;
2498 This->n_frames = 0;
2499 This->colors = 0;
2501 ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
2502 IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
2504 return ret;