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
25 #define NONAMELESSUNION
31 #include "wincodecsdk.h"
35 #include "wincodecs_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
41 static LPWSTR
strdupAtoW(const char *src
)
43 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
44 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
45 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
49 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
50 MetadataItem
**items
, DWORD
*count
)
53 struct logical_screen_descriptor
59 /* global_color_table_flag : 1;
60 * color_resolution : 3;
62 * global_color_table_size : 3;
64 BYTE background_color_index
;
65 BYTE pixel_aspect_ratio
;
75 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
76 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
78 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 9);
79 if (!result
) return E_OUTOFMEMORY
;
81 for (i
= 0; i
< 9; i
++)
83 PropVariantInit(&result
[i
].schema
);
84 PropVariantInit(&result
[i
].id
);
85 PropVariantInit(&result
[i
].value
);
88 result
[0].id
.vt
= VT_LPWSTR
;
89 result
[0].id
.u
.pwszVal
= strdupAtoW("Signature");
90 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
91 result
[0].value
.u
.caub
.cElems
= sizeof(lsd_data
.signature
);
92 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
93 memcpy(result
[0].value
.u
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
95 result
[1].id
.vt
= VT_LPWSTR
;
96 result
[1].id
.u
.pwszVal
= strdupAtoW("Width");
97 result
[1].value
.vt
= VT_UI2
;
98 result
[1].value
.u
.uiVal
= lsd_data
.width
;
100 result
[2].id
.vt
= VT_LPWSTR
;
101 result
[2].id
.u
.pwszVal
= strdupAtoW("Height");
102 result
[2].value
.vt
= VT_UI2
;
103 result
[2].value
.u
.uiVal
= lsd_data
.height
;
105 result
[3].id
.vt
= VT_LPWSTR
;
106 result
[3].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
107 result
[3].value
.vt
= VT_BOOL
;
108 result
[3].value
.u
.boolVal
= (lsd_data
.packed
>> 7) & 1;
110 result
[4].id
.vt
= VT_LPWSTR
;
111 result
[4].id
.u
.pwszVal
= strdupAtoW("ColorResolution");
112 result
[4].value
.vt
= VT_UI1
;
113 result
[4].value
.u
.bVal
= (lsd_data
.packed
>> 4) & 7;
115 result
[5].id
.vt
= VT_LPWSTR
;
116 result
[5].id
.u
.pwszVal
= strdupAtoW("SortFlag");
117 result
[5].value
.vt
= VT_BOOL
;
118 result
[5].value
.u
.boolVal
= (lsd_data
.packed
>> 3) & 1;
120 result
[6].id
.vt
= VT_LPWSTR
;
121 result
[6].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableSize");
122 result
[6].value
.vt
= VT_UI1
;
123 result
[6].value
.u
.bVal
= lsd_data
.packed
& 7;
125 result
[7].id
.vt
= VT_LPWSTR
;
126 result
[7].id
.u
.pwszVal
= strdupAtoW("BackgroundColorIndex");
127 result
[7].value
.vt
= VT_UI1
;
128 result
[7].value
.u
.bVal
= lsd_data
.background_color_index
;
130 result
[8].id
.vt
= VT_LPWSTR
;
131 result
[8].id
.u
.pwszVal
= strdupAtoW("PixelAspectRatio");
132 result
[8].value
.vt
= VT_UI1
;
133 result
[8].value
.u
.bVal
= lsd_data
.pixel_aspect_ratio
;
141 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
143 &CLSID_WICLSDMetadataReader
,
147 HRESULT
LSDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
149 return MetadataReader_Create(&LSDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
152 #include "pshpack1.h"
153 struct image_descriptor
160 /* local_color_table_flag : 1;
161 * interlace_flag : 1;
164 * local_color_table_size : 3;
169 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
170 MetadataItem
**items
, DWORD
*count
)
172 struct image_descriptor imd_data
;
175 MetadataItem
*result
;
180 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
181 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
183 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 8);
184 if (!result
) return E_OUTOFMEMORY
;
186 for (i
= 0; i
< 8; i
++)
188 PropVariantInit(&result
[i
].schema
);
189 PropVariantInit(&result
[i
].id
);
190 PropVariantInit(&result
[i
].value
);
193 result
[0].id
.vt
= VT_LPWSTR
;
194 result
[0].id
.u
.pwszVal
= strdupAtoW("Left");
195 result
[0].value
.vt
= VT_UI2
;
196 result
[0].value
.u
.uiVal
= imd_data
.left
;
198 result
[1].id
.vt
= VT_LPWSTR
;
199 result
[1].id
.u
.pwszVal
= strdupAtoW("Top");
200 result
[1].value
.vt
= VT_UI2
;
201 result
[1].value
.u
.uiVal
= imd_data
.top
;
203 result
[2].id
.vt
= VT_LPWSTR
;
204 result
[2].id
.u
.pwszVal
= strdupAtoW("Width");
205 result
[2].value
.vt
= VT_UI2
;
206 result
[2].value
.u
.uiVal
= imd_data
.width
;
208 result
[3].id
.vt
= VT_LPWSTR
;
209 result
[3].id
.u
.pwszVal
= strdupAtoW("Height");
210 result
[3].value
.vt
= VT_UI2
;
211 result
[3].value
.u
.uiVal
= imd_data
.height
;
213 result
[4].id
.vt
= VT_LPWSTR
;
214 result
[4].id
.u
.pwszVal
= strdupAtoW("LocalColorTableFlag");
215 result
[4].value
.vt
= VT_BOOL
;
216 result
[4].value
.u
.boolVal
= (imd_data
.packed
>> 7) & 1;
218 result
[5].id
.vt
= VT_LPWSTR
;
219 result
[5].id
.u
.pwszVal
= strdupAtoW("InterlaceFlag");
220 result
[5].value
.vt
= VT_BOOL
;
221 result
[5].value
.u
.boolVal
= (imd_data
.packed
>> 6) & 1;
223 result
[6].id
.vt
= VT_LPWSTR
;
224 result
[6].id
.u
.pwszVal
= strdupAtoW("SortFlag");
225 result
[6].value
.vt
= VT_BOOL
;
226 result
[6].value
.u
.boolVal
= (imd_data
.packed
>> 5) & 1;
228 result
[7].id
.vt
= VT_LPWSTR
;
229 result
[7].id
.u
.pwszVal
= strdupAtoW("LocalColorTableSize");
230 result
[7].value
.vt
= VT_UI1
;
231 result
[7].value
.u
.bVal
= imd_data
.packed
& 7;
239 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
241 &CLSID_WICIMDMetadataReader
,
245 HRESULT
IMDReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
247 return MetadataReader_Create(&IMDReader_Vtbl
, pUnkOuter
, iid
, ppv
);
250 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
251 MetadataItem
**items
, DWORD
*count
)
253 #include "pshpack1.h"
254 struct graphic_control_extenstion
259 * user_input_flag : 1;
260 * transparency_flag : 1;
263 BYTE transparent_color_index
;
268 MetadataItem
*result
;
273 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
274 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
276 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 5);
277 if (!result
) return E_OUTOFMEMORY
;
279 for (i
= 0; i
< 5; i
++)
281 PropVariantInit(&result
[i
].schema
);
282 PropVariantInit(&result
[i
].id
);
283 PropVariantInit(&result
[i
].value
);
286 result
[0].id
.vt
= VT_LPWSTR
;
287 result
[0].id
.u
.pwszVal
= strdupAtoW("Disposal");
288 result
[0].value
.vt
= VT_UI1
;
289 result
[0].value
.u
.bVal
= (gce_data
.packed
>> 2) & 7;
291 result
[1].id
.vt
= VT_LPWSTR
;
292 result
[1].id
.u
.pwszVal
= strdupAtoW("UserInputFlag");
293 result
[1].value
.vt
= VT_BOOL
;
294 result
[1].value
.u
.boolVal
= (gce_data
.packed
>> 1) & 1;
296 result
[2].id
.vt
= VT_LPWSTR
;
297 result
[2].id
.u
.pwszVal
= strdupAtoW("TransparencyFlag");
298 result
[2].value
.vt
= VT_BOOL
;
299 result
[2].value
.u
.boolVal
= gce_data
.packed
& 1;
301 result
[3].id
.vt
= VT_LPWSTR
;
302 result
[3].id
.u
.pwszVal
= strdupAtoW("Delay");
303 result
[3].value
.vt
= VT_UI2
;
304 result
[3].value
.u
.uiVal
= gce_data
.delay
;
306 result
[4].id
.vt
= VT_LPWSTR
;
307 result
[4].id
.u
.pwszVal
= strdupAtoW("TransparentColorIndex");
308 result
[4].value
.vt
= VT_UI1
;
309 result
[4].value
.u
.bVal
= gce_data
.transparent_color_index
;
317 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
319 &CLSID_WICGCEMetadataReader
,
323 HRESULT
GCEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
325 return MetadataReader_Create(&GCEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
328 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
329 MetadataItem
**items
, DWORD
*count
)
331 #include "pshpack1.h"
332 struct application_extenstion
334 BYTE extension_introducer
;
335 BYTE extension_label
;
337 BYTE application
[11];
341 ULONG bytesread
, data_size
, i
;
342 MetadataItem
*result
;
349 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
350 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
351 if (ape_data
.extension_introducer
!= 0x21 || ape_data
.extension_label
!= 0xff ||
352 ape_data
.block_size
!= 11)
360 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
361 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
363 HeapFree(GetProcessHeap(), 0, data
);
366 if (!subblock_size
) break;
369 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
372 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
375 HeapFree(GetProcessHeap(), 0, data
);
380 data
[data_size
] = subblock_size
;
381 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
382 if (FAILED(hr
) || bytesread
!= subblock_size
)
384 HeapFree(GetProcessHeap(), 0, data
);
387 data_size
+= subblock_size
+ 1;
390 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
) * 2);
393 HeapFree(GetProcessHeap(), 0, data
);
394 return E_OUTOFMEMORY
;
397 for (i
= 0; i
< 2; i
++)
399 PropVariantInit(&result
[i
].schema
);
400 PropVariantInit(&result
[i
].id
);
401 PropVariantInit(&result
[i
].value
);
404 result
[0].id
.vt
= VT_LPWSTR
;
405 result
[0].id
.u
.pwszVal
= strdupAtoW("Application");
406 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
407 result
[0].value
.u
.caub
.cElems
= sizeof(ape_data
.application
);
408 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
409 memcpy(result
[0].value
.u
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
411 result
[1].id
.vt
= VT_LPWSTR
;
412 result
[1].id
.u
.pwszVal
= strdupAtoW("Data");
413 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
414 result
[1].value
.u
.caub
.cElems
= data_size
;
415 result
[1].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, data_size
);
416 memcpy(result
[1].value
.u
.caub
.pElems
, data
, data_size
);
418 HeapFree(GetProcessHeap(), 0, data
);
426 static const MetadataHandlerVtbl APEReader_Vtbl
= {
428 &CLSID_WICAPEMetadataReader
,
432 HRESULT
APEReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
434 return MetadataReader_Create(&APEReader_Vtbl
, pUnkOuter
, iid
, ppv
);
437 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
438 MetadataItem
**items
, DWORD
*count
)
440 #include "pshpack1.h"
441 struct gif_extenstion
443 BYTE extension_introducer
;
444 BYTE extension_label
;
448 ULONG bytesread
, data_size
;
449 MetadataItem
*result
;
456 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
457 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
458 if (ext_data
.extension_introducer
!= 0x21 || ext_data
.extension_label
!= 0xfe)
466 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
467 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
469 HeapFree(GetProcessHeap(), 0, data
);
472 if (!subblock_size
) break;
475 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
);
478 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
);
481 HeapFree(GetProcessHeap(), 0, data
);
486 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
487 if (FAILED(hr
) || bytesread
!= subblock_size
)
489 HeapFree(GetProcessHeap(), 0, data
);
492 data_size
+= subblock_size
;
495 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem
));
498 HeapFree(GetProcessHeap(), 0, data
);
499 return E_OUTOFMEMORY
;
502 PropVariantInit(&result
->schema
);
503 PropVariantInit(&result
->id
);
504 PropVariantInit(&result
->value
);
506 result
->id
.vt
= VT_LPWSTR
;
507 result
->id
.u
.pwszVal
= strdupAtoW("TextEntry");
508 result
->value
.vt
= VT_LPSTR
;
509 result
->value
.u
.pszVal
= HeapAlloc(GetProcessHeap(), 0, data_size
+ 1);
510 memcpy(result
->value
.u
.pszVal
, data
, data_size
);
511 result
->value
.u
.pszVal
[data_size
] = 0;
513 HeapFree(GetProcessHeap(), 0, data
);
521 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
523 &CLSID_WICGifCommentMetadataReader
,
524 load_GifComment_metadata
527 HRESULT
GifCommentReader_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void **ppv
)
529 return MetadataReader_Create(&GifCommentReader_Vtbl
, pUnkOuter
, iid
, ppv
);
532 static IStream
*create_stream(const void *data
, int data_size
)
539 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
540 if (!hdata
) return NULL
;
542 locked_data
= GlobalLock(hdata
);
543 memcpy(locked_data
, data
, data_size
);
546 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
547 return FAILED(hr
) ? NULL
: stream
;
551 IWICBitmapDecoder IWICBitmapDecoder_iface
;
552 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
553 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
557 CRITICAL_SECTION lock
;
561 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
562 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
568 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
570 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
573 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
575 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
578 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
580 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
583 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
585 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
588 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
591 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
592 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
594 if (!ppv
) return E_INVALIDARG
;
596 if (IsEqualIID(&IID_IUnknown
, iid
) ||
597 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
598 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
600 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
602 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
604 *ppv
= &This
->IWICMetadataBlockReader_iface
;
609 return E_NOINTERFACE
;
612 IUnknown_AddRef((IUnknown
*)*ppv
);
616 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
618 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
619 ULONG ref
= InterlockedIncrement(&This
->ref
);
621 TRACE("(%p) refcount=%u\n", iface
, ref
);
626 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
628 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
629 ULONG ref
= InterlockedDecrement(&This
->ref
);
631 TRACE("(%p) refcount=%u\n", iface
, ref
);
635 IUnknown_Release((IUnknown
*)This
->parent
);
636 HeapFree(GetProcessHeap(), 0, This
);
642 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
643 UINT
*puiWidth
, UINT
*puiHeight
)
645 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
646 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
648 *puiWidth
= This
->frame
->ImageDesc
.Width
;
649 *puiHeight
= This
->frame
->ImageDesc
.Height
;
654 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
655 WICPixelFormatGUID
*pPixelFormat
)
657 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
662 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
663 double *pDpiX
, double *pDpiY
)
665 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
666 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
667 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
668 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
670 *pDpiX
= 96.0 / aspect
;
676 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
677 IWICPalette
*pIPalette
)
679 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
680 WICColor colors
[256];
681 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
684 TRACE("(%p,%p)\n", iface
, pIPalette
);
686 if (!cm
) cm
= This
->parent
->gif
->SColorMap
;
688 if (cm
->ColorCount
> 256)
690 ERR("GIF contains %i colors???\n", cm
->ColorCount
);
694 for (i
= 0; i
< cm
->ColorCount
; i
++) {
695 colors
[i
] = 0xff000000| /* alpha */
696 cm
->Colors
[i
].Red
<< 16|
697 cm
->Colors
[i
].Green
<< 8|
701 /* look for the transparent color extension */
702 for (i
= 0; i
< This
->frame
->ExtensionBlockCount
; ++i
) {
703 eb
= This
->frame
->ExtensionBlocks
+ i
;
704 if (eb
->Function
== 0xF9 && eb
->ByteCount
== 4) {
705 if ((eb
->Bytes
[0] & 1) == 1) {
706 trans
= (unsigned char)eb
->Bytes
[3];
707 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
713 IWICPalette_InitializeCustom(pIPalette
, colors
, cm
->ColorCount
);
718 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
719 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
720 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
722 UINT row_offset
; /* number of bytes into the source rows where the data starts */
732 rect
.Width
= srcwidth
;
733 rect
.Height
= srcheight
;
738 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
742 if (dststride
< rc
->Width
)
745 if ((dststride
* rc
->Height
) > dstbuffersize
)
751 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
754 src
= srcbuffer
+ srcstride
* (y
/8);
756 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
758 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
760 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
762 memcpy(dst
, src
, rc
->Width
);
768 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
769 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
771 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
772 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
774 if (This
->frame
->ImageDesc
.Interlace
)
776 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
777 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
778 prc
, cbStride
, cbBufferSize
, pbBuffer
);
782 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
783 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
784 prc
, cbStride
, cbBufferSize
, pbBuffer
);
788 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
789 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
791 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
792 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
795 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
796 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
798 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
799 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
802 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
803 IWICBitmapSource
**ppIThumbnail
)
805 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
806 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
809 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
810 GifFrameDecode_QueryInterface
,
811 GifFrameDecode_AddRef
,
812 GifFrameDecode_Release
,
813 GifFrameDecode_GetSize
,
814 GifFrameDecode_GetPixelFormat
,
815 GifFrameDecode_GetResolution
,
816 GifFrameDecode_CopyPalette
,
817 GifFrameDecode_CopyPixels
,
818 GifFrameDecode_GetMetadataQueryReader
,
819 GifFrameDecode_GetColorContexts
,
820 GifFrameDecode_GetThumbnail
823 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
824 REFIID iid
, void **ppv
)
826 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
827 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
830 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
832 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
833 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
836 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
838 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
839 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
842 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
845 TRACE("(%p,%p)\n", iface
, guid
);
847 if (!guid
) return E_INVALIDARG
;
849 *guid
= GUID_ContainerFormatGif
;
853 static const void *get_GCE_data(GifFrameDecode
*This
)
857 for (i
= 0; i
< This
->frame
->ExtensionBlockCount
; i
++)
859 if (This
->frame
->ExtensionBlocks
[i
].Function
== GRAPHICS_EXT_FUNC_CODE
&&
860 This
->frame
->ExtensionBlocks
[i
].ByteCount
== 4)
861 return This
->frame
->ExtensionBlocks
[i
].Bytes
;
866 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
869 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
871 TRACE("%p,%p\n", iface
, count
);
873 if (!count
) return E_INVALIDARG
;
876 if (get_GCE_data(This
)) *count
+= 1;
880 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
883 IWICMetadataReader
*metadata_reader
;
884 IWICPersistStream
*persist
;
886 struct image_descriptor IMD_data
;
888 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
890 hr
= CoCreateInstance(&CLSID_WICIMDMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
891 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
892 if (FAILED(hr
)) return hr
;
894 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
897 IWICMetadataReader_Release(metadata_reader
);
901 /* recreate IMD structure from GIF decoder data */
902 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
903 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
904 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
905 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
908 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
909 if (This
->frame
->ImageDesc
.ColorMap
)
911 /* local_color_table_flag */
912 IMD_data
.packed
|= 1 << 7;
913 /* local_color_table_size */
914 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
916 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
919 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
920 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
921 IStream_Release(stream
);
923 IWICPersistStream_Release(persist
);
925 *reader
= metadata_reader
;
929 static HRESULT
create_GCE_metadata_reader(const void *GCE_data
, IWICMetadataReader
**reader
)
932 IWICMetadataReader
*metadata_reader
;
933 IWICPersistStream
*persist
;
936 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
938 hr
= CoCreateInstance(&CLSID_WICGCEMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
939 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
940 if (FAILED(hr
)) return hr
;
942 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
945 IWICMetadataReader_Release(metadata_reader
);
949 stream
= create_stream(GCE_data
, 4);
950 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
951 IStream_Release(stream
);
953 IWICPersistStream_Release(persist
);
955 *reader
= metadata_reader
;
959 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
960 UINT index
, IWICMetadataReader
**reader
)
962 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
963 UINT block_count
= 1;
964 const void *GCE_data
;
966 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
968 GCE_data
= get_GCE_data(This
);
969 if (GCE_data
) block_count
++;
970 /* FIXME: add support for Application Extension metadata block
971 APE_data = get_APE_data(This);
972 if (APE_data) block_count++;
974 if (!reader
|| index
>= block_count
) return E_INVALIDARG
;
977 return create_IMD_metadata_reader(This
, reader
);
979 if (index
== 1 && GCE_data
)
980 return create_GCE_metadata_reader(GCE_data
, reader
);
982 /* FIXME: add support for Application Extension metadata block
984 return create_APE_metadata_reader(APE_data, reader);
989 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
990 IEnumUnknown
**enumerator
)
992 FIXME("(%p,%p): stub\n", iface
, enumerator
);
996 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
998 GifFrameDecode_Block_QueryInterface
,
999 GifFrameDecode_Block_AddRef
,
1000 GifFrameDecode_Block_Release
,
1001 GifFrameDecode_Block_GetContainerFormat
,
1002 GifFrameDecode_Block_GetCount
,
1003 GifFrameDecode_Block_GetReaderByIndex
,
1004 GifFrameDecode_Block_GetEnumerator
1007 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1010 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1011 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1013 if (!ppv
) return E_INVALIDARG
;
1015 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1016 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1018 *ppv
= &This
->IWICBitmapDecoder_iface
;
1020 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1022 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1027 return E_NOINTERFACE
;
1030 IUnknown_AddRef((IUnknown
*)*ppv
);
1034 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1036 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1037 ULONG ref
= InterlockedIncrement(&This
->ref
);
1039 TRACE("(%p) refcount=%u\n", iface
, ref
);
1044 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1046 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1047 ULONG ref
= InterlockedDecrement(&This
->ref
);
1049 TRACE("(%p) refcount=%u\n", iface
, ref
);
1053 This
->lock
.DebugInfo
->Spare
[0] = 0;
1054 DeleteCriticalSection(&This
->lock
);
1055 DGifCloseFile(This
->gif
);
1056 HeapFree(GetProcessHeap(), 0, This
);
1062 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1063 DWORD
*pdwCapability
)
1065 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
1069 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1070 IStream
*stream
= gif
->UserData
;
1076 ERR("attempting to read file after initialization\n");
1080 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1081 if (hr
!= S_OK
) bytesread
= 0;
1085 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1086 WICDecodeOptions cacheOptions
)
1088 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1092 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1094 EnterCriticalSection(&This
->lock
);
1096 if (This
->initialized
|| This
->gif
)
1098 WARN("already initialized\n");
1099 LeaveCriticalSection(&This
->lock
);
1100 return WINCODEC_ERR_WRONGSTATE
;
1103 /* seek to start of stream */
1105 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1107 /* read all data from the stream */
1108 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1111 LeaveCriticalSection(&This
->lock
);
1115 ret
= DGifSlurp(This
->gif
);
1116 if (ret
== GIF_ERROR
)
1118 LeaveCriticalSection(&This
->lock
);
1122 /* make sure we don't use the stream after this method returns */
1123 This
->gif
->UserData
= NULL
;
1126 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1127 IStream_Read(pIStream
, &This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1129 This
->initialized
= TRUE
;
1131 LeaveCriticalSection(&This
->lock
);
1136 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1137 GUID
*pguidContainerFormat
)
1139 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1143 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1144 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1147 IWICComponentInfo
*compinfo
;
1149 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1151 hr
= CreateComponentInfo(&CLSID_WICGifDecoder
, &compinfo
);
1152 if (FAILED(hr
)) return hr
;
1154 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1155 (void**)ppIDecoderInfo
);
1157 IWICComponentInfo_Release(compinfo
);
1162 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
1163 IWICPalette
*pIPalette
)
1165 TRACE("(%p,%p)\n", iface
, pIPalette
);
1166 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
1169 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1170 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1172 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1173 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1176 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1177 IWICBitmapSource
**ppIBitmapSource
)
1179 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1180 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1183 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1184 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1186 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1187 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1190 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1191 IWICBitmapSource
**ppIThumbnail
)
1193 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1194 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1197 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1200 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1201 TRACE("(%p,%p)\n", iface
, pCount
);
1203 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
1205 *pCount
= This
->gif
->ImageCount
;
1207 TRACE("<- %u\n", *pCount
);
1212 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1213 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1215 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1216 GifFrameDecode
*result
;
1217 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1219 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
1221 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1223 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1224 if (!result
) return E_OUTOFMEMORY
;
1226 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1227 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1229 result
->frame
= &This
->gif
->SavedImages
[index
];
1230 IWICBitmapDecoder_AddRef(iface
);
1231 result
->parent
= This
;
1233 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1238 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1239 GifDecoder_QueryInterface
,
1242 GifDecoder_QueryCapability
,
1243 GifDecoder_Initialize
,
1244 GifDecoder_GetContainerFormat
,
1245 GifDecoder_GetDecoderInfo
,
1246 GifDecoder_CopyPalette
,
1247 GifDecoder_GetMetadataQueryReader
,
1248 GifDecoder_GetPreview
,
1249 GifDecoder_GetColorContexts
,
1250 GifDecoder_GetThumbnail
,
1251 GifDecoder_GetFrameCount
,
1255 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1256 REFIID iid
, void **ppv
)
1258 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1259 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1262 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1264 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1265 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1268 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1270 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1271 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1274 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1277 TRACE("(%p,%p)\n", iface
, guid
);
1279 if (!guid
) return E_INVALIDARG
;
1281 *guid
= GUID_ContainerFormatGif
;
1285 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1288 TRACE("%p,%p\n", iface
, count
);
1290 if (!count
) return E_INVALIDARG
;
1296 static HRESULT
create_LSD_metadata_reader(GifDecoder
*This
, IWICMetadataReader
**reader
)
1299 IWICMetadataReader
*metadata_reader
;
1300 IWICPersistStream
*persist
;
1303 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
1305 hr
= CoCreateInstance(&CLSID_WICLSDMetadataReader
, NULL
, CLSCTX_INPROC_SERVER
,
1306 &IID_IWICMetadataReader
, (void **)&metadata_reader
);
1307 if (FAILED(hr
)) return hr
;
1309 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
1312 IWICMetadataReader_Release(metadata_reader
);
1316 stream
= create_stream(This
->LSD_data
, sizeof(This
->LSD_data
));
1317 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionsDefault
);
1318 IStream_Release(stream
);
1320 IWICPersistStream_Release(persist
);
1322 *reader
= metadata_reader
;
1326 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1327 UINT index
, IWICMetadataReader
**reader
)
1329 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1331 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1333 if (!reader
|| index
!= 0) return E_INVALIDARG
;
1335 return create_LSD_metadata_reader(This
, reader
);
1338 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1339 IEnumUnknown
**enumerator
)
1341 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1345 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1347 GifDecoder_Block_QueryInterface
,
1348 GifDecoder_Block_AddRef
,
1349 GifDecoder_Block_Release
,
1350 GifDecoder_Block_GetContainerFormat
,
1351 GifDecoder_Block_GetCount
,
1352 GifDecoder_Block_GetReaderByIndex
,
1353 GifDecoder_Block_GetEnumerator
1356 HRESULT
GifDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
1361 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
1365 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
1367 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1368 if (!This
) return E_OUTOFMEMORY
;
1370 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1371 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1373 This
->initialized
= FALSE
;
1375 InitializeCriticalSection(&This
->lock
);
1376 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1378 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1379 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);