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