crypt32/tests: CertAddCertificateLinkToStore is not present on W98.
[wine/multimedia.git] / dlls / windowscodecs / gifformat.c
blob5cbdc261caa7ac558091766c8176aa3612da1990
1 /*
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
19 #include "config.h"
21 #include <stdarg.h>
23 #define COBJMACROS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "objbase.h"
28 #include "wincodec.h"
30 #include "ungif.h"
32 #include "wincodecs_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
38 typedef struct {
39 const IWICBitmapDecoderVtbl *lpVtbl;
40 LONG ref;
41 BOOL initialized;
42 GifFileType *gif;
43 CRITICAL_SECTION lock;
44 } GifDecoder;
46 typedef struct {
47 const IWICBitmapFrameDecodeVtbl *lpVtbl;
48 LONG ref;
49 SavedImage *frame;
50 GifDecoder *parent;
51 } GifFrameDecode;
53 static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
54 void **ppv)
56 GifFrameDecode *This = (GifFrameDecode*)iface;
57 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
59 if (!ppv) return E_INVALIDARG;
61 if (IsEqualIID(&IID_IUnknown, iid) ||
62 IsEqualIID(&IID_IWICBitmapSource, iid) ||
63 IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
65 *ppv = This;
67 else
69 *ppv = NULL;
70 return E_NOINTERFACE;
73 IUnknown_AddRef((IUnknown*)*ppv);
74 return S_OK;
77 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
79 GifFrameDecode *This = (GifFrameDecode*)iface;
80 ULONG ref = InterlockedIncrement(&This->ref);
82 TRACE("(%p) refcount=%u\n", iface, ref);
84 return ref;
87 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
89 GifFrameDecode *This = (GifFrameDecode*)iface;
90 ULONG ref = InterlockedDecrement(&This->ref);
92 TRACE("(%p) refcount=%u\n", iface, ref);
94 if (ref == 0)
96 IUnknown_Release((IUnknown*)This->parent);
97 HeapFree(GetProcessHeap(), 0, This);
100 return ref;
103 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
104 UINT *puiWidth, UINT *puiHeight)
106 GifFrameDecode *This = (GifFrameDecode*)iface;
107 TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
109 *puiWidth = This->frame->ImageDesc.Width;
110 *puiHeight = This->frame->ImageDesc.Height;
112 return S_OK;
115 static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
116 WICPixelFormatGUID *pPixelFormat)
118 memcpy(pPixelFormat, &GUID_WICPixelFormat8bppIndexed, sizeof(GUID));
120 return S_OK;
123 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
124 double *pDpiX, double *pDpiY)
126 GifFrameDecode *This = (GifFrameDecode*)iface;
127 const GifWord aspect_word = This->parent->gif->SAspectRatio;
128 const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
129 TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
131 *pDpiX = 96.0 / aspect;
132 *pDpiY = 96.0;
134 return S_OK;
137 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
138 IWICPalette *pIPalette)
140 GifFrameDecode *This = (GifFrameDecode*)iface;
141 WICColor colors[256];
142 ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
143 int i, trans;
144 ExtensionBlock *eb;
145 TRACE("(%p,%p)\n", iface, pIPalette);
147 if (!cm) cm = This->parent->gif->SColorMap;
149 if (cm->ColorCount > 256)
151 ERR("GIF contains %i colors???\n", cm->ColorCount);
152 return E_FAIL;
155 for (i = 0; i < cm->ColorCount; i++) {
156 colors[i] = 0xff000000| /* alpha */
157 cm->Colors[i].Red << 16|
158 cm->Colors[i].Green << 8|
159 cm->Colors[i].Blue;
162 /* look for the transparent color extension */
163 for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
164 eb = This->frame->ExtensionBlocks + i;
165 if (eb->Function == 0xF9 && eb->ByteCount == 4) {
166 if ((eb->Bytes[0] & 1) == 1) {
167 trans = (unsigned char)eb->Bytes[3];
168 colors[trans] &= 0xffffff; /* set alpha to 0 */
169 break;
174 IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
176 return S_OK;
179 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
180 UINT srcwidth, UINT srcheight, INT srcstride, const WICRect *rc,
181 UINT dststride, UINT dstbuffersize, BYTE *dstbuffer)
183 UINT row_offset; /* number of bytes into the source rows where the data starts */
184 const BYTE *src;
185 BYTE *dst;
186 UINT y;
187 WICRect rect;
189 if (!rc)
191 rect.X = 0;
192 rect.Y = 0;
193 rect.Width = srcwidth;
194 rect.Height = srcheight;
195 rc = &rect;
197 else
199 if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
200 return E_INVALIDARG;
203 if (dststride < rc->Width)
204 return E_INVALIDARG;
206 if ((dststride * rc->Height) > dstbuffersize)
207 return E_INVALIDARG;
209 row_offset = rc->X;
211 dst = dstbuffer;
212 for (y=rc->Y; y-rc->Y < rc->Height; y++)
214 if (y%8 == 0)
215 src = srcbuffer + srcstride * (y/8);
216 else if (y%4 == 0)
217 src = srcbuffer + srcstride * ((srcheight+7)/8 + y/8);
218 else if (y%2 == 0)
219 src = srcbuffer + srcstride * ((srcheight+3)/4 + y/4);
220 else /* y%2 == 1 */
221 src = srcbuffer + srcstride * ((srcheight+1)/2 + y/2);
222 src += row_offset;
223 memcpy(dst, src, rc->Width);
224 dst += dststride;
226 return S_OK;
229 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
230 const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
232 GifFrameDecode *This = (GifFrameDecode*)iface;
233 TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
235 if (This->frame->ImageDesc.Interlace)
237 return copy_interlaced_pixels(This->frame->RasterBits, This->frame->ImageDesc.Width,
238 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
239 prc, cbStride, cbBufferSize, pbBuffer);
241 else
243 return copy_pixels(8, This->frame->RasterBits, This->frame->ImageDesc.Width,
244 This->frame->ImageDesc.Height, This->frame->ImageDesc.Width,
245 prc, cbStride, cbBufferSize, pbBuffer);
249 static HRESULT WINAPI GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
250 IWICMetadataQueryReader **ppIMetadataQueryReader)
252 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
253 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
256 static HRESULT WINAPI GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
257 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
259 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
260 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
263 static HRESULT WINAPI GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
264 IWICBitmapSource **ppIThumbnail)
266 TRACE("(%p,%p)\n", iface, ppIThumbnail);
267 return WINCODEC_ERR_CODECNOTHUMBNAIL;
270 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = {
271 GifFrameDecode_QueryInterface,
272 GifFrameDecode_AddRef,
273 GifFrameDecode_Release,
274 GifFrameDecode_GetSize,
275 GifFrameDecode_GetPixelFormat,
276 GifFrameDecode_GetResolution,
277 GifFrameDecode_CopyPalette,
278 GifFrameDecode_CopyPixels,
279 GifFrameDecode_GetMetadataQueryReader,
280 GifFrameDecode_GetColorContexts,
281 GifFrameDecode_GetThumbnail
284 static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
285 void **ppv)
287 GifDecoder *This = (GifDecoder*)iface;
288 TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
290 if (!ppv) return E_INVALIDARG;
292 if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid))
294 *ppv = This;
296 else
298 *ppv = NULL;
299 return E_NOINTERFACE;
302 IUnknown_AddRef((IUnknown*)*ppv);
303 return S_OK;
306 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
308 GifDecoder *This = (GifDecoder*)iface;
309 ULONG ref = InterlockedIncrement(&This->ref);
311 TRACE("(%p) refcount=%u\n", iface, ref);
313 return ref;
316 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
318 GifDecoder *This = (GifDecoder*)iface;
319 ULONG ref = InterlockedDecrement(&This->ref);
321 TRACE("(%p) refcount=%u\n", iface, ref);
323 if (ref == 0)
325 This->lock.DebugInfo->Spare[0] = 0;
326 DeleteCriticalSection(&This->lock);
327 DGifCloseFile(This->gif);
328 HeapFree(GetProcessHeap(), 0, This);
331 return ref;
334 static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
335 DWORD *pdwCapability)
337 FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
338 return E_NOTIMPL;
341 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
342 IStream *stream = gif->UserData;
343 ULONG bytesread;
344 HRESULT hr;
346 if (!stream)
348 ERR("attempting to read file after initialization\n");
349 return 0;
352 hr = IStream_Read(stream, data, len, &bytesread);
353 if (hr != S_OK) bytesread = 0;
354 return bytesread;
357 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
358 WICDecodeOptions cacheOptions)
360 GifDecoder *This = (GifDecoder*)iface;
361 LARGE_INTEGER seek;
362 int ret;
364 TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions);
366 EnterCriticalSection(&This->lock);
368 if (This->initialized || This->gif)
370 WARN("already initialized\n");
371 LeaveCriticalSection(&This->lock);
372 return WINCODEC_ERR_WRONGSTATE;
375 /* seek to start of stream */
376 seek.QuadPart = 0;
377 IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
379 /* read all data from the stream */
380 This->gif = DGifOpen((void*)pIStream, _gif_inputfunc);
381 if (!This->gif)
383 LeaveCriticalSection(&This->lock);
384 return E_FAIL;
387 ret = DGifSlurp(This->gif);
388 if (ret == GIF_ERROR)
390 LeaveCriticalSection(&This->lock);
391 return E_FAIL;
394 /* make sure we don't use the stream after this method returns */
395 This->gif->UserData = NULL;
397 This->initialized = TRUE;
399 LeaveCriticalSection(&This->lock);
401 return S_OK;
404 static HRESULT WINAPI GifDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
405 GUID *pguidContainerFormat)
407 memcpy(pguidContainerFormat, &GUID_ContainerFormatGif, sizeof(GUID));
408 return S_OK;
411 static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
412 IWICBitmapDecoderInfo **ppIDecoderInfo)
414 HRESULT hr;
415 IWICComponentInfo *compinfo;
417 TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
419 hr = CreateComponentInfo(&CLSID_WICGifDecoder, &compinfo);
420 if (FAILED(hr)) return hr;
422 hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
423 (void**)ppIDecoderInfo);
425 IWICComponentInfo_Release(compinfo);
427 return hr;
430 static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
431 IWICPalette *pIPalette)
433 TRACE("(%p,%p)\n", iface, pIPalette);
434 return WINCODEC_ERR_PALETTEUNAVAILABLE;
437 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
438 IWICMetadataQueryReader **ppIMetadataQueryReader)
440 TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
441 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
444 static HRESULT WINAPI GifDecoder_GetPreview(IWICBitmapDecoder *iface,
445 IWICBitmapSource **ppIBitmapSource)
447 TRACE("(%p,%p)\n", iface, ppIBitmapSource);
448 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
451 static HRESULT WINAPI GifDecoder_GetColorContexts(IWICBitmapDecoder *iface,
452 UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
454 TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
455 return WINCODEC_ERR_UNSUPPORTEDOPERATION;
458 static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
459 IWICBitmapSource **ppIThumbnail)
461 TRACE("(%p,%p)\n", iface, ppIThumbnail);
462 return WINCODEC_ERR_CODECNOTHUMBNAIL;
465 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
466 UINT *pCount)
468 GifDecoder *This = (GifDecoder*)iface;
469 TRACE("(%p,%p)\n", iface, pCount);
471 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
473 *pCount = This->gif->ImageCount;
475 TRACE("<- %u\n", *pCount);
477 return S_OK;
480 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
481 UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
483 GifDecoder *This = (GifDecoder*)iface;
484 GifFrameDecode *result;
485 TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
487 if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
489 if (index >= This->gif->ImageCount) return E_INVALIDARG;
491 result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
492 if (!result) return E_OUTOFMEMORY;
494 result->lpVtbl = &GifFrameDecode_Vtbl;
495 result->ref = 1;
496 result->frame = &This->gif->SavedImages[index];
497 IWICBitmapDecoder_AddRef(iface);
498 result->parent = This;
500 *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
502 return S_OK;
505 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
506 GifDecoder_QueryInterface,
507 GifDecoder_AddRef,
508 GifDecoder_Release,
509 GifDecoder_QueryCapability,
510 GifDecoder_Initialize,
511 GifDecoder_GetContainerFormat,
512 GifDecoder_GetDecoderInfo,
513 GifDecoder_CopyPalette,
514 GifDecoder_GetMetadataQueryReader,
515 GifDecoder_GetPreview,
516 GifDecoder_GetColorContexts,
517 GifDecoder_GetThumbnail,
518 GifDecoder_GetFrameCount,
519 GifDecoder_GetFrame
522 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
524 GifDecoder *This;
525 HRESULT ret;
527 TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
529 *ppv = NULL;
531 if (pUnkOuter) return CLASS_E_NOAGGREGATION;
533 This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
534 if (!This) return E_OUTOFMEMORY;
536 This->lpVtbl = &GifDecoder_Vtbl;
537 This->ref = 1;
538 This->initialized = FALSE;
539 This->gif = NULL;
540 InitializeCriticalSection(&This->lock);
541 This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
543 ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
544 IUnknown_Release((IUnknown*)This);
546 return ret;