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
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
39 IWICBitmapDecoder IWICBitmapDecoder_iface
;
43 CRITICAL_SECTION lock
;
47 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
53 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
55 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
58 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
60 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
63 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
66 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
67 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
69 if (!ppv
) return E_INVALIDARG
;
71 if (IsEqualIID(&IID_IUnknown
, iid
) ||
72 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
73 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
75 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
83 IUnknown_AddRef((IUnknown
*)*ppv
);
87 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
89 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
90 ULONG ref
= InterlockedIncrement(&This
->ref
);
92 TRACE("(%p) refcount=%u\n", iface
, ref
);
97 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
99 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
100 ULONG ref
= InterlockedDecrement(&This
->ref
);
102 TRACE("(%p) refcount=%u\n", iface
, ref
);
106 IUnknown_Release((IUnknown
*)This
->parent
);
107 HeapFree(GetProcessHeap(), 0, This
);
113 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
114 UINT
*puiWidth
, UINT
*puiHeight
)
116 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
117 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
119 *puiWidth
= This
->frame
->ImageDesc
.Width
;
120 *puiHeight
= This
->frame
->ImageDesc
.Height
;
125 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
126 WICPixelFormatGUID
*pPixelFormat
)
128 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
133 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
134 double *pDpiX
, double *pDpiY
)
136 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
137 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
138 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
139 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
141 *pDpiX
= 96.0 / aspect
;
147 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
148 IWICPalette
*pIPalette
)
150 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
151 WICColor colors
[256];
152 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
155 TRACE("(%p,%p)\n", iface
, pIPalette
);
157 if (!cm
) cm
= This
->parent
->gif
->SColorMap
;
159 if (cm
->ColorCount
> 256)
161 ERR("GIF contains %i colors???\n", cm
->ColorCount
);
165 for (i
= 0; i
< cm
->ColorCount
; i
++) {
166 colors
[i
] = 0xff000000| /* alpha */
167 cm
->Colors
[i
].Red
<< 16|
168 cm
->Colors
[i
].Green
<< 8|
172 /* look for the transparent color extension */
173 for (i
= 0; i
< This
->frame
->ExtensionBlockCount
; ++i
) {
174 eb
= This
->frame
->ExtensionBlocks
+ i
;
175 if (eb
->Function
== 0xF9 && eb
->ByteCount
== 4) {
176 if ((eb
->Bytes
[0] & 1) == 1) {
177 trans
= (unsigned char)eb
->Bytes
[3];
178 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
184 IWICPalette_InitializeCustom(pIPalette
, colors
, cm
->ColorCount
);
189 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
190 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
191 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
193 UINT row_offset
; /* number of bytes into the source rows where the data starts */
203 rect
.Width
= srcwidth
;
204 rect
.Height
= srcheight
;
209 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
213 if (dststride
< rc
->Width
)
216 if ((dststride
* rc
->Height
) > dstbuffersize
)
222 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
225 src
= srcbuffer
+ srcstride
* (y
/8);
227 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
229 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
231 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
233 memcpy(dst
, src
, rc
->Width
);
239 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
240 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
242 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
243 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
245 if (This
->frame
->ImageDesc
.Interlace
)
247 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
248 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
249 prc
, cbStride
, cbBufferSize
, pbBuffer
);
253 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
254 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
255 prc
, cbStride
, cbBufferSize
, pbBuffer
);
259 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
260 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
262 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
263 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
266 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
267 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
269 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
270 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
273 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
274 IWICBitmapSource
**ppIThumbnail
)
276 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
277 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
280 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
281 GifFrameDecode_QueryInterface
,
282 GifFrameDecode_AddRef
,
283 GifFrameDecode_Release
,
284 GifFrameDecode_GetSize
,
285 GifFrameDecode_GetPixelFormat
,
286 GifFrameDecode_GetResolution
,
287 GifFrameDecode_CopyPalette
,
288 GifFrameDecode_CopyPixels
,
289 GifFrameDecode_GetMetadataQueryReader
,
290 GifFrameDecode_GetColorContexts
,
291 GifFrameDecode_GetThumbnail
294 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
297 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
298 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
300 if (!ppv
) return E_INVALIDARG
;
302 if (IsEqualIID(&IID_IUnknown
, iid
) ||
303 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
305 *ppv
= &This
->IWICBitmapDecoder_iface
;
310 return E_NOINTERFACE
;
313 IUnknown_AddRef((IUnknown
*)*ppv
);
317 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
319 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
320 ULONG ref
= InterlockedIncrement(&This
->ref
);
322 TRACE("(%p) refcount=%u\n", iface
, ref
);
327 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
329 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
330 ULONG ref
= InterlockedDecrement(&This
->ref
);
332 TRACE("(%p) refcount=%u\n", iface
, ref
);
336 This
->lock
.DebugInfo
->Spare
[0] = 0;
337 DeleteCriticalSection(&This
->lock
);
338 DGifCloseFile(This
->gif
);
339 HeapFree(GetProcessHeap(), 0, This
);
345 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
346 DWORD
*pdwCapability
)
348 FIXME("(%p,%p,%p): stub\n", iface
, pIStream
, pdwCapability
);
352 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
353 IStream
*stream
= gif
->UserData
;
359 ERR("attempting to read file after initialization\n");
363 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
364 if (hr
!= S_OK
) bytesread
= 0;
368 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
369 WICDecodeOptions cacheOptions
)
371 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
375 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
377 EnterCriticalSection(&This
->lock
);
379 if (This
->initialized
|| This
->gif
)
381 WARN("already initialized\n");
382 LeaveCriticalSection(&This
->lock
);
383 return WINCODEC_ERR_WRONGSTATE
;
386 /* seek to start of stream */
388 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
390 /* read all data from the stream */
391 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
394 LeaveCriticalSection(&This
->lock
);
398 ret
= DGifSlurp(This
->gif
);
399 if (ret
== GIF_ERROR
)
401 LeaveCriticalSection(&This
->lock
);
405 /* make sure we don't use the stream after this method returns */
406 This
->gif
->UserData
= NULL
;
408 This
->initialized
= TRUE
;
410 LeaveCriticalSection(&This
->lock
);
415 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
416 GUID
*pguidContainerFormat
)
418 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
422 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
423 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
426 IWICComponentInfo
*compinfo
;
428 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
430 hr
= CreateComponentInfo(&CLSID_WICGifDecoder
, &compinfo
);
431 if (FAILED(hr
)) return hr
;
433 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
434 (void**)ppIDecoderInfo
);
436 IWICComponentInfo_Release(compinfo
);
441 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
,
442 IWICPalette
*pIPalette
)
444 TRACE("(%p,%p)\n", iface
, pIPalette
);
445 return WINCODEC_ERR_PALETTEUNAVAILABLE
;
448 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
449 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
451 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
452 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
455 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
456 IWICBitmapSource
**ppIBitmapSource
)
458 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
459 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
462 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
463 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
465 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
466 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
469 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
470 IWICBitmapSource
**ppIThumbnail
)
472 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
473 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
476 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
479 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
480 TRACE("(%p,%p)\n", iface
, pCount
);
482 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
484 *pCount
= This
->gif
->ImageCount
;
486 TRACE("<- %u\n", *pCount
);
491 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
492 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
494 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
495 GifFrameDecode
*result
;
496 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
498 if (!This
->initialized
) return WINCODEC_ERR_NOTINITIALIZED
;
500 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
502 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
503 if (!result
) return E_OUTOFMEMORY
;
505 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
507 result
->frame
= &This
->gif
->SavedImages
[index
];
508 IWICBitmapDecoder_AddRef(iface
);
509 result
->parent
= This
;
511 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
516 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
517 GifDecoder_QueryInterface
,
520 GifDecoder_QueryCapability
,
521 GifDecoder_Initialize
,
522 GifDecoder_GetContainerFormat
,
523 GifDecoder_GetDecoderInfo
,
524 GifDecoder_CopyPalette
,
525 GifDecoder_GetMetadataQueryReader
,
526 GifDecoder_GetPreview
,
527 GifDecoder_GetColorContexts
,
528 GifDecoder_GetThumbnail
,
529 GifDecoder_GetFrameCount
,
533 HRESULT
GifDecoder_CreateInstance(IUnknown
*pUnkOuter
, REFIID iid
, void** ppv
)
538 TRACE("(%p,%s,%p)\n", pUnkOuter
, debugstr_guid(iid
), ppv
);
542 if (pUnkOuter
) return CLASS_E_NOAGGREGATION
;
544 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
545 if (!This
) return E_OUTOFMEMORY
;
547 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
549 This
->initialized
= FALSE
;
551 InitializeCriticalSection(&This
->lock
);
552 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
554 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
555 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);