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 #define WIN32_NO_STATUS
22 #define COM_NO_WINDOWS_H
29 #define NONAMELESSUNION
35 //#include "wincodec.h"
36 #include <wincodecsdk.h>
40 #include "wincodecs_private.h"
42 #include <wine/debug.h>
44 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
46 static LPWSTR
strdupAtoW(const char *src
)
48 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
49 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
50 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
54 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
55 MetadataItem
**items
, DWORD
*count
)
58 struct logical_screen_descriptor
64 /* global_color_table_flag : 1;
65 * color_resolution : 3;
67 * global_color_table_size : 3;
69 BYTE background_color_index
;
70 BYTE pixel_aspect_ratio
;
80 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
81 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
83 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 9);
84 if (!result
) return E_OUTOFMEMORY
;
86 for (i
= 0; i
< 9; i
++)
88 PropVariantInit(&result
[i
].schema
);
89 PropVariantInit(&result
[i
].id
);
90 PropVariantInit(&result
[i
].value
);
93 result
[0].id
.vt
= VT_LPWSTR
;
94 result
[0].id
.u
.pwszVal
= strdupAtoW("Signature");
95 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
96 result
[0].value
.u
.caub
.cElems
= sizeof(lsd_data
.signature
);
97 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
98 memcpy(result
[0].value
.u
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
100 result
[1].id
.vt
= VT_LPWSTR
;
101 result
[1].id
.u
.pwszVal
= strdupAtoW("Width");
102 result
[1].value
.vt
= VT_UI2
;
103 result
[1].value
.u
.uiVal
= lsd_data
.width
;
105 result
[2].id
.vt
= VT_LPWSTR
;
106 result
[2].id
.u
.pwszVal
= strdupAtoW("Height");
107 result
[2].value
.vt
= VT_UI2
;
108 result
[2].value
.u
.uiVal
= lsd_data
.height
;
110 result
[3].id
.vt
= VT_LPWSTR
;
111 result
[3].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
112 result
[3].value
.vt
= VT_BOOL
;
113 result
[3].value
.u
.boolVal
= (lsd_data
.packed
>> 7) & 1;
115 result
[4].id
.vt
= VT_LPWSTR
;
116 result
[4].id
.u
.pwszVal
= strdupAtoW("ColorResolution");
117 result
[4].value
.vt
= VT_UI1
;
118 result
[4].value
.u
.bVal
= (lsd_data
.packed
>> 4) & 7;
120 result
[5].id
.vt
= VT_LPWSTR
;
121 result
[5].id
.u
.pwszVal
= strdupAtoW("SortFlag");
122 result
[5].value
.vt
= VT_BOOL
;
123 result
[5].value
.u
.boolVal
= (lsd_data
.packed
>> 3) & 1;
125 result
[6].id
.vt
= VT_LPWSTR
;
126 result
[6].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableSize");
127 result
[6].value
.vt
= VT_UI1
;
128 result
[6].value
.u
.bVal
= lsd_data
.packed
& 7;
130 result
[7].id
.vt
= VT_LPWSTR
;
131 result
[7].id
.u
.pwszVal
= strdupAtoW("BackgroundColorIndex");
132 result
[7].value
.vt
= VT_UI1
;
133 result
[7].value
.u
.bVal
= lsd_data
.background_color_index
;
135 result
[8].id
.vt
= VT_LPWSTR
;
136 result
[8].id
.u
.pwszVal
= strdupAtoW("PixelAspectRatio");
137 result
[8].value
.vt
= VT_UI1
;
138 result
[8].value
.u
.bVal
= lsd_data
.pixel_aspect_ratio
;
146 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
148 &CLSID_WICLSDMetadataReader
,
152 HRESULT
LSDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
154 return MetadataReader_Create(&LSDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
157 #include "pshpack1.h"
158 struct image_descriptor
165 /* local_color_table_flag : 1;
166 * interlace_flag : 1;
169 * local_color_table_size : 3;
174 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
175 MetadataItem
**items
, DWORD
*count
)
177 struct image_descriptor imd_data
;
180 MetadataItem
*result
;
185 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
186 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
188 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 8);
189 if (!result
) return E_OUTOFMEMORY
;
191 for (i
= 0; i
< 8; i
++)
193 PropVariantInit(&result
[i
].schema
);
194 PropVariantInit(&result
[i
].id
);
195 PropVariantInit(&result
[i
].value
);
198 result
[0].id
.vt
= VT_LPWSTR
;
199 result
[0].id
.u
.pwszVal
= strdupAtoW("Left");
200 result
[0].value
.vt
= VT_UI2
;
201 result
[0].value
.u
.uiVal
= imd_data
.left
;
203 result
[1].id
.vt
= VT_LPWSTR
;
204 result
[1].id
.u
.pwszVal
= strdupAtoW("Top");
205 result
[1].value
.vt
= VT_UI2
;
206 result
[1].value
.u
.uiVal
= imd_data
.top
;
208 result
[2].id
.vt
= VT_LPWSTR
;
209 result
[2].id
.u
.pwszVal
= strdupAtoW("Width");
210 result
[2].value
.vt
= VT_UI2
;
211 result
[2].value
.u
.uiVal
= imd_data
.width
;
213 result
[3].id
.vt
= VT_LPWSTR
;
214 result
[3].id
.u
.pwszVal
= strdupAtoW("Height");
215 result
[3].value
.vt
= VT_UI2
;
216 result
[3].value
.u
.uiVal
= imd_data
.height
;
218 result
[4].id
.vt
= VT_LPWSTR
;
219 result
[4].id
.u
.pwszVal
= strdupAtoW("LocalColorTableFlag");
220 result
[4].value
.vt
= VT_BOOL
;
221 result
[4].value
.u
.boolVal
= (imd_data
.packed
>> 7) & 1;
223 result
[5].id
.vt
= VT_LPWSTR
;
224 result
[5].id
.u
.pwszVal
= strdupAtoW("InterlaceFlag");
225 result
[5].value
.vt
= VT_BOOL
;
226 result
[5].value
.u
.boolVal
= (imd_data
.packed
>> 6) & 1;
228 result
[6].id
.vt
= VT_LPWSTR
;
229 result
[6].id
.u
.pwszVal
= strdupAtoW("SortFlag");
230 result
[6].value
.vt
= VT_BOOL
;
231 result
[6].value
.u
.boolVal
= (imd_data
.packed
>> 5) & 1;
233 result
[7].id
.vt
= VT_LPWSTR
;
234 result
[7].id
.u
.pwszVal
= strdupAtoW("LocalColorTableSize");
235 result
[7].value
.vt
= VT_UI1
;
236 result
[7].value
.u
.bVal
= imd_data
.packed
& 7;
244 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
246 &CLSID_WICIMDMetadataReader
,
250 HRESULT
IMDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
252 return MetadataReader_Create(&IMDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
255 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
256 MetadataItem
**items
, DWORD
*count
)
258 #include "pshpack1.h"
259 struct graphic_control_extenstion
264 * user_input_flag : 1;
265 * transparency_flag : 1;
268 BYTE transparent_color_index
;
273 MetadataItem
*result
;
278 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
279 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
281 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 5);
282 if (!result
) return E_OUTOFMEMORY
;
284 for (i
= 0; i
< 5; i
++)
286 PropVariantInit(&result
[i
].schema
);
287 PropVariantInit(&result
[i
].id
);
288 PropVariantInit(&result
[i
].value
);
291 result
[0].id
.vt
= VT_LPWSTR
;
292 result
[0].id
.u
.pwszVal
= strdupAtoW("Disposal");
293 result
[0].value
.vt
= VT_UI1
;
294 result
[0].value
.u
.bVal
= (gce_data
.packed
>> 2) & 7;
296 result
[1].id
.vt
= VT_LPWSTR
;
297 result
[1].id
.u
.pwszVal
= strdupAtoW("UserInputFlag");
298 result
[1].value
.vt
= VT_BOOL
;
299 result
[1].value
.u
.boolVal
= (gce_data
.packed
>> 1) & 1;
301 result
[2].id
.vt
= VT_LPWSTR
;
302 result
[2].id
.u
.pwszVal
= strdupAtoW("TransparencyFlag");
303 result
[2].value
.vt
= VT_BOOL
;
304 result
[2].value
.u
.boolVal
= gce_data
.packed
& 1;
306 result
[3].id
.vt
= VT_LPWSTR
;
307 result
[3].id
.u
.pwszVal
= strdupAtoW("Delay");
308 result
[3].value
.vt
= VT_UI2
;
309 result
[3].value
.u
.uiVal
= gce_data
.delay
;
311 result
[4].id
.vt
= VT_LPWSTR
;
312 result
[4].id
.u
.pwszVal
= strdupAtoW("TransparentColorIndex");
313 result
[4].value
.vt
= VT_UI1
;
314 result
[4].value
.u
.bVal
= gce_data
.transparent_color_index
;
322 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
324 &CLSID_WICGCEMetadataReader
,
328 HRESULT
GCEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
330 return MetadataReader_Create(&GCEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
333 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
334 MetadataItem
**items
, DWORD
*count
)
336 #include "pshpack1.h"
337 struct application_extenstion
339 BYTE extension_introducer
;
340 BYTE extension_label
;
342 BYTE application
[11];
346 ULONG bytesread
, data_size
, i
;
347 MetadataItem
*result
;
354 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
355 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
356 if (ape_data
.extension_introducer
!= 0x21 ||
357 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
358 ape_data
.block_size
!= 11)
366 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
367 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
369 HeapFree(GetProcessHeap(), 0, data
);
372 if (!subblock_size
) break;
375 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
378 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
381 HeapFree(GetProcessHeap(), 0, data
);
386 data
[data_size
] = subblock_size
;
387 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
388 if (FAILED(hr
) || bytesread
!= subblock_size
)
390 HeapFree(GetProcessHeap(), 0, data
);
393 data_size
+= subblock_size
+ 1;
396 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 2);
399 HeapFree(GetProcessHeap(), 0, data
);
400 return E_OUTOFMEMORY
;
403 for (i
= 0; i
< 2; i
++)
405 PropVariantInit(&result
[i
].schema
);
406 PropVariantInit(&result
[i
].id
);
407 PropVariantInit(&result
[i
].value
);
410 result
[0].id
.vt
= VT_LPWSTR
;
411 result
[0].id
.u
.pwszVal
= strdupAtoW("Application");
412 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
413 result
[0].value
.u
.caub
.cElems
= sizeof(ape_data
.application
);
414 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
415 memcpy(result
[0].value
.u
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
417 result
[1].id
.vt
= VT_LPWSTR
;
418 result
[1].id
.u
.pwszVal
= strdupAtoW("Data");
419 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
420 result
[1].value
.u
.caub
.cElems
= data_size
;
421 result
[1].value
.u
.caub
.pElems
= data
;
429 static const MetadataHandlerVtbl APEReader_Vtbl
= {
431 &CLSID_WICAPEMetadataReader
,
435 HRESULT
APEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
437 return MetadataReader_Create(&APEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
440 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
441 MetadataItem
**items
, DWORD
*count
)
443 #include "pshpack1.h"
444 struct gif_extenstion
446 BYTE extension_introducer
;
447 BYTE extension_label
;
451 ULONG bytesread
, data_size
;
452 MetadataItem
*result
;
459 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
460 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
461 if (ext_data
.extension_introducer
!= 0x21 ||
462 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
470 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
471 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
473 HeapFree(GetProcessHeap(), 0, data
);
476 if (!subblock_size
) break;
479 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
482 char *new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
485 HeapFree(GetProcessHeap(), 0, data
);
490 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
491 if (FAILED(hr
) || bytesread
!= subblock_size
)
493 HeapFree(GetProcessHeap(), 0, data
);
496 data_size
+= subblock_size
;
501 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
));
504 HeapFree(GetProcessHeap(), 0, data
);
505 return E_OUTOFMEMORY
;
508 PropVariantInit(&result
->schema
);
509 PropVariantInit(&result
->id
);
510 PropVariantInit(&result
->value
);
512 result
->id
.vt
= VT_LPWSTR
;
513 result
->id
.u
.pwszVal
= strdupAtoW("TextEntry");
514 result
->value
.vt
= VT_LPSTR
;
515 result
->value
.u
.pszVal
= data
;
523 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
525 &CLSID_WICGifCommentMetadataReader
,
526 load_GifComment_metadata
529 HRESULT
GifCommentReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
531 return MetadataReader_Create(&GifCommentReader_Vtbl
, pUnkOuter
, iid
, ppv
);
534 static IStream
*create_stream(const void *data
, int data_size
)
541 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
542 if (!hdata
) return NULL
;
544 locked_data
= GlobalLock(hdata
);
545 memcpy(locked_data
, data
, data_size
);
548 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
549 return FAILED(hr
) ? NULL
: stream
;
552 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
553 const CLSID
*clsid
, IWICMetadataReader
**reader
)
556 IWICMetadataReader
*metadata_reader
;
557 IWICPersistStream
*persist
;
560 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
562 hr
= CoCreateInstance(clsid
, NULL
, CLSCTX_INPROC_SERVER
,
563 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
564 if (FAILED(hr
)) return hr
;
566 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
569 IWICMetadataReader_Release(metadata_reader
);
573 stream
= create_stream(data
, data_size
);
574 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
575 IStream_Release(stream
);
577 IWICPersistStream_Release(persist
);
579 *reader
= metadata_reader
;
584 IWICBitmapDecoder IWICBitmapDecoder_iface
;
585 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
586 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
591 CRITICAL_SECTION lock
;
595 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
596 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
602 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
604 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
607 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
609 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
612 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
614 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
617 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
619 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
622 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
625 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
626 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
628 if (!ppv
) return E_INVALIDARG
;
630 if (IsEqualIID(&IID_IUnknown
, iid
) ||
631 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
632 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
634 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
636 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
638 *ppv
= &This
->IWICMetadataBlockReader_iface
;
643 return E_NOINTERFACE
;
646 IUnknown_AddRef((IUnknown
*)*ppv
);
650 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
652 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
653 ULONG ref
= InterlockedIncrement(&This
->ref
);
655 TRACE("(%p) refcount=%u\n", iface
, ref
);
660 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
662 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
663 ULONG ref
= InterlockedDecrement(&This
->ref
);
665 TRACE("(%p) refcount=%u\n", iface
, ref
);
669 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
670 HeapFree(GetProcessHeap(), 0, This
);
676 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
677 UINT
*puiWidth
, UINT
*puiHeight
)
679 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
680 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
682 *puiWidth
= This
->frame
->ImageDesc
.Width
;
683 *puiHeight
= This
->frame
->ImageDesc
.Height
;
688 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
689 WICPixelFormatGUID
*pPixelFormat
)
691 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
696 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
697 double *pDpiX
, double *pDpiY
)
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
);
704 *pDpiX
= 96.0 / aspect
;
710 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
711 IWICPalette
*pIPalette
)
713 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
714 WICColor colors
[256];
715 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
718 TRACE("(%p,%p)\n", iface
, pIPalette
);
720 if (!cm
) cm
= This
->parent
->gif
->SColorMap
;
722 if (cm
->ColorCount
> 256)
724 ERR("GIF contains %i colors???\n", cm
->ColorCount
);
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|
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 */
747 return IWICPalette_InitializeCustom(pIPalette
, colors
, cm
->ColorCount
);
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
)
754 UINT row_offset
; /* number of bytes into the source rows where the data starts */
764 rect
.Width
= srcwidth
;
765 rect
.Height
= srcheight
;
770 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
774 if (dststride
< rc
->Width
)
777 if ((dststride
* rc
->Height
) > dstbuffersize
)
783 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
786 src
= srcbuffer
+ srcstride
* (y
/8);
788 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
790 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
792 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
794 memcpy(dst
, src
, rc
->Width
);
800 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
801 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
803 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
804 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
806 if (This
->frame
->ImageDesc
.Interlace
)
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
);
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
);
820 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
821 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
823 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
824 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
827 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
828 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
830 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
831 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
834 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
835 IWICBitmapSource
**ppIThumbnail
)
837 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
838 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
841 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
842 GifFrameDecode_QueryInterface
,
843 GifFrameDecode_AddRef
,
844 GifFrameDecode_Release
,
845 GifFrameDecode_GetSize
,
846 GifFrameDecode_GetPixelFormat
,
847 GifFrameDecode_GetResolution
,
848 GifFrameDecode_CopyPalette
,
849 GifFrameDecode_CopyPixels
,
850 GifFrameDecode_GetMetadataQueryReader
,
851 GifFrameDecode_GetColorContexts
,
852 GifFrameDecode_GetThumbnail
855 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
856 REFIID iid
, void **ppv
)
858 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
859 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
862 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
864 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
865 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
868 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
870 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
871 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
874 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
877 TRACE("(%p,%p)\n", iface
, guid
);
879 if (!guid
) return E_INVALIDARG
;
881 *guid
= GUID_ContainerFormatGif
;
885 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
888 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
890 TRACE("%p,%p\n", iface
, count
);
892 if (!count
) return E_INVALIDARG
;
894 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
898 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
901 IWICMetadataReader
*metadata_reader
;
902 IWICPersistStream
*persist
;
904 struct image_descriptor IMD_data
;
906 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
908 hr
= CoCreateInstance(&CLSID_WICIMDMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
909 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
910 if (FAILED(hr
)) return hr
;
912 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
915 IWICMetadataReader_Release(metadata_reader
);
919 /* recreate IMD structure from GIF decoder data */
920 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
921 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
922 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
923 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
926 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
927 if (This
->frame
->ImageDesc
.ColorMap
)
929 /* local_color_table_flag */
930 IMD_data
.packed
|= 1 << 7;
931 /* local_color_table_size */
932 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
934 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
937 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
938 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
939 IStream_Release(stream
);
941 IWICPersistStream_Release(persist
);
943 *reader
= metadata_reader
;
947 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
948 UINT index
, IWICMetadataReader
**reader
)
950 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
951 int i
, gce_index
= -1, gce_skipped
= 0;
953 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
955 if (!reader
) return E_INVALIDARG
;
958 return create_IMD_metadata_reader(This
, reader
);
960 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
963 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; i
++)
969 if (index
!= i
+ 1 - gce_skipped
) continue;
971 if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== GRAPHICS_EXT_FUNC_CODE
)
977 else if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
979 clsid
= &CLSID_WICGifCommentMetadataReader
;
980 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
981 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
985 clsid
= &CLSID_WICUnknownMetadataReader
;
986 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
987 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
989 return create_metadata_reader(data
, data_size
, clsid
, reader
);
992 if (gce_index
== -1) return E_INVALIDARG
;
994 return create_metadata_reader(This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].Bytes
+ 3,
995 This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].ByteCount
- 4,
996 &CLSID_WICGCEMetadataReader
, reader
);
999 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1000 IEnumUnknown
**enumerator
)
1002 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1006 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
1008 GifFrameDecode_Block_QueryInterface
,
1009 GifFrameDecode_Block_AddRef
,
1010 GifFrameDecode_Block_Release
,
1011 GifFrameDecode_Block_GetContainerFormat
,
1012 GifFrameDecode_Block_GetCount
,
1013 GifFrameDecode_Block_GetReaderByIndex
,
1014 GifFrameDecode_Block_GetEnumerator
1017 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1020 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1021 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1023 if (!ppv
) return E_INVALIDARG
;
1025 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1026 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1028 *ppv
= &This
->IWICBitmapDecoder_iface
;
1030 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1032 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1037 return E_NOINTERFACE
;
1040 IUnknown_AddRef((IUnknown
*)*ppv
);
1044 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1046 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1047 ULONG ref
= InterlockedIncrement(&This
->ref
);
1049 TRACE("(%p) refcount=%u\n", iface
, ref
);
1054 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1056 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1057 ULONG ref
= InterlockedDecrement(&This
->ref
);
1059 TRACE("(%p) refcount=%u\n", iface
, ref
);
1063 This
->lock
.DebugInfo
->Spare
[0] = 0;
1064 DeleteCriticalSection(&This
->lock
);
1065 DGifCloseFile(This
->gif
);
1066 HeapFree(GetProcessHeap(), 0, This
);
1072 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1077 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1079 if (!stream
|| !capability
) return E_INVALIDARG
;
1081 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1082 if (hr
!= S_OK
) return hr
;
1084 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1085 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1086 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1090 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1091 IStream
*stream
= gif
->UserData
;
1097 ERR("attempting to read file after initialization\n");
1101 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1102 if (hr
!= S_OK
) bytesread
= 0;
1106 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1107 WICDecodeOptions cacheOptions
)
1109 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1113 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1115 EnterCriticalSection(&This
->lock
);
1117 if (This
->initialized
|| This
->gif
)
1119 WARN("already initialized\n");
1120 LeaveCriticalSection(&This
->lock
);
1121 return WINCODEC_ERR_WRONGSTATE
;
1124 /* seek to start of stream */
1126 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1128 /* read all data from the stream */
1129 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1132 LeaveCriticalSection(&This
->lock
);
1136 ret
= DGifSlurp(This
->gif
);
1137 if (ret
== GIF_ERROR
)
1139 LeaveCriticalSection(&This
->lock
);
1143 /* make sure we don't use the stream after this method returns */
1144 This
->gif
->UserData
= NULL
;
1147 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1148 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1150 This
->initialized
= TRUE
;
1152 LeaveCriticalSection(&This
->lock
);
1157 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1158 GUID
*pguidContainerFormat
)
1160 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1164 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1165 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1168 IWICComponentInfo
*compinfo
;
1170 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1172 hr
= CreateComponentInfo(&CLSID_WICGifDecoder
, &compinfo
);
1173 if (FAILED(hr
)) return hr
;
1175 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1176 (void**)ppIDecoderInfo
);
1178 IWICComponentInfo_Release(compinfo
);
1183 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1185 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1186 WICColor colors
[256];
1188 int i
, trans
, count
;
1191 TRACE("(%p,%p)\n", iface
, palette
);
1193 cm
= This
->gif
->SColorMap
;
1196 if (cm
->ColorCount
> 256)
1198 ERR("GIF contains invalid number of colors: %d\n", cm
->ColorCount
);
1202 for (i
= 0; i
< cm
->ColorCount
; i
++)
1204 colors
[i
] = 0xff000000 | /* alpha */
1205 cm
->Colors
[i
].Red
<< 16 |
1206 cm
->Colors
[i
].Green
<< 8 |
1210 count
= cm
->ColorCount
;
1214 colors
[0] = 0xff000000;
1215 colors
[1] = 0xffffffff;
1217 for (i
= 2; i
< 256; i
++)
1218 colors
[i
] = 0xff000000;
1223 /* look for the transparent color extension */
1224 for (i
= 0; i
< This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlockCount
; i
++)
1226 eb
= This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlocks
+ i
;
1227 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8)
1229 if (eb
->Bytes
[3] & 1)
1231 trans
= (unsigned char)eb
->Bytes
[6];
1232 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
1238 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1241 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1242 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1244 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1245 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1248 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1249 IWICBitmapSource
**ppIBitmapSource
)
1251 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1252 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1255 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1256 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1258 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1259 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1262 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1263 IWICBitmapSource
**ppIThumbnail
)
1265 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1266 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1269 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1272 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1274 if (!pCount
) return E_INVALIDARG
;
1276 EnterCriticalSection(&This
->lock
);
1277 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1278 LeaveCriticalSection(&This
->lock
);
1280 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1285 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1286 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1288 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1289 GifFrameDecode
*result
;
1290 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1292 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1294 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1296 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1297 if (!result
) return E_OUTOFMEMORY
;
1299 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1300 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1302 result
->frame
= &This
->gif
->SavedImages
[index
];
1303 IWICBitmapDecoder_AddRef(iface
);
1304 result
->parent
= This
;
1305 This
->current_frame
= index
;
1307 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1312 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1313 GifDecoder_QueryInterface
,
1316 GifDecoder_QueryCapability
,
1317 GifDecoder_Initialize
,
1318 GifDecoder_GetContainerFormat
,
1319 GifDecoder_GetDecoderInfo
,
1320 GifDecoder_CopyPalette
,
1321 GifDecoder_GetMetadataQueryReader
,
1322 GifDecoder_GetPreview
,
1323 GifDecoder_GetColorContexts
,
1324 GifDecoder_GetThumbnail
,
1325 GifDecoder_GetFrameCount
,
1329 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1330 REFIID iid
, void **ppv
)
1332 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1333 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1336 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1338 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1339 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1342 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1344 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1345 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1348 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1351 TRACE("(%p,%p)\n", iface
, guid
);
1353 if (!guid
) return E_INVALIDARG
;
1355 *guid
= GUID_ContainerFormatGif
;
1359 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1362 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1364 TRACE("%p,%p\n", iface
, count
);
1366 if (!count
) return E_INVALIDARG
;
1368 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1372 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1373 UINT index
, IWICMetadataReader
**reader
)
1375 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1378 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1380 if (!reader
) return E_INVALIDARG
;
1383 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1384 &CLSID_WICLSDMetadataReader
, reader
);
1386 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1390 if (index
!= i
+ 1) continue;
1392 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1393 clsid
= &CLSID_WICAPEMetadataReader
;
1394 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1395 clsid
= &CLSID_WICGifCommentMetadataReader
;
1397 clsid
= &CLSID_WICUnknownMetadataReader
;
1399 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1400 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1404 return E_INVALIDARG
;
1407 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1408 IEnumUnknown
**enumerator
)
1410 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1414 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1416 GifDecoder_Block_QueryInterface
,
1417 GifDecoder_Block_AddRef
,
1418 GifDecoder_Block_Release
,
1419 GifDecoder_Block_GetContainerFormat
,
1420 GifDecoder_Block_GetCount
,
1421 GifDecoder_Block_GetReaderByIndex
,
1422 GifDecoder_Block_GetEnumerator
1425 HRESULT
GifDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1430 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1434 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1436 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1437 if (!This
) return E_OUTOFMEMORY
;
1439 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1440 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1442 This
->initialized
= FALSE
;
1444 This
->current_frame
= 0;
1445 InitializeCriticalSection(&This
->lock
);
1446 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1448 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1449 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);