2 * Copyright 2009 Vincent Povirk for CodeWeavers
3 * Copyright 2012,2016 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
33 #include "wincodecs_private.h"
35 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
45 struct logical_screen_descriptor
51 /* global_color_table_flag : 1;
52 * color_resolution : 3;
54 * global_color_table_size : 3;
56 BYTE background_color_index
;
57 BYTE pixel_aspect_ratio
;
60 struct image_descriptor
67 /* local_color_table_flag : 1;
71 * local_color_table_size : 3;
77 static LPWSTR
strdupAtoW(const char *src
)
79 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
80 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
81 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
85 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
86 MetadataItem
**items
, DWORD
*count
)
88 struct logical_screen_descriptor lsd_data
;
96 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
97 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
99 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 9);
100 if (!result
) return E_OUTOFMEMORY
;
102 for (i
= 0; i
< 9; i
++)
104 PropVariantInit(&result
[i
].schema
);
105 PropVariantInit(&result
[i
].id
);
106 PropVariantInit(&result
[i
].value
);
109 result
[0].id
.vt
= VT_LPWSTR
;
110 result
[0].id
.u
.pwszVal
= strdupAtoW("Signature");
111 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
112 result
[0].value
.u
.caub
.cElems
= sizeof(lsd_data
.signature
);
113 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
114 memcpy(result
[0].value
.u
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
116 result
[1].id
.vt
= VT_LPWSTR
;
117 result
[1].id
.u
.pwszVal
= strdupAtoW("Width");
118 result
[1].value
.vt
= VT_UI2
;
119 result
[1].value
.u
.uiVal
= lsd_data
.width
;
121 result
[2].id
.vt
= VT_LPWSTR
;
122 result
[2].id
.u
.pwszVal
= strdupAtoW("Height");
123 result
[2].value
.vt
= VT_UI2
;
124 result
[2].value
.u
.uiVal
= lsd_data
.height
;
126 result
[3].id
.vt
= VT_LPWSTR
;
127 result
[3].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
128 result
[3].value
.vt
= VT_BOOL
;
129 result
[3].value
.u
.boolVal
= (lsd_data
.packed
>> 7) & 1;
131 result
[4].id
.vt
= VT_LPWSTR
;
132 result
[4].id
.u
.pwszVal
= strdupAtoW("ColorResolution");
133 result
[4].value
.vt
= VT_UI1
;
134 result
[4].value
.u
.bVal
= (lsd_data
.packed
>> 4) & 7;
136 result
[5].id
.vt
= VT_LPWSTR
;
137 result
[5].id
.u
.pwszVal
= strdupAtoW("SortFlag");
138 result
[5].value
.vt
= VT_BOOL
;
139 result
[5].value
.u
.boolVal
= (lsd_data
.packed
>> 3) & 1;
141 result
[6].id
.vt
= VT_LPWSTR
;
142 result
[6].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableSize");
143 result
[6].value
.vt
= VT_UI1
;
144 result
[6].value
.u
.bVal
= lsd_data
.packed
& 7;
146 result
[7].id
.vt
= VT_LPWSTR
;
147 result
[7].id
.u
.pwszVal
= strdupAtoW("BackgroundColorIndex");
148 result
[7].value
.vt
= VT_UI1
;
149 result
[7].value
.u
.bVal
= lsd_data
.background_color_index
;
151 result
[8].id
.vt
= VT_LPWSTR
;
152 result
[8].id
.u
.pwszVal
= strdupAtoW("PixelAspectRatio");
153 result
[8].value
.vt
= VT_UI1
;
154 result
[8].value
.u
.bVal
= lsd_data
.pixel_aspect_ratio
;
162 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
164 &CLSID_WICLSDMetadataReader
,
168 HRESULT
LSDReader_CreateInstance(REFIID iid
, void **ppv
)
170 return MetadataReader_Create(&LSDReader_Vtbl
, iid
, ppv
);
173 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
174 MetadataItem
**items
, DWORD
*count
)
176 struct image_descriptor imd_data
;
179 MetadataItem
*result
;
184 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
185 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
187 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 8);
188 if (!result
) return E_OUTOFMEMORY
;
190 for (i
= 0; i
< 8; i
++)
192 PropVariantInit(&result
[i
].schema
);
193 PropVariantInit(&result
[i
].id
);
194 PropVariantInit(&result
[i
].value
);
197 result
[0].id
.vt
= VT_LPWSTR
;
198 result
[0].id
.u
.pwszVal
= strdupAtoW("Left");
199 result
[0].value
.vt
= VT_UI2
;
200 result
[0].value
.u
.uiVal
= imd_data
.left
;
202 result
[1].id
.vt
= VT_LPWSTR
;
203 result
[1].id
.u
.pwszVal
= strdupAtoW("Top");
204 result
[1].value
.vt
= VT_UI2
;
205 result
[1].value
.u
.uiVal
= imd_data
.top
;
207 result
[2].id
.vt
= VT_LPWSTR
;
208 result
[2].id
.u
.pwszVal
= strdupAtoW("Width");
209 result
[2].value
.vt
= VT_UI2
;
210 result
[2].value
.u
.uiVal
= imd_data
.width
;
212 result
[3].id
.vt
= VT_LPWSTR
;
213 result
[3].id
.u
.pwszVal
= strdupAtoW("Height");
214 result
[3].value
.vt
= VT_UI2
;
215 result
[3].value
.u
.uiVal
= imd_data
.height
;
217 result
[4].id
.vt
= VT_LPWSTR
;
218 result
[4].id
.u
.pwszVal
= strdupAtoW("LocalColorTableFlag");
219 result
[4].value
.vt
= VT_BOOL
;
220 result
[4].value
.u
.boolVal
= (imd_data
.packed
>> 7) & 1;
222 result
[5].id
.vt
= VT_LPWSTR
;
223 result
[5].id
.u
.pwszVal
= strdupAtoW("InterlaceFlag");
224 result
[5].value
.vt
= VT_BOOL
;
225 result
[5].value
.u
.boolVal
= (imd_data
.packed
>> 6) & 1;
227 result
[6].id
.vt
= VT_LPWSTR
;
228 result
[6].id
.u
.pwszVal
= strdupAtoW("SortFlag");
229 result
[6].value
.vt
= VT_BOOL
;
230 result
[6].value
.u
.boolVal
= (imd_data
.packed
>> 5) & 1;
232 result
[7].id
.vt
= VT_LPWSTR
;
233 result
[7].id
.u
.pwszVal
= strdupAtoW("LocalColorTableSize");
234 result
[7].value
.vt
= VT_UI1
;
235 result
[7].value
.u
.bVal
= imd_data
.packed
& 7;
243 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
245 &CLSID_WICIMDMetadataReader
,
249 HRESULT
IMDReader_CreateInstance(REFIID iid
, void **ppv
)
251 return MetadataReader_Create(&IMDReader_Vtbl
, iid
, ppv
);
254 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
255 MetadataItem
**items
, DWORD
*count
)
257 #include "pshpack1.h"
258 struct graphic_control_extension
263 * user_input_flag : 1;
264 * transparency_flag : 1;
267 BYTE transparent_color_index
;
272 MetadataItem
*result
;
277 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
278 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
280 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 5);
281 if (!result
) return E_OUTOFMEMORY
;
283 for (i
= 0; i
< 5; i
++)
285 PropVariantInit(&result
[i
].schema
);
286 PropVariantInit(&result
[i
].id
);
287 PropVariantInit(&result
[i
].value
);
290 result
[0].id
.vt
= VT_LPWSTR
;
291 result
[0].id
.u
.pwszVal
= strdupAtoW("Disposal");
292 result
[0].value
.vt
= VT_UI1
;
293 result
[0].value
.u
.bVal
= (gce_data
.packed
>> 2) & 7;
295 result
[1].id
.vt
= VT_LPWSTR
;
296 result
[1].id
.u
.pwszVal
= strdupAtoW("UserInputFlag");
297 result
[1].value
.vt
= VT_BOOL
;
298 result
[1].value
.u
.boolVal
= (gce_data
.packed
>> 1) & 1;
300 result
[2].id
.vt
= VT_LPWSTR
;
301 result
[2].id
.u
.pwszVal
= strdupAtoW("TransparencyFlag");
302 result
[2].value
.vt
= VT_BOOL
;
303 result
[2].value
.u
.boolVal
= gce_data
.packed
& 1;
305 result
[3].id
.vt
= VT_LPWSTR
;
306 result
[3].id
.u
.pwszVal
= strdupAtoW("Delay");
307 result
[3].value
.vt
= VT_UI2
;
308 result
[3].value
.u
.uiVal
= gce_data
.delay
;
310 result
[4].id
.vt
= VT_LPWSTR
;
311 result
[4].id
.u
.pwszVal
= strdupAtoW("TransparentColorIndex");
312 result
[4].value
.vt
= VT_UI1
;
313 result
[4].value
.u
.bVal
= gce_data
.transparent_color_index
;
321 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
323 &CLSID_WICGCEMetadataReader
,
327 HRESULT
GCEReader_CreateInstance(REFIID iid
, void **ppv
)
329 return MetadataReader_Create(&GCEReader_Vtbl
, iid
, ppv
);
332 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
333 MetadataItem
**items
, DWORD
*count
)
335 #include "pshpack1.h"
336 struct application_extension
338 BYTE extension_introducer
;
339 BYTE extension_label
;
341 BYTE application
[11];
345 ULONG bytesread
, data_size
, i
;
346 MetadataItem
*result
;
353 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
354 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
355 if (ape_data
.extension_introducer
!= 0x21 ||
356 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
357 ape_data
.block_size
!= 11)
365 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
366 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
368 HeapFree(GetProcessHeap(), 0, data
);
371 if (!subblock_size
) break;
374 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
377 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
380 HeapFree(GetProcessHeap(), 0, data
);
385 data
[data_size
] = subblock_size
;
386 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
387 if (FAILED(hr
) || bytesread
!= subblock_size
)
389 HeapFree(GetProcessHeap(), 0, data
);
392 data_size
+= subblock_size
+ 1;
395 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 2);
398 HeapFree(GetProcessHeap(), 0, data
);
399 return E_OUTOFMEMORY
;
402 for (i
= 0; i
< 2; i
++)
404 PropVariantInit(&result
[i
].schema
);
405 PropVariantInit(&result
[i
].id
);
406 PropVariantInit(&result
[i
].value
);
409 result
[0].id
.vt
= VT_LPWSTR
;
410 result
[0].id
.u
.pwszVal
= strdupAtoW("Application");
411 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
412 result
[0].value
.u
.caub
.cElems
= sizeof(ape_data
.application
);
413 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
414 memcpy(result
[0].value
.u
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
416 result
[1].id
.vt
= VT_LPWSTR
;
417 result
[1].id
.u
.pwszVal
= strdupAtoW("Data");
418 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
419 result
[1].value
.u
.caub
.cElems
= data_size
;
420 result
[1].value
.u
.caub
.pElems
= data
;
428 static const MetadataHandlerVtbl APEReader_Vtbl
= {
430 &CLSID_WICAPEMetadataReader
,
434 HRESULT
APEReader_CreateInstance(REFIID iid
, void **ppv
)
436 return MetadataReader_Create(&APEReader_Vtbl
, iid
, ppv
);
439 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
440 MetadataItem
**items
, DWORD
*count
)
442 #include "pshpack1.h"
445 BYTE extension_introducer
;
446 BYTE extension_label
;
450 ULONG bytesread
, data_size
;
451 MetadataItem
*result
;
458 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
459 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
460 if (ext_data
.extension_introducer
!= 0x21 ||
461 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
469 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
470 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
472 HeapFree(GetProcessHeap(), 0, data
);
475 if (!subblock_size
) break;
478 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
481 char *new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
484 HeapFree(GetProcessHeap(), 0, data
);
489 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
490 if (FAILED(hr
) || bytesread
!= subblock_size
)
492 HeapFree(GetProcessHeap(), 0, data
);
495 data_size
+= subblock_size
;
500 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
));
503 HeapFree(GetProcessHeap(), 0, data
);
504 return E_OUTOFMEMORY
;
507 PropVariantInit(&result
->schema
);
508 PropVariantInit(&result
->id
);
509 PropVariantInit(&result
->value
);
511 result
->id
.vt
= VT_LPWSTR
;
512 result
->id
.u
.pwszVal
= strdupAtoW("TextEntry");
513 result
->value
.vt
= VT_LPSTR
;
514 result
->value
.u
.pszVal
= data
;
522 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
524 &CLSID_WICGifCommentMetadataReader
,
525 load_GifComment_metadata
528 HRESULT
GifCommentReader_CreateInstance(REFIID iid
, void **ppv
)
530 return MetadataReader_Create(&GifCommentReader_Vtbl
, iid
, ppv
);
533 static IStream
*create_stream(const void *data
, int data_size
)
540 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
541 if (!hdata
) return NULL
;
543 locked_data
= GlobalLock(hdata
);
544 memcpy(locked_data
, data
, data_size
);
547 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
548 return FAILED(hr
) ? NULL
: stream
;
551 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
552 class_constructor constructor
,
553 IWICMetadataReader
**reader
)
556 IWICMetadataReader
*metadata_reader
;
557 IWICPersistStream
*persist
;
560 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
562 hr
= constructor(&IID_IWICMetadataReader
, (void**)&metadata_reader
);
563 if (FAILED(hr
)) return hr
;
565 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
568 IWICMetadataReader_Release(metadata_reader
);
572 stream
= create_stream(data
, data_size
);
573 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
574 IStream_Release(stream
);
576 IWICPersistStream_Release(persist
);
578 *reader
= metadata_reader
;
583 IWICBitmapDecoder IWICBitmapDecoder_iface
;
584 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 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
825 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
827 if (!ppIMetadataQueryReader
)
830 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
833 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
834 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
836 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
837 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
840 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
841 IWICBitmapSource
**ppIThumbnail
)
843 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
844 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
847 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
848 GifFrameDecode_QueryInterface
,
849 GifFrameDecode_AddRef
,
850 GifFrameDecode_Release
,
851 GifFrameDecode_GetSize
,
852 GifFrameDecode_GetPixelFormat
,
853 GifFrameDecode_GetResolution
,
854 GifFrameDecode_CopyPalette
,
855 GifFrameDecode_CopyPixels
,
856 GifFrameDecode_GetMetadataQueryReader
,
857 GifFrameDecode_GetColorContexts
,
858 GifFrameDecode_GetThumbnail
861 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
862 REFIID iid
, void **ppv
)
864 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
865 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
868 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
870 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
871 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
874 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
876 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
877 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
880 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
883 TRACE("(%p,%p)\n", iface
, guid
);
885 if (!guid
) return E_INVALIDARG
;
887 *guid
= GUID_ContainerFormatGif
;
891 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
894 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
896 TRACE("%p,%p\n", iface
, count
);
898 if (!count
) return E_INVALIDARG
;
900 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
904 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
907 IWICMetadataReader
*metadata_reader
;
908 IWICPersistStream
*persist
;
910 struct image_descriptor IMD_data
;
912 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
914 hr
= IMDReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
915 if (FAILED(hr
)) return hr
;
917 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
920 IWICMetadataReader_Release(metadata_reader
);
924 /* recreate IMD structure from GIF decoder data */
925 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
926 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
927 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
928 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
931 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
932 if (This
->frame
->ImageDesc
.ColorMap
)
934 /* local_color_table_flag */
935 IMD_data
.packed
|= 1 << 7;
936 /* local_color_table_size */
937 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
939 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
942 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
943 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
944 IStream_Release(stream
);
946 IWICPersistStream_Release(persist
);
948 *reader
= metadata_reader
;
952 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
953 UINT index
, IWICMetadataReader
**reader
)
955 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
956 int i
, gce_index
= -1, gce_skipped
= 0;
958 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
960 if (!reader
) return E_INVALIDARG
;
963 return create_IMD_metadata_reader(This
, reader
);
965 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
968 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; i
++)
970 class_constructor constructor
;
974 if (index
!= i
+ 1 - gce_skipped
) continue;
976 if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== GRAPHICS_EXT_FUNC_CODE
)
982 else if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
984 constructor
= GifCommentReader_CreateInstance
;
985 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
986 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
990 constructor
= UnknownMetadataReader_CreateInstance
;
991 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
992 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
994 return create_metadata_reader(data
, data_size
, constructor
, reader
);
997 if (gce_index
== -1) return E_INVALIDARG
;
999 return create_metadata_reader(This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].Bytes
+ 3,
1000 This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].ByteCount
- 4,
1001 GCEReader_CreateInstance
, reader
);
1004 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1005 IEnumUnknown
**enumerator
)
1007 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1011 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
1013 GifFrameDecode_Block_QueryInterface
,
1014 GifFrameDecode_Block_AddRef
,
1015 GifFrameDecode_Block_Release
,
1016 GifFrameDecode_Block_GetContainerFormat
,
1017 GifFrameDecode_Block_GetCount
,
1018 GifFrameDecode_Block_GetReaderByIndex
,
1019 GifFrameDecode_Block_GetEnumerator
1022 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1025 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1026 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1028 if (!ppv
) return E_INVALIDARG
;
1030 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1031 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1033 *ppv
= &This
->IWICBitmapDecoder_iface
;
1035 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1037 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1042 return E_NOINTERFACE
;
1045 IUnknown_AddRef((IUnknown
*)*ppv
);
1049 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1051 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1052 ULONG ref
= InterlockedIncrement(&This
->ref
);
1054 TRACE("(%p) refcount=%u\n", iface
, ref
);
1059 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1061 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1062 ULONG ref
= InterlockedDecrement(&This
->ref
);
1064 TRACE("(%p) refcount=%u\n", iface
, ref
);
1070 IStream_Release(This
->stream
);
1071 DGifCloseFile(This
->gif
);
1073 This
->lock
.DebugInfo
->Spare
[0] = 0;
1074 DeleteCriticalSection(&This
->lock
);
1075 HeapFree(GetProcessHeap(), 0, This
);
1081 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1086 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1088 if (!stream
|| !capability
) return E_INVALIDARG
;
1090 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1091 if (hr
!= S_OK
) return hr
;
1093 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1094 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1095 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1099 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1100 IStream
*stream
= gif
->UserData
;
1106 ERR("attempting to read file after initialization\n");
1110 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1111 if (FAILED(hr
)) bytesread
= 0;
1115 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1116 WICDecodeOptions cacheOptions
)
1118 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1122 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1124 EnterCriticalSection(&This
->lock
);
1126 if (This
->initialized
|| This
->gif
)
1128 WARN("already initialized\n");
1129 LeaveCriticalSection(&This
->lock
);
1130 return WINCODEC_ERR_WRONGSTATE
;
1133 /* seek to start of stream */
1135 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1137 /* read all data from the stream */
1138 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1141 LeaveCriticalSection(&This
->lock
);
1145 ret
= DGifSlurp(This
->gif
);
1146 if (ret
== GIF_ERROR
)
1148 LeaveCriticalSection(&This
->lock
);
1152 /* make sure we don't use the stream after this method returns */
1153 This
->gif
->UserData
= NULL
;
1156 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1157 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1159 This
->stream
= pIStream
;
1160 IStream_AddRef(This
->stream
);
1162 This
->initialized
= TRUE
;
1164 LeaveCriticalSection(&This
->lock
);
1169 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1170 GUID
*pguidContainerFormat
)
1172 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1176 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1177 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1179 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1181 return get_decoder_info(&CLSID_WICGifDecoder
, ppIDecoderInfo
);
1184 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1186 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1187 WICColor colors
[256];
1189 int i
, trans
, count
;
1192 TRACE("(%p,%p)\n", iface
, palette
);
1195 return WINCODEC_ERR_WRONGSTATE
;
1197 cm
= This
->gif
->SColorMap
;
1200 if (cm
->ColorCount
> 256)
1202 ERR("GIF contains invalid number of colors: %d\n", cm
->ColorCount
);
1206 for (i
= 0; i
< cm
->ColorCount
; i
++)
1208 colors
[i
] = 0xff000000 | /* alpha */
1209 cm
->Colors
[i
].Red
<< 16 |
1210 cm
->Colors
[i
].Green
<< 8 |
1214 count
= cm
->ColorCount
;
1218 colors
[0] = 0xff000000;
1219 colors
[1] = 0xffffffff;
1221 for (i
= 2; i
< 256; i
++)
1222 colors
[i
] = 0xff000000;
1227 /* look for the transparent color extension */
1228 for (i
= 0; i
< This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlockCount
; i
++)
1230 eb
= This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlocks
+ i
;
1231 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8)
1233 if (eb
->Bytes
[3] & 1)
1235 trans
= (unsigned char)eb
->Bytes
[6];
1236 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
1242 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1245 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1246 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1248 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1250 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1252 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
1254 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1257 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1258 IWICBitmapSource
**ppIBitmapSource
)
1260 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1261 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1264 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1265 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1267 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1268 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1271 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1272 IWICBitmapSource
**ppIThumbnail
)
1274 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1275 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1278 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1281 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1283 if (!pCount
) return E_INVALIDARG
;
1285 EnterCriticalSection(&This
->lock
);
1286 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1287 LeaveCriticalSection(&This
->lock
);
1289 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1294 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1295 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1297 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1298 GifFrameDecode
*result
;
1299 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1301 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1303 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1305 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1306 if (!result
) return E_OUTOFMEMORY
;
1308 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1309 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1311 result
->frame
= &This
->gif
->SavedImages
[index
];
1312 IWICBitmapDecoder_AddRef(iface
);
1313 result
->parent
= This
;
1314 This
->current_frame
= index
;
1316 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1321 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1322 GifDecoder_QueryInterface
,
1325 GifDecoder_QueryCapability
,
1326 GifDecoder_Initialize
,
1327 GifDecoder_GetContainerFormat
,
1328 GifDecoder_GetDecoderInfo
,
1329 GifDecoder_CopyPalette
,
1330 GifDecoder_GetMetadataQueryReader
,
1331 GifDecoder_GetPreview
,
1332 GifDecoder_GetColorContexts
,
1333 GifDecoder_GetThumbnail
,
1334 GifDecoder_GetFrameCount
,
1338 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1339 REFIID iid
, void **ppv
)
1341 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1342 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1345 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1347 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1348 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1351 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1353 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1354 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1357 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1360 TRACE("(%p,%p)\n", iface
, guid
);
1362 if (!guid
) return E_INVALIDARG
;
1364 *guid
= GUID_ContainerFormatGif
;
1368 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1371 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1373 TRACE("%p,%p\n", iface
, count
);
1375 if (!count
) return E_INVALIDARG
;
1377 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1381 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1382 UINT index
, IWICMetadataReader
**reader
)
1384 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1387 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1389 if (!reader
) return E_INVALIDARG
;
1392 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1393 LSDReader_CreateInstance
, reader
);
1395 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1397 class_constructor constructor
;
1399 if (index
!= i
+ 1) continue;
1401 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1402 constructor
= APEReader_CreateInstance
;
1403 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1404 constructor
= GifCommentReader_CreateInstance
;
1406 constructor
= UnknownMetadataReader_CreateInstance
;
1408 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1409 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1410 constructor
, reader
);
1413 return E_INVALIDARG
;
1416 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1417 IEnumUnknown
**enumerator
)
1419 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1423 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1425 GifDecoder_Block_QueryInterface
,
1426 GifDecoder_Block_AddRef
,
1427 GifDecoder_Block_Release
,
1428 GifDecoder_Block_GetContainerFormat
,
1429 GifDecoder_Block_GetCount
,
1430 GifDecoder_Block_GetReaderByIndex
,
1431 GifDecoder_Block_GetEnumerator
1434 HRESULT
GifDecoder_CreateInstance(REFIID iid
, void** ppv
)
1439 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1443 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1444 if (!This
) return E_OUTOFMEMORY
;
1446 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1447 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1448 This
->stream
= NULL
;
1450 This
->initialized
= FALSE
;
1452 This
->current_frame
= 0;
1453 InitializeCriticalSection(&This
->lock
);
1454 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1456 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1457 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1462 typedef struct GifEncoder
1464 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1467 CRITICAL_SECTION lock
;
1468 BOOL initialized
, info_written
, committed
;
1470 WICColor palette
[256];
1474 static inline GifEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1476 return CONTAINING_RECORD(iface
, GifEncoder
, IWICBitmapEncoder_iface
);
1479 typedef struct GifFrameEncode
1481 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1483 GifEncoder
*encoder
;
1484 BOOL initialized
, interlace
, committed
;
1485 UINT width
, height
, lines
;
1487 WICColor palette
[256];
1492 static inline GifFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1494 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICBitmapFrameEncode_iface
);
1497 static HRESULT WINAPI
GifFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
, void **ppv
)
1499 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
1501 if (!ppv
) return E_INVALIDARG
;
1503 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1504 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1506 IWICBitmapFrameEncode_AddRef(iface
);
1512 return E_NOINTERFACE
;
1515 static ULONG WINAPI
GifFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1517 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1518 ULONG ref
= InterlockedIncrement(&This
->ref
);
1520 TRACE("%p -> %u\n", iface
, ref
);
1524 static ULONG WINAPI
GifFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1526 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1527 ULONG ref
= InterlockedDecrement(&This
->ref
);
1529 TRACE("%p -> %u\n", iface
, ref
);
1533 IWICBitmapEncoder_Release(&This
->encoder
->IWICBitmapEncoder_iface
);
1534 HeapFree(GetProcessHeap(), 0, This
->image_data
);
1535 HeapFree(GetProcessHeap(), 0, This
);
1541 static HRESULT WINAPI
GifFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
, IPropertyBag2
*options
)
1543 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1546 TRACE("%p,%p\n", iface
, options
);
1548 EnterCriticalSection(&This
->encoder
->lock
);
1550 if (!This
->initialized
)
1552 This
->initialized
= TRUE
;
1556 hr
= WINCODEC_ERR_WRONGSTATE
;
1558 LeaveCriticalSection(&This
->encoder
->lock
);
1563 static HRESULT WINAPI
GifFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
, UINT width
, UINT height
)
1565 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1568 TRACE("%p,%u,%u\n", iface
, width
, height
);
1570 if (!width
|| !height
) return E_INVALIDARG
;
1572 EnterCriticalSection(&This
->encoder
->lock
);
1574 if (This
->initialized
)
1576 HeapFree(GetProcessHeap(), 0, This
->image_data
);
1578 This
->image_data
= HeapAlloc(GetProcessHeap(), 0, width
* height
);
1579 if (This
->image_data
)
1581 This
->width
= width
;
1582 This
->height
= height
;
1589 hr
= WINCODEC_ERR_WRONGSTATE
;
1591 LeaveCriticalSection(&This
->encoder
->lock
);
1596 static HRESULT WINAPI
GifFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
, double xres
, double yres
)
1598 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1601 TRACE("%p,%f,%f\n", iface
, xres
, yres
);
1603 EnterCriticalSection(&This
->encoder
->lock
);
1605 if (This
->initialized
)
1612 hr
= WINCODEC_ERR_WRONGSTATE
;
1614 LeaveCriticalSection(&This
->encoder
->lock
);
1619 static HRESULT WINAPI
GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
, WICPixelFormatGUID
*format
)
1621 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1624 TRACE("%p,%s\n", iface
, debugstr_guid(format
));
1626 if (!format
) return E_INVALIDARG
;
1628 EnterCriticalSection(&This
->encoder
->lock
);
1630 if (This
->initialized
)
1632 *format
= GUID_WICPixelFormat8bppIndexed
;
1636 hr
= WINCODEC_ERR_WRONGSTATE
;
1638 LeaveCriticalSection(&This
->encoder
->lock
);
1643 static HRESULT WINAPI
GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
, UINT count
, IWICColorContext
**context
)
1645 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
1649 static HRESULT WINAPI
GifFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
, IWICPalette
*palette
)
1651 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1654 TRACE("%p,%p\n", iface
, palette
);
1656 if (!palette
) return E_INVALIDARG
;
1658 EnterCriticalSection(&This
->encoder
->lock
);
1660 if (This
->initialized
)
1661 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1663 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1665 LeaveCriticalSection(&This
->encoder
->lock
);
1669 static HRESULT WINAPI
GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*thumbnail
)
1671 FIXME("%p,%p: stub\n", iface
, thumbnail
);
1675 static HRESULT WINAPI
GifFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
, UINT lines
, UINT stride
, UINT size
, BYTE
*pixels
)
1677 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1680 TRACE("%p,%u,%u,%u,%p\n", iface
, lines
, stride
, size
, pixels
);
1682 if (!pixels
) return E_INVALIDARG
;
1684 EnterCriticalSection(&This
->encoder
->lock
);
1686 if (This
->initialized
&& This
->image_data
)
1688 if (This
->lines
+ lines
<= This
->height
)
1694 dst
= This
->image_data
+ This
->lines
* This
->width
;
1696 for (i
= 0; i
< lines
; i
++)
1698 memcpy(dst
, src
, This
->width
);
1703 This
->lines
+= lines
;
1710 hr
= WINCODEC_ERR_WRONGSTATE
;
1712 LeaveCriticalSection(&This
->encoder
->lock
);
1716 static HRESULT WINAPI
GifFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*source
, WICRect
*rc
)
1718 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1721 TRACE("%p,%p,%p\n", iface
, source
, rc
);
1723 if (!source
) return E_INVALIDARG
;
1725 EnterCriticalSection(&This
->encoder
->lock
);
1727 if (This
->initialized
)
1729 const GUID
*format
= &GUID_WICPixelFormat8bppIndexed
;
1731 hr
= configure_write_source(iface
, source
, rc
, format
,
1732 This
->width
, This
->height
, This
->xres
, This
->yres
);
1734 hr
= write_source(iface
, source
, rc
, format
, 8, This
->width
, This
->height
);
1737 hr
= WINCODEC_ERR_WRONGSTATE
;
1739 LeaveCriticalSection(&This
->encoder
->lock
);
1743 #define LZW_DICT_SIZE (1 << 12)
1747 short prefix
[LZW_DICT_SIZE
];
1748 unsigned char suffix
[LZW_DICT_SIZE
];
1753 struct lzw_dict dict
;
1754 short init_code_bits
, code_bits
, next_code
, clear_code
, eof_code
;
1757 int (*user_write_data
)(void *user_ptr
, void *data
, int length
);
1767 struct output_stream
1777 static int lzw_output_code(struct lzw_state
*state
, short code
)
1779 state
->bits_buf
|= code
<< state
->bits_count
;
1780 state
->bits_count
+= state
->code_bits
;
1782 while (state
->bits_count
>= 8)
1784 unsigned char byte
= (unsigned char)state
->bits_buf
;
1785 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1787 state
->bits_buf
>>= 8;
1788 state
->bits_count
-= 8;
1794 static inline int lzw_output_clear_code(struct lzw_state
*state
)
1796 return lzw_output_code(state
, state
->clear_code
);
1799 static inline int lzw_output_eof_code(struct lzw_state
*state
)
1801 return lzw_output_code(state
, state
->eof_code
);
1804 static int lzw_flush_bits(struct lzw_state
*state
)
1808 while (state
->bits_count
>= 8)
1810 byte
= (unsigned char)state
->bits_buf
;
1811 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1813 state
->bits_buf
>>= 8;
1814 state
->bits_count
-= 8;
1817 if (state
->bits_count
)
1819 static const char mask
[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1821 byte
= (unsigned char)state
->bits_buf
& mask
[state
->bits_count
];
1822 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1826 state
->bits_buf
= 0;
1827 state
->bits_count
= 0;
1832 static void lzw_dict_reset(struct lzw_state
*state
)
1836 state
->code_bits
= state
->init_code_bits
+ 1;
1837 state
->next_code
= (1 << state
->init_code_bits
) + 2;
1839 for(i
= 0; i
< LZW_DICT_SIZE
; i
++)
1841 state
->dict
.prefix
[i
] = 1 << 12; /* impossible LZW code value */
1842 state
->dict
.suffix
[i
] = 0;
1846 static void lzw_state_init(struct lzw_state
*state
, short init_code_bits
, void *user_write_data
, void *user_ptr
)
1848 state
->init_code_bits
= init_code_bits
;
1849 state
->clear_code
= 1 << init_code_bits
;
1850 state
->eof_code
= state
->clear_code
+ 1;
1851 state
->bits_buf
= 0;
1852 state
->bits_count
= 0;
1853 state
->user_write_data
= user_write_data
;
1854 state
->user_ptr
= user_ptr
;
1856 lzw_dict_reset(state
);
1859 static int lzw_dict_add(struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1861 if (state
->next_code
< LZW_DICT_SIZE
)
1863 state
->dict
.prefix
[state
->next_code
] = prefix
;
1864 state
->dict
.suffix
[state
->next_code
] = suffix
;
1866 if ((state
->next_code
& (state
->next_code
- 1)) == 0)
1870 return state
->next_code
;
1876 static short lzw_dict_lookup(const struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1880 for (i
= 0; i
< state
->next_code
; i
++)
1882 if (state
->dict
.prefix
[i
] == prefix
&& state
->dict
.suffix
[i
] == suffix
)
1889 static inline int write_byte(struct output_stream
*out
, char byte
)
1891 if (out
->gif_block
.len
== 255)
1893 if (IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
), NULL
) != S_OK
)
1896 out
->gif_block
.len
= 0;
1899 out
->gif_block
.data
[out
->gif_block
.len
++] = byte
;
1904 static int write_data(void *user_ptr
, void *user_data
, int length
)
1906 unsigned char *data
= user_data
;
1907 struct output_stream
*out
= user_ptr
;
1912 if (!write_byte(out
, *data
++)) return 0;
1918 static int flush_output_data(void *user_ptr
)
1920 struct output_stream
*out
= user_ptr
;
1922 if (out
->gif_block
.len
)
1924 if (IStream_Write(out
->out
, &out
->gif_block
, out
->gif_block
.len
+ sizeof(out
->gif_block
.len
), NULL
) != S_OK
)
1928 /* write GIF block terminator */
1929 out
->gif_block
.len
= 0;
1930 return IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
.len
), NULL
) == S_OK
;
1933 static inline int read_byte(struct input_stream
*in
, unsigned char *byte
)
1945 static HRESULT
gif_compress(IStream
*out_stream
, const BYTE
*in_data
, ULONG in_size
)
1947 struct input_stream in
;
1948 struct output_stream out
;
1949 struct lzw_state state
;
1950 short init_code_bits
, prefix
, code
;
1951 unsigned char suffix
;
1956 out
.gif_block
.len
= 0;
1957 out
.out
= out_stream
;
1959 init_code_bits
= suffix
= 8;
1960 if (IStream_Write(out
.out
, &suffix
, sizeof(suffix
), NULL
) != S_OK
)
1963 lzw_state_init(&state
, init_code_bits
, write_data
, &out
);
1965 if (!lzw_output_clear_code(&state
))
1968 if (read_byte(&in
, &suffix
))
1972 while (read_byte(&in
, &suffix
))
1974 code
= lzw_dict_lookup(&state
, prefix
, suffix
);
1977 if (!lzw_output_code(&state
, prefix
))
1980 if (lzw_dict_add(&state
, prefix
, suffix
) == -1)
1982 if (!lzw_output_clear_code(&state
))
1984 lzw_dict_reset(&state
);
1993 if (!lzw_output_code(&state
, prefix
))
1995 if (!lzw_output_eof_code(&state
))
1997 if (!lzw_flush_bits(&state
))
2001 return flush_output_data(&out
) ? S_OK
: E_FAIL
;
2004 static HRESULT WINAPI
GifFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
2006 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
2009 TRACE("%p\n", iface
);
2011 EnterCriticalSection(&This
->encoder
->lock
);
2013 if (This
->image_data
&& This
->lines
== This
->height
&& !This
->committed
)
2015 BYTE gif_palette
[256][3];
2019 if (!This
->encoder
->info_written
)
2021 struct logical_screen_descriptor lsd
;
2023 /* Logical Screen Descriptor */
2024 memcpy(lsd
.signature
, "GIF89a", 6);
2025 lsd
.width
= This
->width
;
2026 lsd
.height
= This
->height
;
2028 if (This
->encoder
->colors
)
2029 lsd
.packed
|= 0x80; /* global color table flag */
2030 lsd
.packed
|= 0x07 << 4; /* color resolution */
2031 lsd
.packed
|= 0x07; /* global color table size */
2032 lsd
.background_color_index
= 0; /* FIXME */
2033 lsd
.pixel_aspect_ratio
= 0;
2034 hr
= IStream_Write(This
->encoder
->stream
, &lsd
, sizeof(lsd
), NULL
);
2035 if (hr
== S_OK
&& This
->encoder
->colors
)
2039 /* Global Color Table */
2040 memset(gif_palette
, 0, sizeof(gif_palette
));
2041 for (i
= 0; i
< This
->encoder
->colors
; i
++)
2043 gif_palette
[i
][0] = (This
->encoder
->palette
[i
] >> 16) & 0xff;
2044 gif_palette
[i
][1] = (This
->encoder
->palette
[i
] >> 8) & 0xff;
2045 gif_palette
[i
][2] = This
->encoder
->palette
[i
] & 0xff;
2047 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2050 /* FIXME: write GCE, APE, etc. GIF extensions */
2053 This
->encoder
->info_written
= TRUE
;
2058 char image_separator
= 0x2c;
2060 hr
= IStream_Write(This
->encoder
->stream
, &image_separator
, sizeof(image_separator
), NULL
);
2063 struct image_descriptor imd
;
2065 /* Image Descriptor */
2068 imd
.width
= This
->width
;
2069 imd
.height
= This
->height
;
2073 imd
.packed
|= 0x80; /* local color table flag */
2074 imd
.packed
|= 0x07; /* local color table size */
2076 /* FIXME: interlace flag */
2077 hr
= IStream_Write(This
->encoder
->stream
, &imd
, sizeof(imd
), NULL
);
2078 if (hr
== S_OK
&& This
->colors
)
2082 /* Local Color Table */
2083 memset(gif_palette
, 0, sizeof(gif_palette
));
2084 for (i
= 0; i
< This
->colors
; i
++)
2086 gif_palette
[i
][0] = (This
->palette
[i
] >> 16) & 0xff;
2087 gif_palette
[i
][1] = (This
->palette
[i
] >> 8) & 0xff;
2088 gif_palette
[i
][2] = This
->palette
[i
] & 0xff;
2090 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2094 hr
= gif_compress(This
->encoder
->stream
, This
->image_data
, This
->width
* This
->height
);
2096 This
->committed
= TRUE
;
2103 hr
= WINCODEC_ERR_WRONGSTATE
;
2105 LeaveCriticalSection(&This
->encoder
->lock
);
2109 static HRESULT WINAPI
GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
, IWICMetadataQueryWriter
**writer
)
2111 FIXME("%p, %p: stub\n", iface
, writer
);
2115 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl
=
2117 GifFrameEncode_QueryInterface
,
2118 GifFrameEncode_AddRef
,
2119 GifFrameEncode_Release
,
2120 GifFrameEncode_Initialize
,
2121 GifFrameEncode_SetSize
,
2122 GifFrameEncode_SetResolution
,
2123 GifFrameEncode_SetPixelFormat
,
2124 GifFrameEncode_SetColorContexts
,
2125 GifFrameEncode_SetPalette
,
2126 GifFrameEncode_SetThumbnail
,
2127 GifFrameEncode_WritePixels
,
2128 GifFrameEncode_WriteSource
,
2129 GifFrameEncode_Commit
,
2130 GifFrameEncode_GetMetadataQueryWriter
2133 static HRESULT WINAPI
GifEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
, void **ppv
)
2135 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
2137 if (!ppv
) return E_INVALIDARG
;
2139 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2140 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
2142 IWICBitmapEncoder_AddRef(iface
);
2148 return E_NOINTERFACE
;
2151 static ULONG WINAPI
GifEncoder_AddRef(IWICBitmapEncoder
*iface
)
2153 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2154 ULONG ref
= InterlockedIncrement(&This
->ref
);
2156 TRACE("%p -> %u\n", iface
, ref
);
2160 static ULONG WINAPI
GifEncoder_Release(IWICBitmapEncoder
*iface
)
2162 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2163 ULONG ref
= InterlockedDecrement(&This
->ref
);
2165 TRACE("%p -> %u\n", iface
, ref
);
2169 if (This
->stream
) IStream_Release(This
->stream
);
2170 This
->lock
.DebugInfo
->Spare
[0] = 0;
2171 DeleteCriticalSection(&This
->lock
);
2172 HeapFree(GetProcessHeap(), 0, This
);
2178 static HRESULT WINAPI
GifEncoder_Initialize(IWICBitmapEncoder
*iface
, IStream
*stream
, WICBitmapEncoderCacheOption option
)
2180 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2183 TRACE("%p,%p,%#x\n", iface
, stream
, option
);
2185 if (!stream
) return E_INVALIDARG
;
2187 EnterCriticalSection(&This
->lock
);
2189 if (!This
->initialized
)
2191 IStream_AddRef(stream
);
2192 This
->stream
= stream
;
2193 This
->initialized
= TRUE
;
2197 hr
= WINCODEC_ERR_WRONGSTATE
;
2199 LeaveCriticalSection(&This
->lock
);
2204 static HRESULT WINAPI
GifEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
, GUID
*format
)
2206 if (!format
) return E_INVALIDARG
;
2208 *format
= GUID_ContainerFormatGif
;
2212 static HRESULT WINAPI
GifEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
2214 IWICComponentInfo
*comp_info
;
2217 TRACE("%p,%p\n", iface
, info
);
2219 if (!info
) return E_INVALIDARG
;
2221 hr
= CreateComponentInfo(&CLSID_WICGifEncoder
, &comp_info
);
2224 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
2225 IWICComponentInfo_Release(comp_info
);
2230 static HRESULT WINAPI
GifEncoder_SetColorContexts(IWICBitmapEncoder
*iface
, UINT count
, IWICColorContext
**context
)
2232 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
2236 static HRESULT WINAPI
GifEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
2238 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2241 TRACE("%p,%p\n", iface
, palette
);
2243 if (!palette
) return E_INVALIDARG
;
2245 EnterCriticalSection(&This
->lock
);
2247 if (This
->initialized
)
2248 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
2250 hr
= WINCODEC_ERR_NOTINITIALIZED
;
2252 LeaveCriticalSection(&This
->lock
);
2256 static HRESULT WINAPI
GifEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*thumbnail
)
2258 TRACE("%p,%p\n", iface
, thumbnail
);
2259 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2262 static HRESULT WINAPI
GifEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*preview
)
2264 TRACE("%p,%p\n", iface
, preview
);
2265 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2268 static HRESULT WINAPI
GifEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
, IWICBitmapFrameEncode
**frame
, IPropertyBag2
**options
)
2270 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2273 TRACE("%p,%p,%p\n", iface
, frame
, options
);
2275 if (!frame
) return E_INVALIDARG
;
2277 EnterCriticalSection(&This
->lock
);
2279 if (This
->initialized
&& !This
->committed
)
2281 GifFrameEncode
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
2286 ret
->IWICBitmapFrameEncode_iface
.lpVtbl
= &GifFrameEncode_Vtbl
;
2288 ret
->encoder
= This
;
2289 ret
->initialized
= FALSE
;
2290 ret
->interlace
= FALSE
; /* FIXME: read from the properties */
2291 ret
->committed
= FALSE
;
2298 ret
->image_data
= NULL
;
2299 IWICBitmapEncoder_AddRef(iface
);
2300 *frame
= &ret
->IWICBitmapFrameEncode_iface
;
2306 hr
= CreatePropertyBag2(NULL
, 0, options
);
2309 IWICBitmapFrameEncode_Release(*frame
);
2318 hr
= WINCODEC_ERR_WRONGSTATE
;
2320 LeaveCriticalSection(&This
->lock
);
2326 static HRESULT WINAPI
GifEncoder_Commit(IWICBitmapEncoder
*iface
)
2328 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2331 TRACE("%p\n", iface
);
2333 EnterCriticalSection(&This
->lock
);
2335 if (This
->initialized
&& !This
->committed
)
2337 char gif_trailer
= 0x3b;
2339 /* FIXME: write text, comment GIF extensions */
2341 hr
= IStream_Write(This
->stream
, &gif_trailer
, sizeof(gif_trailer
), NULL
);
2343 This
->committed
= TRUE
;
2346 hr
= WINCODEC_ERR_WRONGSTATE
;
2348 LeaveCriticalSection(&This
->lock
);
2352 static HRESULT WINAPI
GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
, IWICMetadataQueryWriter
**writer
)
2354 FIXME("%p,%p: stub\n", iface
, writer
);
2358 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl
=
2360 GifEncoder_QueryInterface
,
2363 GifEncoder_Initialize
,
2364 GifEncoder_GetContainerFormat
,
2365 GifEncoder_GetEncoderInfo
,
2366 GifEncoder_SetColorContexts
,
2367 GifEncoder_SetPalette
,
2368 GifEncoder_SetThumbnail
,
2369 GifEncoder_SetPreview
,
2370 GifEncoder_CreateNewFrame
,
2372 GifEncoder_GetMetadataQueryWriter
2375 HRESULT
GifEncoder_CreateInstance(REFIID iid
, void **ppv
)
2380 TRACE("%s,%p\n", debugstr_guid(iid
), ppv
);
2384 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
2385 if (!This
) return E_OUTOFMEMORY
;
2387 This
->IWICBitmapEncoder_iface
.lpVtbl
= &GifEncoder_Vtbl
;
2389 This
->stream
= NULL
;
2390 InitializeCriticalSection(&This
->lock
);
2391 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifEncoder.lock");
2392 This
->initialized
= FALSE
;
2393 This
->info_written
= FALSE
;
2394 This
->committed
= FALSE
;
2398 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2399 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);