2 * Copyright 2009 Vincent Povirk for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
30 #include "wincodecsdk.h"
34 #include "wincodecs_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
40 static LPWSTR strdupAtoW(const char *src)
42 int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
43 LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
44 if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
48 static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
49 MetadataItem **items, DWORD *count)
52 struct logical_screen_descriptor
58 /* global_color_table_flag : 1;
59 * color_resolution : 3;
61 * global_color_table_size : 3;
63 BYTE background_color_index;
64 BYTE pixel_aspect_ratio;
74 hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread);
75 if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK;
77 result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 9);
78 if (!result) return E_OUTOFMEMORY;
80 for (i = 0; i < 9; i++)
82 PropVariantInit(&result[i].schema);
83 PropVariantInit(&result[i].id);
84 PropVariantInit(&result[i].value);
87 result[0].id.vt = VT_LPWSTR;
88 result[0].id.u.pwszVal = strdupAtoW("Signature");
89 result[0].value.vt = VT_UI1|VT_VECTOR;
90 result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
91 result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
92 memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
94 result[1].id.vt = VT_LPWSTR;
95 result[1].id.u.pwszVal = strdupAtoW("Width");
96 result[1].value.vt = VT_UI2;
97 result[1].value.u.uiVal = lsd_data.width;
99 result[2].id.vt = VT_LPWSTR;
100 result[2].id.u.pwszVal = strdupAtoW("Height");
101 result[2].value.vt = VT_UI2;
102 result[2].value.u.uiVal = lsd_data.height;
104 result[3].id.vt = VT_LPWSTR;
105 result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
106 result[3].value.vt = VT_BOOL;
107 result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;
109 result[4].id.vt = VT_LPWSTR;
110 result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
111 result[4].value.vt = VT_UI1;
112 result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;
114 result[5].id.vt = VT_LPWSTR;
115 result[5].id.u.pwszVal = strdupAtoW("SortFlag");
116 result[5].value.vt = VT_BOOL;
117 result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;
119 result[6].id.vt = VT_LPWSTR;
120 result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
121 result[6].value.vt = VT_UI1;
122 result[6].value.u.bVal = lsd_data.packed & 7;
124 result[7].id.vt = VT_LPWSTR;
125 result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
126 result[7].value.vt = VT_UI1;
127 result[7].value.u.bVal = lsd_data.background_color_index;
129 result[8].id.vt = VT_LPWSTR;
130 result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
131 result[8].value.vt = VT_UI1;
132 result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;
140 static const MetadataHandlerVtbl LSDReader_Vtbl = {
142 &CLSID_WICLSDMetadataReader,
146 HRESULT LSDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
148 return MetadataReader_Create(&LSDReader_Vtbl, pUnkOuter, iid, ppv);
151 static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options,
152 MetadataItem **items, DWORD *count)
154 #include "pshpack1.h"
155 struct image_descriptor
162 /* local_color_table_flag : 1;
163 * interlace_flag : 1;
166 * local_color_table_size : 3;
172 MetadataItem *result;
177 hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread);
178 if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK;
180 result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 8);
181 if (!result) return E_OUTOFMEMORY;
183 for (i = 0; i < 8; i++)
185 PropVariantInit(&result[i].schema);
186 PropVariantInit(&result[i].id);
187 PropVariantInit(&result[i].value);
190 result[0].id.vt = VT_LPWSTR;
191 result[0].id.u.pwszVal = strdupAtoW("Left");
192 result[0].value.vt = VT_UI2;
193 result[0].value.u.uiVal = imd_data.left;
195 result[1].id.vt = VT_LPWSTR;
196 result[1].id.u.pwszVal = strdupAtoW("Top");
197 result[1].value.vt = VT_UI2;
198 result[1].value.u.uiVal = imd_data.top;
200 result[2].id.vt = VT_LPWSTR;
201 result[2].id.u.pwszVal = strdupAtoW("Width");
202 result[2].value.vt = VT_UI2;
203 result[2].value.u.uiVal = imd_data.width;
205 result[3].id.vt = VT_LPWSTR;
206 result[3].id.u.pwszVal = strdupAtoW("Height");
207 result[3].value.vt = VT_UI2;
208 result[3].value.u.uiVal = imd_data.height;
210 result[4].id.vt = VT_LPWSTR;
211 result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag");
212 result[4].value.vt = VT_BOOL;
213 result[4].value.u.boolVal = (imd_data.packed >> 7) & 1;
215 result[5].id.vt = VT_LPWSTR;
216 result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag");
217 result[5].value.vt = VT_BOOL;
218 result[5].value.u.boolVal = (imd_data.packed >> 6) & 1;
220 result[6].id.vt = VT_LPWSTR;
221 result[6].id.u.pwszVal = strdupAtoW("SortFlag");
222 result[6].value.vt = VT_BOOL;
223 result[6].value.u.boolVal = (imd_data.packed >> 5) & 1;
225 result[7].id.vt = VT_LPWSTR;
226 result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize");
227 result[7].value.vt = VT_UI1;
228 result[7].value.u.bVal = imd_data.packed & 7;
236 static const MetadataHandlerVtbl IMDReader_Vtbl = {
238 &CLSID_WICIMDMetadataReader,
242 HRESULT IMDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
244 return MetadataReader_Create(&IMDReader_Vtbl, pUnkOuter, iid, ppv);
247 static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
248 MetadataItem **items, DWORD *count)
250 #include "pshpack1.h"
251 struct graphic_control_extenstion
256 * user_input_flag : 1;
257 * transparency_flag : 1;
260 BYTE transparent_color_index;
265 MetadataItem *result;
270 hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread);
271 if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK;
273 result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 5);
274 if (!result) return E_OUTOFMEMORY;
276 for (i = 0; i < 5; i++)
278 PropVariantInit(&result[i].schema);
279 PropVariantInit(&result[i].id);
280 PropVariantInit(&result[i].value);
283 result[0].id.vt = VT_LPWSTR;
284 result[0].id.u.pwszVal = strdupAtoW("Disposal");
285 result[0].value.vt = VT_UI1;
286 result[0].value.u.bVal = (gce_data.packed >> 2) & 7;
288 result[1].id.vt = VT_LPWSTR;
289 result[1].id.u.pwszVal = strdupAtoW("UserInputFlag");
290 result[1].value.vt = VT_BOOL;
291 result[1].value.u.boolVal = (gce_data.packed >> 1) & 1;
293 result[2].id.vt = VT_LPWSTR;
294 result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag");
295 result[2].value.vt = VT_BOOL;
296 result[2].value.u.boolVal = gce_data.packed & 1;
298 result[3].id.vt = VT_LPWSTR;
299 result[3].id.u.pwszVal = strdupAtoW("Delay");
300 result[3].value.vt = VT_UI2;
301 result[3].value.u.uiVal = gce_data.delay;
303 result[4].id.vt = VT_LPWSTR;
304 result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex");
305 result[4].value.vt = VT_UI1;
306 result[4].value.u.bVal = gce_data.transparent_color_index;
314 static const MetadataHandlerVtbl GCEReader_Vtbl = {
316 &CLSID_WICGCEMetadataReader,
320 HRESULT GCEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
322 return MetadataReader_Create(&GCEReader_Vtbl, pUnkOuter, iid, ppv);
326 IWICBitmapDecoder IWICBitmapDecoder_iface;
330 CRITICAL_SECTION lock;
334 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
340 static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
342 return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
345 static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
347 return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface);
350 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
353 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
354 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
356 if (!ppv) return E_INVALIDARG;
358 if (IsEqualIID(&IID_IUnknown, iid) ||
359 IsEqualIID(&IID_IWICBitmapSource, iid) ||
360 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
362 *ppv = &This->IWICBitmapFrameDecode_iface;
367 return E_NOINTERFACE;
370 IUnknown_AddRef((IUnknown*)*ppv);
374 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
376 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
377 ULONG ref = InterlockedIncrement(&This->ref);
379 TRACE("(%p) refcount=%u\n", iface, ref);
384 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
386 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
387 ULONG ref = InterlockedDecrement(&This->ref);
389 TRACE("(%p) refcount=%u\n", iface, ref);
393 IUnknown_Release((IUnknown*)This->parent);
394 HeapFree(GetProcessHeap(), 0, This);
400 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
401 UINT *puiWidth, UINT *puiHeight)
403 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
404 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
406 *puiWidth = This->frame->ImageDesc.Width;
407 *puiHeight = This->frame->ImageDesc.Height;
412 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
413 WICPixelFormatGUID *pPixelFormat)
415 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
420 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
421 double *pDpiX, double *pDpiY)
423 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
424 const GifWord aspect_word = This->parent->gif->SAspectRatio;
425 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
426 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
428 *pDpiX = 96.0 / aspect;
434 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
435 IWICPalette *pIPalette)
437 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
438 WICColor colors[256];
439 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
442 TRACE("(%p,%p)\n", iface, pIPalette);
444 if (!cm) cm = This->parent->gif->SColorMap;
446 if (cm->ColorCount > 256)
448 ERR("GIF contains %i colors???\n", cm->ColorCount);
452 for (i = 0; i < cm->ColorCount; i++) {
453 colors[i] = 0xff000000| /* alpha */
454 cm->Colors[i].Red << 16|
455 cm->Colors[i].Green << 8|
459 /* look for the transparent color extension */
460 for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
461 eb = This->frame->ExtensionBlocks + i;
462 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
463 if ((eb->Bytes[0] & 1) == 1) {
464 trans = (unsigned char)eb->Bytes[3];
465 colors[trans] &= 0xffffff; /* set alpha to 0 */
471 IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
476 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
477 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
478 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
480 UINT row_offset; /* number of bytes into the source rows where the data starts */
490 rect.Width = srcwidth;
491 rect.Height = srcheight;
496 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
500 if (dststride < rc->Width)
503 if ((dststride * rc->Height) > dstbuffersize)
509 for (y=rc->Y; y-rc->Y < rc->Height; y++)
512 src = srcbuffer + srcstride * (y/8);
514 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
516 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
518 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
520 memcpy(dst, src, rc->Width);
526 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
527 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
529 GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
530 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
532 if (This->frame->ImageDesc.Interlace)
534 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
535 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
536 prc, cbStride, cbBufferSize, pbBuffer);
540 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
541 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
542 prc, cbStride, cbBufferSize, pbBuffer);
546 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
547 IWICMetadataQueryReader **ppIMetadataQueryReader)
549 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
550 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
553 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
554 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
556 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
557 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
560 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
561 IWICBitmapSource **ppIThumbnail)
563 TRACE("(%p,%p)\n", iface, ppIThumbnail);
564 return WINCODEC_ERR_CODECNOTHUMBNAIL;
567 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
568 GifFrameDecode_QueryInterface,
569 GifFrameDecode_AddRef,
570 GifFrameDecode_Release,
571 GifFrameDecode_GetSize,
572 GifFrameDecode_GetPixelFormat,
573 GifFrameDecode_GetResolution,
574 GifFrameDecode_CopyPalette,
575 GifFrameDecode_CopyPixels,
576 GifFrameDecode_GetMetadataQueryReader,
577 GifFrameDecode_GetColorContexts,
578 GifFrameDecode_GetThumbnail
581 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
584 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
585 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
587 if (!ppv) return E_INVALIDARG;
589 if (IsEqualIID(&IID_IUnknown, iid) ||
590 IsEqualIID(&IID_IWICBitmapDecoder, iid))
592 *ppv = &This->IWICBitmapDecoder_iface;
597 return E_NOINTERFACE;
600 IUnknown_AddRef((IUnknown*)*ppv);
604 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
606 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
607 ULONG ref = InterlockedIncrement(&This->ref);
609 TRACE("(%p) refcount=%u\n", iface, ref);
614 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
616 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
617 ULONG ref = InterlockedDecrement(&This->ref);
619 TRACE("(%p) refcount=%u\n", iface, ref);
623 This->lock.DebugInfo->Spare[0] = 0;
624 DeleteCriticalSection(&This->lock);
625 DGifCloseFile(This->gif);
626 HeapFree(GetProcessHeap(), 0, This);
632 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
633 DWORD *pdwCapability)
635 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
639 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
640 IStream *stream = gif->UserData;
646 ERR("attempting to read file after initialization\n");
650 hr = IStream_Read(stream, data, len, &bytesread);
651 if (hr != S_OK) bytesread = 0;
655 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
656 WICDecodeOptions cacheOptions)
658 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
662 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
664 EnterCriticalSection(&This->lock);
666 if (This->initialized || This->gif)
668 WARN("already initialized\n");
669 LeaveCriticalSection(&This->lock);
670 return WINCODEC_ERR_WRONGSTATE;
673 /* seek to start of stream */
675 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
677 /* read all data from the stream */
678 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
681 LeaveCriticalSection(&This->lock);
685 ret = DGifSlurp(This->gif);
686 if (ret == GIF_ERROR)
688 LeaveCriticalSection(&This->lock);
692 /* make sure we don't use the stream after this method returns */
693 This->gif->UserData = NULL;
695 This->initialized = TRUE;
697 LeaveCriticalSection(&This->lock);
702 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
703 GUID *pguidContainerFormat)
705 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
709 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
710 IWICBitmapDecoderInfo **ppIDecoderInfo)
713 IWICComponentInfo *compinfo;
715 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
717 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
718 if (FAILED(hr)) return hr;
720 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
721 (void**)ppIDecoderInfo);
723 IWICComponentInfo_Release(compinfo);
728 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
729 IWICPalette *pIPalette)
731 TRACE("(%p,%p)\n", iface, pIPalette);
732 return WINCODEC_ERR_PALETTEUNAVAILABLE;
735 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
736 IWICMetadataQueryReader **ppIMetadataQueryReader)
738 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
739 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
742 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
743 IWICBitmapSource **ppIBitmapSource)
745 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
746 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
749 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
750 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
752 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
753 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
756 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
757 IWICBitmapSource **ppIThumbnail)
759 TRACE("(%p,%p)\n", iface, ppIThumbnail);
760 return WINCODEC_ERR_CODECNOTHUMBNAIL;
763 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
766 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
767 TRACE("(%p,%p)\n", iface, pCount);
769 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
771 *pCount = This->gif->ImageCount;
773 TRACE("<- %u\n", *pCount);
778 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
779 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
781 GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
782 GifFrameDecode *result;
783 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
785 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
787 if (index >= This->gif->ImageCount) return E_INVALIDARG;
789 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
790 if (!result) return E_OUTOFMEMORY;
792 result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
794 result->frame = &This->gif->SavedImages[index];
795 IWICBitmapDecoder_AddRef(iface);
796 result->parent = This;
798 *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
803 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
804 GifDecoder_QueryInterface,
807 GifDecoder_QueryCapability,
808 GifDecoder_Initialize,
809 GifDecoder_GetContainerFormat,
810 GifDecoder_GetDecoderInfo,
811 GifDecoder_CopyPalette,
812 GifDecoder_GetMetadataQueryReader,
813 GifDecoder_GetPreview,
814 GifDecoder_GetColorContexts,
815 GifDecoder_GetThumbnail,
816 GifDecoder_GetFrameCount,
820 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
825 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
829 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
831 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
832 if (!This) return E_OUTOFMEMORY;
834 This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
836 This->initialized = FALSE;
838 InitializeCriticalSection(&This->lock);
839 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
841 ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
842 IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);