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
20 #include "wincodecs_private.h"
28 struct logical_screen_descriptor
34 /* global_color_table_flag : 1;
35 * color_resolution : 3;
37 * global_color_table_size : 3;
39 BYTE background_color_index
;
40 BYTE pixel_aspect_ratio
;
43 struct image_descriptor
50 /* local_color_table_flag : 1;
54 * local_color_table_size : 3;
60 static LPWSTR
strdupAtoW(const char *src
)
62 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
63 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
64 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
68 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
69 MetadataItem
**items
, DWORD
*count
)
71 struct logical_screen_descriptor lsd_data
;
79 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
80 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
82 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 9);
83 if (!result
) return E_OUTOFMEMORY
;
85 for (i
= 0; i
< 9; i
++)
87 PropVariantInit(&result
[i
].schema
);
88 PropVariantInit(&result
[i
].id
);
89 PropVariantInit(&result
[i
].value
);
92 result
[0].id
.vt
= VT_LPWSTR
;
93 result
[0].id
.u
.pwszVal
= strdupAtoW("Signature");
94 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
95 result
[0].value
.u
.caub
.cElems
= sizeof(lsd_data
.signature
);
96 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
97 memcpy(result
[0].value
.u
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
99 result
[1].id
.vt
= VT_LPWSTR
;
100 result
[1].id
.u
.pwszVal
= strdupAtoW("Width");
101 result
[1].value
.vt
= VT_UI2
;
102 result
[1].value
.u
.uiVal
= lsd_data
.width
;
104 result
[2].id
.vt
= VT_LPWSTR
;
105 result
[2].id
.u
.pwszVal
= strdupAtoW("Height");
106 result
[2].value
.vt
= VT_UI2
;
107 result
[2].value
.u
.uiVal
= lsd_data
.height
;
109 result
[3].id
.vt
= VT_LPWSTR
;
110 result
[3].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
111 result
[3].value
.vt
= VT_BOOL
;
112 result
[3].value
.u
.boolVal
= (lsd_data
.packed
>> 7) & 1;
114 result
[4].id
.vt
= VT_LPWSTR
;
115 result
[4].id
.u
.pwszVal
= strdupAtoW("ColorResolution");
116 result
[4].value
.vt
= VT_UI1
;
117 result
[4].value
.u
.bVal
= (lsd_data
.packed
>> 4) & 7;
119 result
[5].id
.vt
= VT_LPWSTR
;
120 result
[5].id
.u
.pwszVal
= strdupAtoW("SortFlag");
121 result
[5].value
.vt
= VT_BOOL
;
122 result
[5].value
.u
.boolVal
= (lsd_data
.packed
>> 3) & 1;
124 result
[6].id
.vt
= VT_LPWSTR
;
125 result
[6].id
.u
.pwszVal
= strdupAtoW("GlobalColorTableSize");
126 result
[6].value
.vt
= VT_UI1
;
127 result
[6].value
.u
.bVal
= lsd_data
.packed
& 7;
129 result
[7].id
.vt
= VT_LPWSTR
;
130 result
[7].id
.u
.pwszVal
= strdupAtoW("BackgroundColorIndex");
131 result
[7].value
.vt
= VT_UI1
;
132 result
[7].value
.u
.bVal
= lsd_data
.background_color_index
;
134 result
[8].id
.vt
= VT_LPWSTR
;
135 result
[8].id
.u
.pwszVal
= strdupAtoW("PixelAspectRatio");
136 result
[8].value
.vt
= VT_UI1
;
137 result
[8].value
.u
.bVal
= lsd_data
.pixel_aspect_ratio
;
145 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
147 &CLSID_WICLSDMetadataReader
,
151 HRESULT
LSDReader_CreateInstance(REFIID iid
, void **ppv
)
153 return MetadataReader_Create(&LSDReader_Vtbl
, iid
, ppv
);
156 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
157 MetadataItem
**items
, DWORD
*count
)
159 struct image_descriptor imd_data
;
162 MetadataItem
*result
;
167 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
168 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
170 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 8);
171 if (!result
) return E_OUTOFMEMORY
;
173 for (i
= 0; i
< 8; i
++)
175 PropVariantInit(&result
[i
].schema
);
176 PropVariantInit(&result
[i
].id
);
177 PropVariantInit(&result
[i
].value
);
180 result
[0].id
.vt
= VT_LPWSTR
;
181 result
[0].id
.u
.pwszVal
= strdupAtoW("Left");
182 result
[0].value
.vt
= VT_UI2
;
183 result
[0].value
.u
.uiVal
= imd_data
.left
;
185 result
[1].id
.vt
= VT_LPWSTR
;
186 result
[1].id
.u
.pwszVal
= strdupAtoW("Top");
187 result
[1].value
.vt
= VT_UI2
;
188 result
[1].value
.u
.uiVal
= imd_data
.top
;
190 result
[2].id
.vt
= VT_LPWSTR
;
191 result
[2].id
.u
.pwszVal
= strdupAtoW("Width");
192 result
[2].value
.vt
= VT_UI2
;
193 result
[2].value
.u
.uiVal
= imd_data
.width
;
195 result
[3].id
.vt
= VT_LPWSTR
;
196 result
[3].id
.u
.pwszVal
= strdupAtoW("Height");
197 result
[3].value
.vt
= VT_UI2
;
198 result
[3].value
.u
.uiVal
= imd_data
.height
;
200 result
[4].id
.vt
= VT_LPWSTR
;
201 result
[4].id
.u
.pwszVal
= strdupAtoW("LocalColorTableFlag");
202 result
[4].value
.vt
= VT_BOOL
;
203 result
[4].value
.u
.boolVal
= (imd_data
.packed
>> 7) & 1;
205 result
[5].id
.vt
= VT_LPWSTR
;
206 result
[5].id
.u
.pwszVal
= strdupAtoW("InterlaceFlag");
207 result
[5].value
.vt
= VT_BOOL
;
208 result
[5].value
.u
.boolVal
= (imd_data
.packed
>> 6) & 1;
210 result
[6].id
.vt
= VT_LPWSTR
;
211 result
[6].id
.u
.pwszVal
= strdupAtoW("SortFlag");
212 result
[6].value
.vt
= VT_BOOL
;
213 result
[6].value
.u
.boolVal
= (imd_data
.packed
>> 5) & 1;
215 result
[7].id
.vt
= VT_LPWSTR
;
216 result
[7].id
.u
.pwszVal
= strdupAtoW("LocalColorTableSize");
217 result
[7].value
.vt
= VT_UI1
;
218 result
[7].value
.u
.bVal
= imd_data
.packed
& 7;
226 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
228 &CLSID_WICIMDMetadataReader
,
232 HRESULT
IMDReader_CreateInstance(REFIID iid
, void **ppv
)
234 return MetadataReader_Create(&IMDReader_Vtbl
, iid
, ppv
);
237 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
238 MetadataItem
**items
, DWORD
*count
)
240 #include "pshpack1.h"
241 struct graphic_control_extension
246 * user_input_flag : 1;
247 * transparency_flag : 1;
250 BYTE transparent_color_index
;
255 MetadataItem
*result
;
260 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
261 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
263 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 5);
264 if (!result
) return E_OUTOFMEMORY
;
266 for (i
= 0; i
< 5; i
++)
268 PropVariantInit(&result
[i
].schema
);
269 PropVariantInit(&result
[i
].id
);
270 PropVariantInit(&result
[i
].value
);
273 result
[0].id
.vt
= VT_LPWSTR
;
274 result
[0].id
.u
.pwszVal
= strdupAtoW("Disposal");
275 result
[0].value
.vt
= VT_UI1
;
276 result
[0].value
.u
.bVal
= (gce_data
.packed
>> 2) & 7;
278 result
[1].id
.vt
= VT_LPWSTR
;
279 result
[1].id
.u
.pwszVal
= strdupAtoW("UserInputFlag");
280 result
[1].value
.vt
= VT_BOOL
;
281 result
[1].value
.u
.boolVal
= (gce_data
.packed
>> 1) & 1;
283 result
[2].id
.vt
= VT_LPWSTR
;
284 result
[2].id
.u
.pwszVal
= strdupAtoW("TransparencyFlag");
285 result
[2].value
.vt
= VT_BOOL
;
286 result
[2].value
.u
.boolVal
= gce_data
.packed
& 1;
288 result
[3].id
.vt
= VT_LPWSTR
;
289 result
[3].id
.u
.pwszVal
= strdupAtoW("Delay");
290 result
[3].value
.vt
= VT_UI2
;
291 result
[3].value
.u
.uiVal
= gce_data
.delay
;
293 result
[4].id
.vt
= VT_LPWSTR
;
294 result
[4].id
.u
.pwszVal
= strdupAtoW("TransparentColorIndex");
295 result
[4].value
.vt
= VT_UI1
;
296 result
[4].value
.u
.bVal
= gce_data
.transparent_color_index
;
304 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
306 &CLSID_WICGCEMetadataReader
,
310 HRESULT
GCEReader_CreateInstance(REFIID iid
, void **ppv
)
312 return MetadataReader_Create(&GCEReader_Vtbl
, iid
, ppv
);
315 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
316 MetadataItem
**items
, DWORD
*count
)
318 #include "pshpack1.h"
319 struct application_extension
321 BYTE extension_introducer
;
322 BYTE extension_label
;
324 BYTE application
[11];
328 ULONG bytesread
, data_size
, i
;
329 MetadataItem
*result
;
336 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
337 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
338 if (ape_data
.extension_introducer
!= 0x21 ||
339 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
340 ape_data
.block_size
!= 11)
348 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
349 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
351 HeapFree(GetProcessHeap(), 0, data
);
354 if (!subblock_size
) break;
357 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
360 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
363 HeapFree(GetProcessHeap(), 0, data
);
368 data
[data_size
] = subblock_size
;
369 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
370 if (FAILED(hr
) || bytesread
!= subblock_size
)
372 HeapFree(GetProcessHeap(), 0, data
);
375 data_size
+= subblock_size
+ 1;
378 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 2);
381 HeapFree(GetProcessHeap(), 0, data
);
382 return E_OUTOFMEMORY
;
385 for (i
= 0; i
< 2; i
++)
387 PropVariantInit(&result
[i
].schema
);
388 PropVariantInit(&result
[i
].id
);
389 PropVariantInit(&result
[i
].value
);
392 result
[0].id
.vt
= VT_LPWSTR
;
393 result
[0].id
.u
.pwszVal
= strdupAtoW("Application");
394 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
395 result
[0].value
.u
.caub
.cElems
= sizeof(ape_data
.application
);
396 result
[0].value
.u
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
397 memcpy(result
[0].value
.u
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
399 result
[1].id
.vt
= VT_LPWSTR
;
400 result
[1].id
.u
.pwszVal
= strdupAtoW("Data");
401 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
402 result
[1].value
.u
.caub
.cElems
= data_size
;
403 result
[1].value
.u
.caub
.pElems
= data
;
411 static const MetadataHandlerVtbl APEReader_Vtbl
= {
413 &CLSID_WICAPEMetadataReader
,
417 HRESULT
APEReader_CreateInstance(REFIID iid
, void **ppv
)
419 return MetadataReader_Create(&APEReader_Vtbl
, iid
, ppv
);
422 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
423 MetadataItem
**items
, DWORD
*count
)
425 #include "pshpack1.h"
428 BYTE extension_introducer
;
429 BYTE extension_label
;
433 ULONG bytesread
, data_size
;
434 MetadataItem
*result
;
441 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
442 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
443 if (ext_data
.extension_introducer
!= 0x21 ||
444 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
452 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
453 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
455 HeapFree(GetProcessHeap(), 0, data
);
458 if (!subblock_size
) break;
461 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
464 char *new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
467 HeapFree(GetProcessHeap(), 0, data
);
472 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
473 if (FAILED(hr
) || bytesread
!= subblock_size
)
475 HeapFree(GetProcessHeap(), 0, data
);
478 data_size
+= subblock_size
;
483 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
));
486 HeapFree(GetProcessHeap(), 0, data
);
487 return E_OUTOFMEMORY
;
490 PropVariantInit(&result
->schema
);
491 PropVariantInit(&result
->id
);
492 PropVariantInit(&result
->value
);
494 result
->id
.vt
= VT_LPWSTR
;
495 result
->id
.u
.pwszVal
= strdupAtoW("TextEntry");
496 result
->value
.vt
= VT_LPSTR
;
497 result
->value
.u
.pszVal
= data
;
505 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
507 &CLSID_WICGifCommentMetadataReader
,
508 load_GifComment_metadata
511 HRESULT
GifCommentReader_CreateInstance(REFIID iid
, void **ppv
)
513 return MetadataReader_Create(&GifCommentReader_Vtbl
, iid
, ppv
);
516 static IStream
*create_stream(const void *data
, int data_size
)
523 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
524 if (!hdata
) return NULL
;
526 locked_data
= GlobalLock(hdata
);
527 memcpy(locked_data
, data
, data_size
);
530 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
531 return FAILED(hr
) ? NULL
: stream
;
534 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
535 class_constructor constructor
,
536 IWICMetadataReader
**reader
)
539 IWICMetadataReader
*metadata_reader
;
540 IWICPersistStream
*persist
;
543 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
545 hr
= constructor(&IID_IWICMetadataReader
, (void**)&metadata_reader
);
546 if (FAILED(hr
)) return hr
;
548 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
551 IWICMetadataReader_Release(metadata_reader
);
555 stream
= create_stream(data
, data_size
);
556 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
557 IStream_Release(stream
);
559 IWICPersistStream_Release(persist
);
561 *reader
= metadata_reader
;
566 IWICBitmapDecoder IWICBitmapDecoder_iface
;
567 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
569 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
574 CRITICAL_SECTION lock
;
578 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
579 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
585 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
587 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
590 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
592 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
595 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
597 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
600 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
602 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
605 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
608 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
609 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
611 if (!ppv
) return E_INVALIDARG
;
613 if (IsEqualIID(&IID_IUnknown
, iid
) ||
614 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
615 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
617 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
619 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
621 *ppv
= &This
->IWICMetadataBlockReader_iface
;
626 return E_NOINTERFACE
;
629 IUnknown_AddRef((IUnknown
*)*ppv
);
633 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
635 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
636 ULONG ref
= InterlockedIncrement(&This
->ref
);
638 TRACE("(%p) refcount=%u\n", iface
, ref
);
643 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
645 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
646 ULONG ref
= InterlockedDecrement(&This
->ref
);
648 TRACE("(%p) refcount=%u\n", iface
, ref
);
652 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
653 HeapFree(GetProcessHeap(), 0, This
);
659 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
660 UINT
*puiWidth
, UINT
*puiHeight
)
662 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
663 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
665 *puiWidth
= This
->frame
->ImageDesc
.Width
;
666 *puiHeight
= This
->frame
->ImageDesc
.Height
;
671 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
672 WICPixelFormatGUID
*pPixelFormat
)
674 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
679 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
680 double *pDpiX
, double *pDpiY
)
682 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
683 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
684 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
685 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
687 *pDpiX
= 96.0 / aspect
;
693 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
694 IWICPalette
*pIPalette
)
696 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
697 WICColor colors
[256];
698 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
701 TRACE("(%p,%p)\n", iface
, pIPalette
);
703 if (!cm
) cm
= This
->parent
->gif
->SColorMap
;
705 if (cm
->ColorCount
> 256)
707 ERR("GIF contains %i colors???\n", cm
->ColorCount
);
711 for (i
= 0; i
< cm
->ColorCount
; i
++) {
712 colors
[i
] = 0xff000000| /* alpha */
713 cm
->Colors
[i
].Red
<< 16|
714 cm
->Colors
[i
].Green
<< 8|
718 /* look for the transparent color extension */
719 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; ++i
) {
720 eb
= This
->frame
->Extensions
.ExtensionBlocks
+ i
;
721 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8) {
722 if (eb
->Bytes
[3] & 1) {
723 trans
= (unsigned char)eb
->Bytes
[6];
724 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
730 return IWICPalette_InitializeCustom(pIPalette
, colors
, cm
->ColorCount
);
733 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
734 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
735 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
737 UINT row_offset
; /* number of bytes into the source rows where the data starts */
747 rect
.Width
= srcwidth
;
748 rect
.Height
= srcheight
;
753 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
757 if (dststride
< rc
->Width
)
760 if ((dststride
* rc
->Height
) > dstbuffersize
)
766 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
769 src
= srcbuffer
+ srcstride
* (y
/8);
771 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
773 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
775 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
777 memcpy(dst
, src
, rc
->Width
);
783 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
784 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
786 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
787 TRACE("(%p,%p,%u,%u,%p)\n", iface
, prc
, cbStride
, cbBufferSize
, pbBuffer
);
789 if (This
->frame
->ImageDesc
.Interlace
)
791 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
792 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
793 prc
, cbStride
, cbBufferSize
, pbBuffer
);
797 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
798 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
799 prc
, cbStride
, cbBufferSize
, pbBuffer
);
803 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
804 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
806 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
808 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
810 if (!ppIMetadataQueryReader
)
813 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, ppIMetadataQueryReader
);
816 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
817 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
819 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
820 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
823 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
824 IWICBitmapSource
**ppIThumbnail
)
826 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
827 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
830 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
831 GifFrameDecode_QueryInterface
,
832 GifFrameDecode_AddRef
,
833 GifFrameDecode_Release
,
834 GifFrameDecode_GetSize
,
835 GifFrameDecode_GetPixelFormat
,
836 GifFrameDecode_GetResolution
,
837 GifFrameDecode_CopyPalette
,
838 GifFrameDecode_CopyPixels
,
839 GifFrameDecode_GetMetadataQueryReader
,
840 GifFrameDecode_GetColorContexts
,
841 GifFrameDecode_GetThumbnail
844 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
845 REFIID iid
, void **ppv
)
847 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
848 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
851 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
853 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
854 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
857 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
859 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
860 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
863 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
866 TRACE("(%p,%p)\n", iface
, guid
);
868 if (!guid
) return E_INVALIDARG
;
870 *guid
= GUID_ContainerFormatGif
;
874 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
877 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
879 TRACE("%p,%p\n", iface
, count
);
881 if (!count
) return E_INVALIDARG
;
883 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
887 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
890 IWICMetadataReader
*metadata_reader
;
891 IWICPersistStream
*persist
;
893 struct image_descriptor IMD_data
;
895 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
897 hr
= IMDReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
898 if (FAILED(hr
)) return hr
;
900 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
903 IWICMetadataReader_Release(metadata_reader
);
907 /* recreate IMD structure from GIF decoder data */
908 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
909 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
910 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
911 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
914 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
915 if (This
->frame
->ImageDesc
.ColorMap
)
917 /* local_color_table_flag */
918 IMD_data
.packed
|= 1 << 7;
919 /* local_color_table_size */
920 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
922 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
925 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
926 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
927 IStream_Release(stream
);
929 IWICPersistStream_Release(persist
);
931 *reader
= metadata_reader
;
935 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
936 UINT index
, IWICMetadataReader
**reader
)
938 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
939 int i
, gce_index
= -1, gce_skipped
= 0;
941 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
943 if (!reader
) return E_INVALIDARG
;
946 return create_IMD_metadata_reader(This
, reader
);
948 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
951 for (i
= 0; i
< This
->frame
->Extensions
.ExtensionBlockCount
; i
++)
953 class_constructor constructor
;
957 if (index
!= i
+ 1 - gce_skipped
) continue;
959 if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== GRAPHICS_EXT_FUNC_CODE
)
965 else if (This
->frame
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
967 constructor
= GifCommentReader_CreateInstance
;
968 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
969 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
973 constructor
= UnknownMetadataReader_CreateInstance
;
974 data
= This
->frame
->Extensions
.ExtensionBlocks
[i
].Bytes
;
975 data_size
= This
->frame
->Extensions
.ExtensionBlocks
[i
].ByteCount
;
977 return create_metadata_reader(data
, data_size
, constructor
, reader
);
980 if (gce_index
== -1) return E_INVALIDARG
;
982 return create_metadata_reader(This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].Bytes
+ 3,
983 This
->frame
->Extensions
.ExtensionBlocks
[gce_index
].ByteCount
- 4,
984 GCEReader_CreateInstance
, reader
);
987 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
988 IEnumUnknown
**enumerator
)
990 FIXME("(%p,%p): stub\n", iface
, enumerator
);
994 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
996 GifFrameDecode_Block_QueryInterface
,
997 GifFrameDecode_Block_AddRef
,
998 GifFrameDecode_Block_Release
,
999 GifFrameDecode_Block_GetContainerFormat
,
1000 GifFrameDecode_Block_GetCount
,
1001 GifFrameDecode_Block_GetReaderByIndex
,
1002 GifFrameDecode_Block_GetEnumerator
1005 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1008 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1009 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1011 if (!ppv
) return E_INVALIDARG
;
1013 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1014 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1016 *ppv
= &This
->IWICBitmapDecoder_iface
;
1018 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1020 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1025 return E_NOINTERFACE
;
1028 IUnknown_AddRef((IUnknown
*)*ppv
);
1032 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1034 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1035 ULONG ref
= InterlockedIncrement(&This
->ref
);
1037 TRACE("(%p) refcount=%u\n", iface
, ref
);
1042 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1044 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1045 ULONG ref
= InterlockedDecrement(&This
->ref
);
1047 TRACE("(%p) refcount=%u\n", iface
, ref
);
1053 IStream_Release(This
->stream
);
1054 DGifCloseFile(This
->gif
);
1056 This
->lock
.DebugInfo
->Spare
[0] = 0;
1057 DeleteCriticalSection(&This
->lock
);
1058 HeapFree(GetProcessHeap(), 0, This
);
1064 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1069 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1071 if (!stream
|| !capability
) return E_INVALIDARG
;
1073 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1074 if (hr
!= S_OK
) return hr
;
1076 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1077 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1078 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1082 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1083 IStream
*stream
= gif
->UserData
;
1089 ERR("attempting to read file after initialization\n");
1093 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1094 if (FAILED(hr
)) bytesread
= 0;
1098 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1099 WICDecodeOptions cacheOptions
)
1101 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1105 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1107 EnterCriticalSection(&This
->lock
);
1109 if (This
->initialized
|| This
->gif
)
1111 WARN("already initialized\n");
1112 LeaveCriticalSection(&This
->lock
);
1113 return WINCODEC_ERR_WRONGSTATE
;
1116 /* seek to start of stream */
1118 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1120 /* read all data from the stream */
1121 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1124 LeaveCriticalSection(&This
->lock
);
1128 ret
= DGifSlurp(This
->gif
);
1129 if (ret
== GIF_ERROR
)
1131 LeaveCriticalSection(&This
->lock
);
1135 /* make sure we don't use the stream after this method returns */
1136 This
->gif
->UserData
= NULL
;
1139 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1140 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1142 This
->stream
= pIStream
;
1143 IStream_AddRef(This
->stream
);
1145 This
->initialized
= TRUE
;
1147 LeaveCriticalSection(&This
->lock
);
1152 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1153 GUID
*pguidContainerFormat
)
1155 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1159 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1160 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1163 IWICComponentInfo
*compinfo
;
1165 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1167 hr
= CreateComponentInfo(&CLSID_WICGifDecoder
, &compinfo
);
1168 if (FAILED(hr
)) return hr
;
1170 hr
= IWICComponentInfo_QueryInterface(compinfo
, &IID_IWICBitmapDecoderInfo
,
1171 (void**)ppIDecoderInfo
);
1173 IWICComponentInfo_Release(compinfo
);
1178 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1180 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1181 WICColor colors
[256];
1183 int i
, trans
, count
;
1186 TRACE("(%p,%p)\n", iface
, palette
);
1189 return WINCODEC_ERR_WRONGSTATE
;
1191 cm
= This
->gif
->SColorMap
;
1194 if (cm
->ColorCount
> 256)
1196 ERR("GIF contains invalid number of colors: %d\n", cm
->ColorCount
);
1200 for (i
= 0; i
< cm
->ColorCount
; i
++)
1202 colors
[i
] = 0xff000000 | /* alpha */
1203 cm
->Colors
[i
].Red
<< 16 |
1204 cm
->Colors
[i
].Green
<< 8 |
1208 count
= cm
->ColorCount
;
1212 colors
[0] = 0xff000000;
1213 colors
[1] = 0xffffffff;
1215 for (i
= 2; i
< 256; i
++)
1216 colors
[i
] = 0xff000000;
1221 /* look for the transparent color extension */
1222 for (i
= 0; i
< This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlockCount
; i
++)
1224 eb
= This
->gif
->SavedImages
[This
->current_frame
].Extensions
.ExtensionBlocks
+ i
;
1225 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&& eb
->ByteCount
== 8)
1227 if (eb
->Bytes
[3] & 1)
1229 trans
= (unsigned char)eb
->Bytes
[6];
1230 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
1236 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1239 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1240 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1242 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1243 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1246 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1247 IWICBitmapSource
**ppIBitmapSource
)
1249 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1250 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1253 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1254 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1256 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1257 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1260 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1261 IWICBitmapSource
**ppIThumbnail
)
1263 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1264 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1267 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1270 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1272 if (!pCount
) return E_INVALIDARG
;
1274 EnterCriticalSection(&This
->lock
);
1275 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1276 LeaveCriticalSection(&This
->lock
);
1278 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1283 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1284 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1286 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1287 GifFrameDecode
*result
;
1288 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1290 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1292 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1294 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1295 if (!result
) return E_OUTOFMEMORY
;
1297 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1298 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1300 result
->frame
= &This
->gif
->SavedImages
[index
];
1301 IWICBitmapDecoder_AddRef(iface
);
1302 result
->parent
= This
;
1303 This
->current_frame
= index
;
1305 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1310 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1311 GifDecoder_QueryInterface
,
1314 GifDecoder_QueryCapability
,
1315 GifDecoder_Initialize
,
1316 GifDecoder_GetContainerFormat
,
1317 GifDecoder_GetDecoderInfo
,
1318 GifDecoder_CopyPalette
,
1319 GifDecoder_GetMetadataQueryReader
,
1320 GifDecoder_GetPreview
,
1321 GifDecoder_GetColorContexts
,
1322 GifDecoder_GetThumbnail
,
1323 GifDecoder_GetFrameCount
,
1327 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1328 REFIID iid
, void **ppv
)
1330 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1331 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1334 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1336 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1337 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1340 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1342 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1343 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1346 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1349 TRACE("(%p,%p)\n", iface
, guid
);
1351 if (!guid
) return E_INVALIDARG
;
1353 *guid
= GUID_ContainerFormatGif
;
1357 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1360 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1362 TRACE("%p,%p\n", iface
, count
);
1364 if (!count
) return E_INVALIDARG
;
1366 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1370 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1371 UINT index
, IWICMetadataReader
**reader
)
1373 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1376 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1378 if (!reader
) return E_INVALIDARG
;
1381 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1382 LSDReader_CreateInstance
, reader
);
1384 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1386 class_constructor constructor
;
1388 if (index
!= i
+ 1) continue;
1390 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1391 constructor
= APEReader_CreateInstance
;
1392 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1393 constructor
= GifCommentReader_CreateInstance
;
1395 constructor
= UnknownMetadataReader_CreateInstance
;
1397 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1398 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1399 constructor
, reader
);
1402 return E_INVALIDARG
;
1405 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1406 IEnumUnknown
**enumerator
)
1408 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1412 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1414 GifDecoder_Block_QueryInterface
,
1415 GifDecoder_Block_AddRef
,
1416 GifDecoder_Block_Release
,
1417 GifDecoder_Block_GetContainerFormat
,
1418 GifDecoder_Block_GetCount
,
1419 GifDecoder_Block_GetReaderByIndex
,
1420 GifDecoder_Block_GetEnumerator
1423 HRESULT
GifDecoder_CreateInstance(REFIID iid
, void** ppv
)
1428 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1432 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1433 if (!This
) return E_OUTOFMEMORY
;
1435 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1436 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1437 This
->stream
= NULL
;
1439 This
->initialized
= FALSE
;
1441 This
->current_frame
= 0;
1442 InitializeCriticalSection(&This
->lock
);
1443 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1445 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1446 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1451 typedef struct GifEncoder
1453 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1456 CRITICAL_SECTION lock
;
1457 BOOL initialized
, info_written
, committed
;
1459 WICColor palette
[256];
1463 static inline GifEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1465 return CONTAINING_RECORD(iface
, GifEncoder
, IWICBitmapEncoder_iface
);
1468 typedef struct GifFrameEncode
1470 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1472 GifEncoder
*encoder
;
1473 BOOL initialized
, interlace
, committed
;
1474 UINT width
, height
, lines
;
1476 WICColor palette
[256];
1481 static inline GifFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1483 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICBitmapFrameEncode_iface
);
1486 static HRESULT WINAPI
GifFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
, void **ppv
)
1488 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
1490 if (!ppv
) return E_INVALIDARG
;
1492 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1493 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1495 IWICBitmapFrameEncode_AddRef(iface
);
1501 return E_NOINTERFACE
;
1504 static ULONG WINAPI
GifFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1506 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1507 ULONG ref
= InterlockedIncrement(&This
->ref
);
1509 TRACE("%p -> %u\n", iface
, ref
);
1513 static ULONG WINAPI
GifFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1515 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1516 ULONG ref
= InterlockedDecrement(&This
->ref
);
1518 TRACE("%p -> %u\n", iface
, ref
);
1522 IWICBitmapEncoder_Release(&This
->encoder
->IWICBitmapEncoder_iface
);
1523 HeapFree(GetProcessHeap(), 0, This
->image_data
);
1524 HeapFree(GetProcessHeap(), 0, This
);
1530 static HRESULT WINAPI
GifFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
, IPropertyBag2
*options
)
1532 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1535 TRACE("%p,%p\n", iface
, options
);
1537 EnterCriticalSection(&This
->encoder
->lock
);
1539 if (!This
->initialized
)
1541 This
->initialized
= TRUE
;
1545 hr
= WINCODEC_ERR_WRONGSTATE
;
1547 LeaveCriticalSection(&This
->encoder
->lock
);
1552 static HRESULT WINAPI
GifFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
, UINT width
, UINT height
)
1554 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1557 TRACE("%p,%u,%u\n", iface
, width
, height
);
1559 if (!width
|| !height
) return E_INVALIDARG
;
1561 EnterCriticalSection(&This
->encoder
->lock
);
1563 if (This
->initialized
)
1565 HeapFree(GetProcessHeap(), 0, This
->image_data
);
1567 This
->image_data
= HeapAlloc(GetProcessHeap(), 0, width
* height
);
1568 if (This
->image_data
)
1570 This
->width
= width
;
1571 This
->height
= height
;
1578 hr
= WINCODEC_ERR_WRONGSTATE
;
1580 LeaveCriticalSection(&This
->encoder
->lock
);
1585 static HRESULT WINAPI
GifFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
, double xres
, double yres
)
1587 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1590 TRACE("%p,%f,%f\n", iface
, xres
, yres
);
1592 EnterCriticalSection(&This
->encoder
->lock
);
1594 if (This
->initialized
)
1601 hr
= WINCODEC_ERR_WRONGSTATE
;
1603 LeaveCriticalSection(&This
->encoder
->lock
);
1608 static HRESULT WINAPI
GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
, WICPixelFormatGUID
*format
)
1610 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1613 TRACE("%p,%s\n", iface
, debugstr_guid(format
));
1615 if (!format
) return E_INVALIDARG
;
1617 EnterCriticalSection(&This
->encoder
->lock
);
1619 if (This
->initialized
)
1621 *format
= GUID_WICPixelFormat8bppIndexed
;
1625 hr
= WINCODEC_ERR_WRONGSTATE
;
1627 LeaveCriticalSection(&This
->encoder
->lock
);
1632 static HRESULT WINAPI
GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
, UINT count
, IWICColorContext
**context
)
1634 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
1638 static HRESULT WINAPI
GifFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
, IWICPalette
*palette
)
1640 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1643 TRACE("%p,%p\n", iface
, palette
);
1645 if (!palette
) return E_INVALIDARG
;
1647 EnterCriticalSection(&This
->encoder
->lock
);
1649 if (This
->initialized
)
1650 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1652 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1654 LeaveCriticalSection(&This
->encoder
->lock
);
1658 static HRESULT WINAPI
GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*thumbnail
)
1660 FIXME("%p,%p: stub\n", iface
, thumbnail
);
1664 static HRESULT WINAPI
GifFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
, UINT lines
, UINT stride
, UINT size
, BYTE
*pixels
)
1666 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1669 TRACE("%p,%u,%u,%u,%p\n", iface
, lines
, stride
, size
, pixels
);
1671 if (!pixels
) return E_INVALIDARG
;
1673 EnterCriticalSection(&This
->encoder
->lock
);
1675 if (This
->initialized
&& This
->image_data
)
1677 if (This
->lines
+ lines
<= This
->height
)
1683 dst
= This
->image_data
+ This
->lines
* This
->width
;
1685 for (i
= 0; i
< lines
; i
++)
1687 memcpy(dst
, src
, This
->width
);
1692 This
->lines
+= lines
;
1699 hr
= WINCODEC_ERR_WRONGSTATE
;
1701 LeaveCriticalSection(&This
->encoder
->lock
);
1705 static HRESULT WINAPI
GifFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*source
, WICRect
*rc
)
1707 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1710 TRACE("%p,%p,%p\n", iface
, source
, rc
);
1712 if (!source
) return E_INVALIDARG
;
1714 EnterCriticalSection(&This
->encoder
->lock
);
1716 if (This
->initialized
)
1718 const GUID
*format
= &GUID_WICPixelFormat8bppIndexed
;
1720 hr
= configure_write_source(iface
, source
, rc
, format
,
1721 This
->width
, This
->height
, This
->xres
, This
->yres
);
1723 hr
= write_source(iface
, source
, rc
, format
, 8, This
->width
, This
->height
);
1726 hr
= WINCODEC_ERR_WRONGSTATE
;
1728 LeaveCriticalSection(&This
->encoder
->lock
);
1732 #define LZW_DICT_SIZE (1 << 12)
1736 short prefix
[LZW_DICT_SIZE
];
1737 unsigned char suffix
[LZW_DICT_SIZE
];
1742 struct lzw_dict dict
;
1743 short init_code_bits
, code_bits
, next_code
, clear_code
, eof_code
;
1746 int (*user_write_data
)(void *user_ptr
, void *data
, int length
);
1756 struct output_stream
1766 static int lzw_output_code(struct lzw_state
*state
, short code
)
1768 state
->bits_buf
|= code
<< state
->bits_count
;
1769 state
->bits_count
+= state
->code_bits
;
1771 while (state
->bits_count
>= 8)
1773 unsigned char byte
= (unsigned char)state
->bits_buf
;
1774 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1776 state
->bits_buf
>>= 8;
1777 state
->bits_count
-= 8;
1783 static inline int lzw_output_clear_code(struct lzw_state
*state
)
1785 return lzw_output_code(state
, state
->clear_code
);
1788 static inline int lzw_output_eof_code(struct lzw_state
*state
)
1790 return lzw_output_code(state
, state
->eof_code
);
1793 static int lzw_flush_bits(struct lzw_state
*state
)
1797 while (state
->bits_count
>= 8)
1799 byte
= (unsigned char)state
->bits_buf
;
1800 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1802 state
->bits_buf
>>= 8;
1803 state
->bits_count
-= 8;
1806 if (state
->bits_count
)
1808 static const char mask
[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1810 byte
= (unsigned char)state
->bits_buf
& mask
[state
->bits_count
];
1811 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1815 state
->bits_buf
= 0;
1816 state
->bits_count
= 0;
1821 static void lzw_dict_reset(struct lzw_state
*state
)
1825 state
->code_bits
= state
->init_code_bits
+ 1;
1826 state
->next_code
= (1 << state
->init_code_bits
) + 2;
1828 for(i
= 0; i
< LZW_DICT_SIZE
; i
++)
1830 state
->dict
.prefix
[i
] = 1 << 12; /* impossible LZW code value */
1831 state
->dict
.suffix
[i
] = 0;
1835 static void lzw_state_init(struct lzw_state
*state
, short init_code_bits
, void *user_write_data
, void *user_ptr
)
1837 state
->init_code_bits
= init_code_bits
;
1838 state
->clear_code
= 1 << init_code_bits
;
1839 state
->eof_code
= state
->clear_code
+ 1;
1840 state
->bits_buf
= 0;
1841 state
->bits_count
= 0;
1842 state
->user_write_data
= user_write_data
;
1843 state
->user_ptr
= user_ptr
;
1845 lzw_dict_reset(state
);
1848 static int lzw_dict_add(struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1850 if (state
->next_code
< LZW_DICT_SIZE
)
1852 state
->dict
.prefix
[state
->next_code
] = prefix
;
1853 state
->dict
.suffix
[state
->next_code
] = suffix
;
1855 if ((state
->next_code
& (state
->next_code
- 1)) == 0)
1859 return state
->next_code
;
1865 static short lzw_dict_lookup(const struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1869 for (i
= 0; i
< state
->next_code
; i
++)
1871 if (state
->dict
.prefix
[i
] == prefix
&& state
->dict
.suffix
[i
] == suffix
)
1878 static inline int write_byte(struct output_stream
*out
, char byte
)
1880 if (out
->gif_block
.len
== 255)
1882 if (IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
), NULL
) != S_OK
)
1885 out
->gif_block
.len
= 0;
1888 out
->gif_block
.data
[out
->gif_block
.len
++] = byte
;
1893 static int write_data(void *user_ptr
, void *user_data
, int length
)
1895 unsigned char *data
= user_data
;
1896 struct output_stream
*out
= user_ptr
;
1901 if (!write_byte(out
, *data
++)) return 0;
1907 static int flush_output_data(void *user_ptr
)
1909 struct output_stream
*out
= user_ptr
;
1911 if (out
->gif_block
.len
)
1913 if (IStream_Write(out
->out
, &out
->gif_block
, out
->gif_block
.len
+ sizeof(out
->gif_block
.len
), NULL
) != S_OK
)
1917 /* write GIF block terminator */
1918 out
->gif_block
.len
= 0;
1919 return IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
.len
), NULL
) == S_OK
;
1922 static inline int read_byte(struct input_stream
*in
, unsigned char *byte
)
1934 static HRESULT
gif_compress(IStream
*out_stream
, const BYTE
*in_data
, ULONG in_size
)
1936 struct input_stream in
;
1937 struct output_stream out
;
1938 struct lzw_state state
;
1939 short init_code_bits
, prefix
, code
;
1940 unsigned char suffix
;
1945 out
.gif_block
.len
= 0;
1946 out
.out
= out_stream
;
1948 init_code_bits
= suffix
= 8;
1949 if (IStream_Write(out
.out
, &suffix
, sizeof(suffix
), NULL
) != S_OK
)
1952 lzw_state_init(&state
, init_code_bits
, write_data
, &out
);
1954 if (!lzw_output_clear_code(&state
))
1957 if (read_byte(&in
, &suffix
))
1961 while (read_byte(&in
, &suffix
))
1963 code
= lzw_dict_lookup(&state
, prefix
, suffix
);
1966 if (!lzw_output_code(&state
, prefix
))
1969 if (lzw_dict_add(&state
, prefix
, suffix
) == -1)
1971 if (!lzw_output_clear_code(&state
))
1973 lzw_dict_reset(&state
);
1982 if (!lzw_output_code(&state
, prefix
))
1984 if (!lzw_output_eof_code(&state
))
1986 if (!lzw_flush_bits(&state
))
1990 return flush_output_data(&out
) ? S_OK
: E_FAIL
;
1993 static HRESULT WINAPI
GifFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1995 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1998 TRACE("%p\n", iface
);
2000 EnterCriticalSection(&This
->encoder
->lock
);
2002 if (This
->image_data
&& This
->lines
== This
->height
&& !This
->committed
)
2004 BYTE gif_palette
[256][3];
2008 if (!This
->encoder
->info_written
)
2010 struct logical_screen_descriptor lsd
;
2012 /* Logical Screen Descriptor */
2013 memcpy(lsd
.signature
, "GIF89a", 6);
2014 lsd
.width
= This
->width
;
2015 lsd
.height
= This
->height
;
2017 if (This
->encoder
->colors
)
2018 lsd
.packed
|= 0x80; /* global color table flag */
2019 lsd
.packed
|= 0x07 << 4; /* color resolution */
2020 lsd
.packed
|= 0x07; /* global color table size */
2021 lsd
.background_color_index
= 0; /* FIXME */
2022 lsd
.pixel_aspect_ratio
= 0;
2023 hr
= IStream_Write(This
->encoder
->stream
, &lsd
, sizeof(lsd
), NULL
);
2024 if (hr
== S_OK
&& This
->encoder
->colors
)
2028 /* Global Color Table */
2029 memset(gif_palette
, 0, sizeof(gif_palette
));
2030 for (i
= 0; i
< This
->encoder
->colors
; i
++)
2032 gif_palette
[i
][0] = (This
->encoder
->palette
[i
] >> 16) & 0xff;
2033 gif_palette
[i
][1] = (This
->encoder
->palette
[i
] >> 8) & 0xff;
2034 gif_palette
[i
][2] = This
->encoder
->palette
[i
] & 0xff;
2036 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2039 /* FIXME: write GCE, APE, etc. GIF extensions */
2042 This
->encoder
->info_written
= TRUE
;
2047 char image_separator
= 0x2c;
2049 hr
= IStream_Write(This
->encoder
->stream
, &image_separator
, sizeof(image_separator
), NULL
);
2052 struct image_descriptor imd
;
2054 /* Image Descriptor */
2057 imd
.width
= This
->width
;
2058 imd
.height
= This
->height
;
2062 imd
.packed
|= 0x80; /* local color table flag */
2063 imd
.packed
|= 0x07; /* local color table size */
2065 /* FIXME: interlace flag */
2066 hr
= IStream_Write(This
->encoder
->stream
, &imd
, sizeof(imd
), NULL
);
2067 if (hr
== S_OK
&& This
->colors
)
2071 /* Local Color Table */
2072 memset(gif_palette
, 0, sizeof(gif_palette
));
2073 for (i
= 0; i
< This
->colors
; i
++)
2075 gif_palette
[i
][0] = (This
->palette
[i
] >> 16) & 0xff;
2076 gif_palette
[i
][1] = (This
->palette
[i
] >> 8) & 0xff;
2077 gif_palette
[i
][2] = This
->palette
[i
] & 0xff;
2079 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2083 hr
= gif_compress(This
->encoder
->stream
, This
->image_data
, This
->width
* This
->height
);
2085 This
->committed
= TRUE
;
2092 hr
= WINCODEC_ERR_WRONGSTATE
;
2094 LeaveCriticalSection(&This
->encoder
->lock
);
2098 static HRESULT WINAPI
GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
, IWICMetadataQueryWriter
**writer
)
2100 FIXME("%p, %p: stub\n", iface
, writer
);
2104 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl
=
2106 GifFrameEncode_QueryInterface
,
2107 GifFrameEncode_AddRef
,
2108 GifFrameEncode_Release
,
2109 GifFrameEncode_Initialize
,
2110 GifFrameEncode_SetSize
,
2111 GifFrameEncode_SetResolution
,
2112 GifFrameEncode_SetPixelFormat
,
2113 GifFrameEncode_SetColorContexts
,
2114 GifFrameEncode_SetPalette
,
2115 GifFrameEncode_SetThumbnail
,
2116 GifFrameEncode_WritePixels
,
2117 GifFrameEncode_WriteSource
,
2118 GifFrameEncode_Commit
,
2119 GifFrameEncode_GetMetadataQueryWriter
2122 static HRESULT WINAPI
GifEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
, void **ppv
)
2124 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
2126 if (!ppv
) return E_INVALIDARG
;
2128 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2129 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
2131 IWICBitmapEncoder_AddRef(iface
);
2137 return E_NOINTERFACE
;
2140 static ULONG WINAPI
GifEncoder_AddRef(IWICBitmapEncoder
*iface
)
2142 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2143 ULONG ref
= InterlockedIncrement(&This
->ref
);
2145 TRACE("%p -> %u\n", iface
, ref
);
2149 static ULONG WINAPI
GifEncoder_Release(IWICBitmapEncoder
*iface
)
2151 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2152 ULONG ref
= InterlockedDecrement(&This
->ref
);
2154 TRACE("%p -> %u\n", iface
, ref
);
2158 if (This
->stream
) IStream_Release(This
->stream
);
2159 This
->lock
.DebugInfo
->Spare
[0] = 0;
2160 DeleteCriticalSection(&This
->lock
);
2161 HeapFree(GetProcessHeap(), 0, This
);
2167 static HRESULT WINAPI
GifEncoder_Initialize(IWICBitmapEncoder
*iface
, IStream
*stream
, WICBitmapEncoderCacheOption option
)
2169 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2172 TRACE("%p,%p,%#x\n", iface
, stream
, option
);
2174 if (!stream
) return E_INVALIDARG
;
2176 EnterCriticalSection(&This
->lock
);
2178 if (!This
->initialized
)
2180 IStream_AddRef(stream
);
2181 This
->stream
= stream
;
2182 This
->initialized
= TRUE
;
2186 hr
= WINCODEC_ERR_WRONGSTATE
;
2188 LeaveCriticalSection(&This
->lock
);
2193 static HRESULT WINAPI
GifEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
, GUID
*format
)
2195 if (!format
) return E_INVALIDARG
;
2197 *format
= GUID_ContainerFormatGif
;
2201 static HRESULT WINAPI
GifEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
2203 IWICComponentInfo
*comp_info
;
2206 TRACE("%p,%p\n", iface
, info
);
2208 if (!info
) return E_INVALIDARG
;
2210 hr
= CreateComponentInfo(&CLSID_WICGifEncoder
, &comp_info
);
2213 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
2214 IWICComponentInfo_Release(comp_info
);
2219 static HRESULT WINAPI
GifEncoder_SetColorContexts(IWICBitmapEncoder
*iface
, UINT count
, IWICColorContext
**context
)
2221 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
2225 static HRESULT WINAPI
GifEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
2227 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2230 TRACE("%p,%p\n", iface
, palette
);
2232 if (!palette
) return E_INVALIDARG
;
2234 EnterCriticalSection(&This
->lock
);
2236 if (This
->initialized
)
2237 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
2239 hr
= WINCODEC_ERR_NOTINITIALIZED
;
2241 LeaveCriticalSection(&This
->lock
);
2245 static HRESULT WINAPI
GifEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*thumbnail
)
2247 TRACE("%p,%p\n", iface
, thumbnail
);
2248 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2251 static HRESULT WINAPI
GifEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*preview
)
2253 TRACE("%p,%p\n", iface
, preview
);
2254 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2257 static HRESULT WINAPI
GifEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
, IWICBitmapFrameEncode
**frame
, IPropertyBag2
**options
)
2259 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2262 TRACE("%p,%p,%p\n", iface
, frame
, options
);
2264 if (!frame
) return E_INVALIDARG
;
2266 EnterCriticalSection(&This
->lock
);
2268 if (This
->initialized
&& !This
->committed
)
2270 GifFrameEncode
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
2275 ret
->IWICBitmapFrameEncode_iface
.lpVtbl
= &GifFrameEncode_Vtbl
;
2277 ret
->encoder
= This
;
2278 ret
->initialized
= FALSE
;
2279 ret
->interlace
= FALSE
; /* FIXME: read from the properties */
2280 ret
->committed
= FALSE
;
2287 ret
->image_data
= NULL
;
2288 IWICBitmapEncoder_AddRef(iface
);
2289 *frame
= &ret
->IWICBitmapFrameEncode_iface
;
2295 hr
= CreatePropertyBag2(NULL
, 0, options
);
2298 IWICBitmapFrameEncode_Release(*frame
);
2307 hr
= WINCODEC_ERR_WRONGSTATE
;
2309 LeaveCriticalSection(&This
->lock
);
2315 static HRESULT WINAPI
GifEncoder_Commit(IWICBitmapEncoder
*iface
)
2317 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2320 TRACE("%p\n", iface
);
2322 EnterCriticalSection(&This
->lock
);
2324 if (This
->initialized
&& !This
->committed
)
2326 char gif_trailer
= 0x3b;
2328 /* FIXME: write text, comment GIF extensions */
2330 hr
= IStream_Write(This
->stream
, &gif_trailer
, sizeof(gif_trailer
), NULL
);
2332 This
->committed
= TRUE
;
2335 hr
= WINCODEC_ERR_WRONGSTATE
;
2337 LeaveCriticalSection(&This
->lock
);
2341 static HRESULT WINAPI
GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
, IWICMetadataQueryWriter
**writer
)
2343 FIXME("%p,%p: stub\n", iface
, writer
);
2347 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl
=
2349 GifEncoder_QueryInterface
,
2352 GifEncoder_Initialize
,
2353 GifEncoder_GetContainerFormat
,
2354 GifEncoder_GetEncoderInfo
,
2355 GifEncoder_SetColorContexts
,
2356 GifEncoder_SetPalette
,
2357 GifEncoder_SetThumbnail
,
2358 GifEncoder_SetPreview
,
2359 GifEncoder_CreateNewFrame
,
2361 GifEncoder_GetMetadataQueryWriter
2364 HRESULT
GifEncoder_CreateInstance(REFIID iid
, void **ppv
)
2369 TRACE("%s,%p\n", debugstr_guid(iid
), ppv
);
2373 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
2374 if (!This
) return E_OUTOFMEMORY
;
2376 This
->IWICBitmapEncoder_iface
.lpVtbl
= &GifEncoder_Vtbl
;
2378 This
->stream
= NULL
;
2379 InitializeCriticalSection(&This
->lock
);
2380 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifEncoder.lock");
2381 This
->initialized
= FALSE
;
2382 This
->info_written
= FALSE
;
2383 This
->committed
= FALSE
;
2387 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2388 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);