2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012 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 "wincodecs_private.h"
26 static LPWSTR
strdupAtoW(const char *src
)
28 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
29 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
30 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
34 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
35 MetadataItem
**items
, DWORD
*count
)
38 struct logical_screen_descriptor
44 /* global_color_table_flag : 1;
45 * color_resolution : 3;
47 * global_color_table_size : 3;
49 BYTE background_color_index
;
50 BYTE pixel_aspect_ratio
;
60 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
61 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
63 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 9);
64 if (!result
) return E_OUTOFMEMORY
;
66 for (i
= 0; i
< 9; i
++)
68 PropVariantInit(&result
[i
].schema
);
69 PropVariantInit(&result
[i
].id
);
70 PropVariantInit(&result
[i
].value
);
73 result
[0].id
.vt
= VT_LPWSTR
;
74 result
[0].id
.u
.pwszVal
= strdupAtoW("Signature");
75 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
76 result
[0].value
.u
.caub
.cElems
= sizeof(lsd_data
.signature
);
77 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
78 memcpy(result
[0].value
.u
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
80 result
[1].id
.vt
= VT_LPWSTR
;
81 result
[1].id
.u
.pwszVal
= strdupAtoW("Width");
82 result
[1].value
.vt
= VT_UI2
;
83 result
[1].value
.u
.uiVal
= lsd_data
.width
;
85 result
[2].id
.vt
= VT_LPWSTR
;
86 result
[2].id
.u
.pwszVal
= strdupAtoW("Height");
87 result
[2].value
.vt
= VT_UI2
;
88 result
[2].value
.u
.uiVal
= lsd_data
.height
;
90 result
[3].id
.vt
= VT_LPWSTR
;
91 result
[3].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
92 result
[3].value
.vt
= VT_BOOL
;
93 result
[3].value
.u
.boolVal
= (lsd_data
.packed
>> 7) & 1;
95 result
[4].id
.vt
= VT_LPWSTR
;
96 result
[4].id
.u
.pwszVal
= strdupAtoW("ColorResolution");
97 result
[4].value
.vt
= VT_UI1
;
98 result
[4].value
.u
.bVal
= (lsd_data
.packed
>> 4) & 7;
100 result
[5].id
.vt
= VT_LPWSTR
;
101 result
[5].id
.u
.pwszVal
= strdupAtoW("SortFlag");
102 result
[5].value
.vt
= VT_BOOL
;
103 result
[5].value
.u
.boolVal
= (lsd_data
.packed
>> 3) & 1;
105 result
[6].id
.vt
= VT_LPWSTR
;
106 result
[6].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableSize");
107 result
[6].value
.vt
= VT_UI1
;
108 result
[6].value
.u
.bVal
= lsd_data
.packed
& 7;
110 result
[7].id
.vt
= VT_LPWSTR
;
111 result
[7].id
.u
.pwszVal
= strdupAtoW("BackgroundColorIndex");
112 result
[7].value
.vt
= VT_UI1
;
113 result
[7].value
.u
.bVal
= lsd_data
.background_color_index
;
115 result
[8].id
.vt
= VT_LPWSTR
;
116 result
[8].id
.u
.pwszVal
= strdupAtoW("PixelAspectRatio");
117 result
[8].value
.vt
= VT_UI1
;
118 result
[8].value
.u
.bVal
= lsd_data
.pixel_aspect_ratio
;
126 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
128 &CLSID_WICLSDMetadataReader
,
132 HRESULT
LSDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
134 return MetadataReader_Create(&LSDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
137 #include "pshpack1.h"
138 struct image_descriptor
145 /* local_color_table_flag : 1;
146 * interlace_flag : 1;
149 * local_color_table_size : 3;
154 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
155 MetadataItem
**items
, DWORD
*count
)
157 struct image_descriptor imd_data
;
160 MetadataItem
*result
;
165 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
166 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
168 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 8);
169 if (!result
) return E_OUTOFMEMORY
;
171 for (i
= 0; i
< 8; i
++)
173 PropVariantInit(&result
[i
].schema
);
174 PropVariantInit(&result
[i
].id
);
175 PropVariantInit(&result
[i
].value
);
178 result
[0].id
.vt
= VT_LPWSTR
;
179 result
[0].id
.u
.pwszVal
= strdupAtoW("Left");
180 result
[0].value
.vt
= VT_UI2
;
181 result
[0].value
.u
.uiVal
= imd_data
.left
;
183 result
[1].id
.vt
= VT_LPWSTR
;
184 result
[1].id
.u
.pwszVal
= strdupAtoW("Top");
185 result
[1].value
.vt
= VT_UI2
;
186 result
[1].value
.u
.uiVal
= imd_data
.top
;
188 result
[2].id
.vt
= VT_LPWSTR
;
189 result
[2].id
.u
.pwszVal
= strdupAtoW("Width");
190 result
[2].value
.vt
= VT_UI2
;
191 result
[2].value
.u
.uiVal
= imd_data
.width
;
193 result
[3].id
.vt
= VT_LPWSTR
;
194 result
[3].id
.u
.pwszVal
= strdupAtoW("Height");
195 result
[3].value
.vt
= VT_UI2
;
196 result
[3].value
.u
.uiVal
= imd_data
.height
;
198 result
[4].id
.vt
= VT_LPWSTR
;
199 result
[4].id
.u
.pwszVal
= strdupAtoW("LocalColorTableFlag");
200 result
[4].value
.vt
= VT_BOOL
;
201 result
[4].value
.u
.boolVal
= (imd_data
.packed
>> 7) & 1;
203 result
[5].id
.vt
= VT_LPWSTR
;
204 result
[5].id
.u
.pwszVal
= strdupAtoW("InterlaceFlag");
205 result
[5].value
.vt
= VT_BOOL
;
206 result
[5].value
.u
.boolVal
= (imd_data
.packed
>> 6) & 1;
208 result
[6].id
.vt
= VT_LPWSTR
;
209 result
[6].id
.u
.pwszVal
= strdupAtoW("SortFlag");
210 result
[6].value
.vt
= VT_BOOL
;
211 result
[6].value
.u
.boolVal
= (imd_data
.packed
>> 5) & 1;
213 result
[7].id
.vt
= VT_LPWSTR
;
214 result
[7].id
.u
.pwszVal
= strdupAtoW("LocalColorTableSize");
215 result
[7].value
.vt
= VT_UI1
;
216 result
[7].value
.u
.bVal
= imd_data
.packed
& 7;
224 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
226 &CLSID_WICIMDMetadataReader
,
230 HRESULT
IMDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
232 return MetadataReader_Create(&IMDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
235 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
236 MetadataItem
**items
, DWORD
*count
)
238 #include "pshpack1.h"
239 struct graphic_control_extenstion
244 * user_input_flag : 1;
245 * transparency_flag : 1;
248 BYTE transparent_color_index
;
253 MetadataItem
*result
;
258 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
259 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
261 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 5);
262 if (!result
) return E_OUTOFMEMORY
;
264 for (i
= 0; i
< 5; i
++)
266 PropVariantInit(&result
[i
].schema
);
267 PropVariantInit(&result
[i
].id
);
268 PropVariantInit(&result
[i
].value
);
271 result
[0].id
.vt
= VT_LPWSTR
;
272 result
[0].id
.u
.pwszVal
= strdupAtoW("Disposal");
273 result
[0].value
.vt
= VT_UI1
;
274 result
[0].value
.u
.bVal
= (gce_data
.packed
>> 2) & 7;
276 result
[1].id
.vt
= VT_LPWSTR
;
277 result
[1].id
.u
.pwszVal
= strdupAtoW("UserInputFlag");
278 result
[1].value
.vt
= VT_BOOL
;
279 result
[1].value
.u
.boolVal
= (gce_data
.packed
>> 1) & 1;
281 result
[2].id
.vt
= VT_LPWSTR
;
282 result
[2].id
.u
.pwszVal
= strdupAtoW("TransparencyFlag");
283 result
[2].value
.vt
= VT_BOOL
;
284 result
[2].value
.u
.boolVal
= gce_data
.packed
& 1;
286 result
[3].id
.vt
= VT_LPWSTR
;
287 result
[3].id
.u
.pwszVal
= strdupAtoW("Delay");
288 result
[3].value
.vt
= VT_UI2
;
289 result
[3].value
.u
.uiVal
= gce_data
.delay
;
291 result
[4].id
.vt
= VT_LPWSTR
;
292 result
[4].id
.u
.pwszVal
= strdupAtoW("TransparentColorIndex");
293 result
[4].value
.vt
= VT_UI1
;
294 result
[4].value
.u
.bVal
= gce_data
.transparent_color_index
;
302 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
304 &CLSID_WICGCEMetadataReader
,
308 HRESULT
GCEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
310 return MetadataReader_Create(&GCEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
313 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
314 MetadataItem
**items
, DWORD
*count
)
316 #include "pshpack1.h"
317 struct application_extenstion
319 BYTE extension_introducer
;
320 BYTE extension_label
;
322 BYTE application
[11];
326 ULONG bytesread
, data_size
, i
;
327 MetadataItem
*result
;
334 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
335 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
336 if (ape_data
.extension_introducer
!= 0x21 ||
337 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
338 ape_data
.block_size
!= 11)
346 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
347 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
349 HeapFree(GetProcessHeap(), 0, data
);
352 if (!subblock_size
) break;
355 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
358 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
361 HeapFree(GetProcessHeap(), 0, data
);
366 data
[data_size
] = subblock_size
;
367 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
368 if (FAILED(hr
) || bytesread
!= subblock_size
)
370 HeapFree(GetProcessHeap(), 0, data
);
373 data_size
+= subblock_size
+ 1;
376 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 2);
379 HeapFree(GetProcessHeap(), 0, data
);
380 return E_OUTOFMEMORY
;
383 for (i
= 0; i
< 2; i
++)
385 PropVariantInit(&result
[i
].schema
);
386 PropVariantInit(&result
[i
].id
);
387 PropVariantInit(&result
[i
].value
);
390 result
[0].id
.vt
= VT_LPWSTR
;
391 result
[0].id
.u
.pwszVal
= strdupAtoW("Application");
392 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
393 result
[0].value
.u
.caub
.cElems
= sizeof(ape_data
.application
);
394 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
395 memcpy(result
[0].value
.u
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
397 result
[1].id
.vt
= VT_LPWSTR
;
398 result
[1].id
.u
.pwszVal
= strdupAtoW("Data");
399 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
400 result
[1].value
.u
.caub
.cElems
= data_size
;
401 result
[1].value
.u
.caub
.pElems
= data
;
409 static const MetadataHandlerVtbl APEReader_Vtbl
= {
411 &CLSID_WICAPEMetadataReader
,
415 HRESULT
APEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
417 return MetadataReader_Create(&APEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
420 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
421 MetadataItem
**items
, DWORD
*count
)
423 #include "pshpack1.h"
424 struct gif_extenstion
426 BYTE extension_introducer
;
427 BYTE extension_label
;
431 ULONG bytesread
, data_size
;
432 MetadataItem
*result
;
439 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
440 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
441 if (ext_data
.extension_introducer
!= 0x21 ||
442 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
450 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
451 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
453 HeapFree(GetProcessHeap(), 0, data
);
456 if (!subblock_size
) break;
459 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
462 char *new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
465 HeapFree(GetProcessHeap(), 0, data
);
470 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
471 if (FAILED(hr
) || bytesread
!= subblock_size
)
473 HeapFree(GetProcessHeap(), 0, data
);
476 data_size
+= subblock_size
;
481 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
));
484 HeapFree(GetProcessHeap(), 0, data
);
485 return E_OUTOFMEMORY
;
488 PropVariantInit(&result
->schema
);
489 PropVariantInit(&result
->id
);
490 PropVariantInit(&result
->value
);
492 result
->id
.vt
= VT_LPWSTR
;
493 result
->id
.u
.pwszVal
= strdupAtoW("TextEntry");
494 result
->value
.vt
= VT_LPSTR
;
495 result
->value
.u
.pszVal
= data
;
503 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
505 &CLSID_WICGifCommentMetadataReader
,
506 load_GifComment_metadata
509 HRESULT
GifCommentReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
511 return MetadataReader_Create(&GifCommentReader_Vtbl
, pUnkOuter
, iid
, ppv
);
514 static IStream
*create_stream(const void *data
, int data_size
)
521 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
522 if (!hdata
) return NULL
;
524 locked_data
= GlobalLock(hdata
);
525 memcpy(locked_data
, data
, data_size
);
528 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
529 return FAILED(hr
) ? NULL
: stream
;
532 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
533 const CLSID
*clsid
, IWICMetadataReader
**reader
)
536 IWICMetadataReader
*metadata_reader
;
537 IWICPersistStream
*persist
;
540 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
542 hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
,
543 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
544 if (FAILED(hr
)) return hr
;
546 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
549 IWICMetadataReader_Release(metadata_reader
);
553 stream
= create_stream(data
, data_size
);
554 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
555 IStream_Release(stream
);
557 IWICPersistStream_Release(persist
);
559 *reader
= metadata_reader
;
564 IWICBitmapDecoder IWICBitmapDecoder_iface
;
565 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
566 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
571 CRITICAL_SECTION lock
;
575 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
576 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
582 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
584 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
587 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
589 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
592 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
594 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
597 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
599 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
602 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
605 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
606 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
608 if (!ppv
) return E_INVALIDARG
;
610 if (IsEqualIID(&IID_IUnknown
, iid
) ||
611 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
612 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
614 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
616 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
618 *ppv
= &This
->IWICMetadataBlockReader_iface
;
623 return E_NOINTERFACE
;
626 IUnknown_AddRef((IUnknown
*)*ppv
);
630 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
632 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
633 ULONG ref
= InterlockedIncrement(&This
->ref
);
635 TRACE("(%p) refcount=%u\n", iface
, ref
);
640 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
642 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
643 ULONG ref
= InterlockedDecrement(&This
->ref
);
645 TRACE("(%p) refcount=%u\n", iface
, ref
);
649 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
650 HeapFree(GetProcessHeap(), 0, This
);
656 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
657 UINT
*puiWidth
, UINT
*puiHeight
)
659 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
660 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
662 *puiWidth
= This
->frame
->ImageDesc
.Width
;
663 *puiHeight
= This
->frame
->ImageDesc
.Height
;
668 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
669 WICPixelFormatGUID
*pPixelFormat
)
671 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
676 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
677 double *pDpiX
, double *pDpiY
)
679 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
680 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
681 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
682 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
684 *pDpiX
= 96.0 / aspect
;
690 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
691 IWICPalette
*pIPalette
)
693 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
694 WICColor colors
[256];
695 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
698 TRACE("(%p,%p)\n", iface
, pIPalette
);
700 if (!cm
) cm
= This
->parent
->gif
->SColorMap
;
702 if (cm
->ColorCount
> 256)
704 ERR("GIF contains %i colors???\n", cm
->ColorCount
);
708 for (i
= 0; i
< cm
->ColorCount
; i
++) {
709 colors
[i
] = 0xff000000| /* alpha */
710 cm
->Colors
[i
].Red
<< 16|
711 cm
->Colors
[i
].Green
<< 8|
715 /* look for the transparent color extension */
716 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; ++i
) {
717 eb
= This
->frame
->Extensions
.ExtensionBlocks
+ i
;
718 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8) {
719 if (eb
->Bytes
[3] & 1) {
720 trans
= (unsigned char)eb
->Bytes
[6];
721 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
727 return IWICPalette_InitializeCustom(pIPalette
, colors
, cm
->ColorCount
);
730 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
731 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
732 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
734 UINT row_offset
; /* number of bytes into the source rows where the data starts */
744 rect
.Width
= srcwidth
;
745 rect
.Height
= srcheight
;
750 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
754 if (dststride
< rc
->Width
)
757 if ((dststride
* rc
->Height
) > dstbuffersize
)
763 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
766 src
= srcbuffer
+ srcstride
* (y
/8);
768 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
770 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
772 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
774 memcpy(dst
, src
, rc
->Width
);
780 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
781 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
783 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
784 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
786 if (This
->frame
->ImageDesc
.Interlace
)
788 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
789 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
790 prc
, cbStride
, cbBufferSize
, pbBuffer
);
794 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
795 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
796 prc
, cbStride
, cbBufferSize
, pbBuffer
);
800 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
801 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
803 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
804 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
807 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
808 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
810 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
811 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
814 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
815 IWICBitmapSource
**ppIThumbnail
)
817 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
818 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
821 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
822 GifFrameDecode_QueryInterface
,
823 GifFrameDecode_AddRef
,
824 GifFrameDecode_Release
,
825 GifFrameDecode_GetSize
,
826 GifFrameDecode_GetPixelFormat
,
827 GifFrameDecode_GetResolution
,
828 GifFrameDecode_CopyPalette
,
829 GifFrameDecode_CopyPixels
,
830 GifFrameDecode_GetMetadataQueryReader
,
831 GifFrameDecode_GetColorContexts
,
832 GifFrameDecode_GetThumbnail
835 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
836 REFIID iid
, void **ppv
)
838 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
839 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
842 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
844 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
845 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
848 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
850 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
851 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
854 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
857 TRACE("(%p,%p)\n", iface
, guid
);
859 if (!guid
) return E_INVALIDARG
;
861 *guid
= GUID_ContainerFormatGif
;
865 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
868 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
870 TRACE("%p,%p\n", iface
, count
);
872 if (!count
) return E_INVALIDARG
;
874 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
878 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
881 IWICMetadataReader
*metadata_reader
;
882 IWICPersistStream
*persist
;
884 struct image_descriptor IMD_data
;
886 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
888 hr
= CoCreateInstance(&CLSID_WICIMDMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
889 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
890 if (FAILED(hr
)) return hr
;
892 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
895 IWICMetadataReader_Release(metadata_reader
);
899 /* recreate IMD structure from GIF decoder data */
900 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
901 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
902 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
903 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
906 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
907 if (This
->frame
->ImageDesc
.ColorMap
)
909 /* local_color_table_flag */
910 IMD_data
.packed
|= 1 << 7;
911 /* local_color_table_size */
912 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
914 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
917 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
918 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
919 IStream_Release(stream
);
921 IWICPersistStream_Release(persist
);
923 *reader
= metadata_reader
;
927 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
928 UINT index
, IWICMetadataReader
**reader
)
930 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
931 int i
, gce_index
= -1, gce_skipped
= 0;
933 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
935 if (!reader
) return E_INVALIDARG
;
938 return create_IMD_metadata_reader(This
, reader
);
940 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
943 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; i
++)
949 if (index
!= i
+ 1 - gce_skipped
) continue;
951 if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== GRAPHICS_EXT_FUNC_CODE
)
957 else if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
959 clsid
= &CLSID_WICGifCommentMetadataReader
;
960 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
961 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
965 clsid
= &CLSID_WICUnknownMetadataReader
;
966 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
967 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
969 return create_metadata_reader(data
, data_size
, clsid
, reader
);
972 if (gce_index
== -1) return E_INVALIDARG
;
974 return create_metadata_reader(This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].Bytes
+ 3,
975 This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].ByteCount
- 4,
976 &CLSID_WICGCEMetadataReader
, reader
);
979 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
980 IEnumUnknown
**enumerator
)
982 FIXME("(%p,%p): stub\n", iface
, enumerator
);
986 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
988 GifFrameDecode_Block_QueryInterface
,
989 GifFrameDecode_Block_AddRef
,
990 GifFrameDecode_Block_Release
,
991 GifFrameDecode_Block_GetContainerFormat
,
992 GifFrameDecode_Block_GetCount
,
993 GifFrameDecode_Block_GetReaderByIndex
,
994 GifFrameDecode_Block_GetEnumerator
997 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1000 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1001 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1003 if (!ppv
) return E_INVALIDARG
;
1005 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1006 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1008 *ppv
= &This
->IWICBitmapDecoder_iface
;
1010 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1012 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1017 return E_NOINTERFACE
;
1020 IUnknown_AddRef((IUnknown
*)*ppv
);
1024 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1026 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1027 ULONG ref
= InterlockedIncrement(&This
->ref
);
1029 TRACE("(%p) refcount=%u\n", iface
, ref
);
1034 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1036 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1037 ULONG ref
= InterlockedDecrement(&This
->ref
);
1039 TRACE("(%p) refcount=%u\n", iface
, ref
);
1043 This
->lock
.DebugInfo
->Spare
[0] = 0;
1044 DeleteCriticalSection(&This
->lock
);
1045 DGifCloseFile(This
->gif
);
1046 HeapFree(GetProcessHeap(), 0, This
);
1052 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1057 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1059 if (!stream
|| !capability
) return E_INVALIDARG
;
1061 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1062 if (hr
!= S_OK
) return hr
;
1064 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1065 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1066 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1070 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1071 IStream
*stream
= gif
->UserData
;
1077 ERR("attempting to read file after initialization\n");
1081 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1082 if (hr
!= S_OK
) bytesread
= 0;
1086 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1087 WICDecodeOptions cacheOptions
)
1089 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1093 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1095 EnterCriticalSection(&This
->lock
);
1097 if (This
->initialized
|| This
->gif
)
1099 WARN("already initialized\n");
1100 LeaveCriticalSection(&This
->lock
);
1101 return WINCODEC_ERR_WRONGSTATE
;
1104 /* seek to start of stream */
1106 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1108 /* read all data from the stream */
1109 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1112 LeaveCriticalSection(&This
->lock
);
1116 ret
= DGifSlurp(This
->gif
);
1117 if (ret
== GIF_ERROR
)
1119 LeaveCriticalSection(&This
->lock
);
1123 /* make sure we don't use the stream after this method returns */
1124 This
->gif
->UserData
= NULL
;
1127 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1128 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1130 This
->initialized
= TRUE
;
1132 LeaveCriticalSection(&This
->lock
);
1137 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1138 GUID
*pguidContainerFormat
)
1140 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1144 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1145 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1148 IWICComponentInfo
*compinfo
;
1150 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1152 hr
= CreateComponentInfo(&CLSID_WICGifDecoder
, &compinfo
);
1153 if (FAILED(hr
)) return hr
;
1155 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1156 (void**)ppIDecoderInfo
);
1158 IWICComponentInfo_Release(compinfo
);
1163 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1165 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1166 WICColor colors
[256];
1168 int i
, trans
, count
;
1171 TRACE("(%p,%p)\n", iface
, palette
);
1173 cm
= This
->gif
->SColorMap
;
1176 if (cm
->ColorCount
> 256)
1178 ERR("GIF contains invalid number of colors: %d\n", cm
->ColorCount
);
1182 for (i
= 0; i
< cm
->ColorCount
; i
++)
1184 colors
[i
] = 0xff000000 | /* alpha */
1185 cm
->Colors
[i
].Red
<< 16 |
1186 cm
->Colors
[i
].Green
<< 8 |
1190 count
= cm
->ColorCount
;
1194 colors
[0] = 0xff000000;
1195 colors
[1] = 0xffffffff;
1197 for (i
= 2; i
< 256; i
++)
1198 colors
[i
] = 0xff000000;
1203 /* look for the transparent color extension */
1204 for (i
= 0; i
< This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlockCount
; i
++)
1206 eb
= This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlocks
+ i
;
1207 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8)
1209 if (eb
->Bytes
[3] & 1)
1211 trans
= (unsigned char)eb
->Bytes
[6];
1212 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
1218 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1221 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1222 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1224 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1225 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1228 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1229 IWICBitmapSource
**ppIBitmapSource
)
1231 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1232 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1235 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1236 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1238 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1239 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1242 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1243 IWICBitmapSource
**ppIThumbnail
)
1245 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1246 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1249 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1252 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1254 if (!pCount
) return E_INVALIDARG
;
1256 EnterCriticalSection(&This
->lock
);
1257 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1258 LeaveCriticalSection(&This
->lock
);
1260 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1265 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1266 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1268 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1269 GifFrameDecode
*result
;
1270 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1272 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1274 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1276 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1277 if (!result
) return E_OUTOFMEMORY
;
1279 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1280 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1282 result
->frame
= &This
->gif
->SavedImages
[index
];
1283 IWICBitmapDecoder_AddRef(iface
);
1284 result
->parent
= This
;
1285 This
->current_frame
= index
;
1287 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1292 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1293 GifDecoder_QueryInterface
,
1296 GifDecoder_QueryCapability
,
1297 GifDecoder_Initialize
,
1298 GifDecoder_GetContainerFormat
,
1299 GifDecoder_GetDecoderInfo
,
1300 GifDecoder_CopyPalette
,
1301 GifDecoder_GetMetadataQueryReader
,
1302 GifDecoder_GetPreview
,
1303 GifDecoder_GetColorContexts
,
1304 GifDecoder_GetThumbnail
,
1305 GifDecoder_GetFrameCount
,
1309 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1310 REFIID iid
, void **ppv
)
1312 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1313 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1316 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1318 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1319 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1322 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1324 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1325 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1328 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1331 TRACE("(%p,%p)\n", iface
, guid
);
1333 if (!guid
) return E_INVALIDARG
;
1335 *guid
= GUID_ContainerFormatGif
;
1339 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1342 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1344 TRACE("%p,%p\n", iface
, count
);
1346 if (!count
) return E_INVALIDARG
;
1348 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1352 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1353 UINT index
, IWICMetadataReader
**reader
)
1355 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1358 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1360 if (!reader
) return E_INVALIDARG
;
1363 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1364 &CLSID_WICLSDMetadataReader
, reader
);
1366 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1370 if (index
!= i
+ 1) continue;
1372 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1373 clsid
= &CLSID_WICAPEMetadataReader
;
1374 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1375 clsid
= &CLSID_WICGifCommentMetadataReader
;
1377 clsid
= &CLSID_WICUnknownMetadataReader
;
1379 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1380 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1384 return E_INVALIDARG
;
1387 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1388 IEnumUnknown
**enumerator
)
1390 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1394 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1396 GifDecoder_Block_QueryInterface
,
1397 GifDecoder_Block_AddRef
,
1398 GifDecoder_Block_Release
,
1399 GifDecoder_Block_GetContainerFormat
,
1400 GifDecoder_Block_GetCount
,
1401 GifDecoder_Block_GetReaderByIndex
,
1402 GifDecoder_Block_GetEnumerator
1405 HRESULT
GifDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1410 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1414 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1416 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1417 if (!This
) return E_OUTOFMEMORY
;
1419 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1420 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1422 This
->initialized
= FALSE
;
1424 This
->current_frame
= 0;
1425 InitializeCriticalSection(&This
->lock
);
1426 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1428 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1429 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);