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
23 #define NONAMELESSUNION
31 #include "wincodecs_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
39 struct logical_screen_descriptor
45 /* global_color_table_flag : 1;
46 * color_resolution : 3;
48 * global_color_table_size : 3;
50 BYTE background_color_index
;
51 BYTE pixel_aspect_ratio
;
54 struct image_descriptor
61 /* local_color_table_flag : 1;
65 * local_color_table_size : 3;
71 static LPWSTR
strdupAtoW(const char *src
)
73 int len
= MultiByteToWideChar(CP_ACP
, 0, src
, -1, NULL
, 0);
74 LPWSTR dst
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
75 if (dst
) MultiByteToWideChar(CP_ACP
, 0, src
, -1, dst
, len
);
79 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
80 MetadataItem
**items
, DWORD
*count
)
82 struct logical_screen_descriptor lsd_data
;
90 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
91 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
93 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 9);
94 if (!result
) return E_OUTOFMEMORY
;
96 for (i
= 0; i
< 9; i
++)
98 PropVariantInit(&result
[i
].schema
);
99 PropVariantInit(&result
[i
].id
);
100 PropVariantInit(&result
[i
].value
);
103 result
[0].id
.vt
= VT_LPWSTR
;
104 result
[0].id
.pwszVal
= strdupAtoW("Signature");
105 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
106 result
[0].value
.caub
.cElems
= sizeof(lsd_data
.signature
);
107 result
[0].value
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data
.signature
));
108 memcpy(result
[0].value
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
110 result
[1].id
.vt
= VT_LPWSTR
;
111 result
[1].id
.pwszVal
= strdupAtoW("Width");
112 result
[1].value
.vt
= VT_UI2
;
113 result
[1].value
.uiVal
= lsd_data
.width
;
115 result
[2].id
.vt
= VT_LPWSTR
;
116 result
[2].id
.pwszVal
= strdupAtoW("Height");
117 result
[2].value
.vt
= VT_UI2
;
118 result
[2].value
.uiVal
= lsd_data
.height
;
120 result
[3].id
.vt
= VT_LPWSTR
;
121 result
[3].id
.pwszVal
= strdupAtoW("GlobalColorTableFlag");
122 result
[3].value
.vt
= VT_BOOL
;
123 result
[3].value
.boolVal
= (lsd_data
.packed
>> 7) & 1;
125 result
[4].id
.vt
= VT_LPWSTR
;
126 result
[4].id
.pwszVal
= strdupAtoW("ColorResolution");
127 result
[4].value
.vt
= VT_UI1
;
128 result
[4].value
.bVal
= (lsd_data
.packed
>> 4) & 7;
130 result
[5].id
.vt
= VT_LPWSTR
;
131 result
[5].id
.pwszVal
= strdupAtoW("SortFlag");
132 result
[5].value
.vt
= VT_BOOL
;
133 result
[5].value
.boolVal
= (lsd_data
.packed
>> 3) & 1;
135 result
[6].id
.vt
= VT_LPWSTR
;
136 result
[6].id
.pwszVal
= strdupAtoW("GlobalColorTableSize");
137 result
[6].value
.vt
= VT_UI1
;
138 result
[6].value
.bVal
= lsd_data
.packed
& 7;
140 result
[7].id
.vt
= VT_LPWSTR
;
141 result
[7].id
.pwszVal
= strdupAtoW("BackgroundColorIndex");
142 result
[7].value
.vt
= VT_UI1
;
143 result
[7].value
.bVal
= lsd_data
.background_color_index
;
145 result
[8].id
.vt
= VT_LPWSTR
;
146 result
[8].id
.pwszVal
= strdupAtoW("PixelAspectRatio");
147 result
[8].value
.vt
= VT_UI1
;
148 result
[8].value
.bVal
= lsd_data
.pixel_aspect_ratio
;
156 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
158 &CLSID_WICLSDMetadataReader
,
162 HRESULT
LSDReader_CreateInstance(REFIID iid
, void **ppv
)
164 return MetadataReader_Create(&LSDReader_Vtbl
, iid
, ppv
);
167 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
168 MetadataItem
**items
, DWORD
*count
)
170 struct image_descriptor imd_data
;
173 MetadataItem
*result
;
178 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
179 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
181 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 8);
182 if (!result
) return E_OUTOFMEMORY
;
184 for (i
= 0; i
< 8; i
++)
186 PropVariantInit(&result
[i
].schema
);
187 PropVariantInit(&result
[i
].id
);
188 PropVariantInit(&result
[i
].value
);
191 result
[0].id
.vt
= VT_LPWSTR
;
192 result
[0].id
.pwszVal
= strdupAtoW("Left");
193 result
[0].value
.vt
= VT_UI2
;
194 result
[0].value
.uiVal
= imd_data
.left
;
196 result
[1].id
.vt
= VT_LPWSTR
;
197 result
[1].id
.pwszVal
= strdupAtoW("Top");
198 result
[1].value
.vt
= VT_UI2
;
199 result
[1].value
.uiVal
= imd_data
.top
;
201 result
[2].id
.vt
= VT_LPWSTR
;
202 result
[2].id
.pwszVal
= strdupAtoW("Width");
203 result
[2].value
.vt
= VT_UI2
;
204 result
[2].value
.uiVal
= imd_data
.width
;
206 result
[3].id
.vt
= VT_LPWSTR
;
207 result
[3].id
.pwszVal
= strdupAtoW("Height");
208 result
[3].value
.vt
= VT_UI2
;
209 result
[3].value
.uiVal
= imd_data
.height
;
211 result
[4].id
.vt
= VT_LPWSTR
;
212 result
[4].id
.pwszVal
= strdupAtoW("LocalColorTableFlag");
213 result
[4].value
.vt
= VT_BOOL
;
214 result
[4].value
.boolVal
= (imd_data
.packed
>> 7) & 1;
216 result
[5].id
.vt
= VT_LPWSTR
;
217 result
[5].id
.pwszVal
= strdupAtoW("InterlaceFlag");
218 result
[5].value
.vt
= VT_BOOL
;
219 result
[5].value
.boolVal
= (imd_data
.packed
>> 6) & 1;
221 result
[6].id
.vt
= VT_LPWSTR
;
222 result
[6].id
.pwszVal
= strdupAtoW("SortFlag");
223 result
[6].value
.vt
= VT_BOOL
;
224 result
[6].value
.boolVal
= (imd_data
.packed
>> 5) & 1;
226 result
[7].id
.vt
= VT_LPWSTR
;
227 result
[7].id
.pwszVal
= strdupAtoW("LocalColorTableSize");
228 result
[7].value
.vt
= VT_UI1
;
229 result
[7].value
.bVal
= imd_data
.packed
& 7;
237 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
239 &CLSID_WICIMDMetadataReader
,
243 HRESULT
IMDReader_CreateInstance(REFIID iid
, void **ppv
)
245 return MetadataReader_Create(&IMDReader_Vtbl
, iid
, ppv
);
248 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
249 MetadataItem
**items
, DWORD
*count
)
251 #include "pshpack1.h"
252 struct graphic_control_extension
257 * user_input_flag : 1;
258 * transparency_flag : 1;
261 BYTE transparent_color_index
;
266 MetadataItem
*result
;
271 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
272 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
274 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 5);
275 if (!result
) return E_OUTOFMEMORY
;
277 for (i
= 0; i
< 5; i
++)
279 PropVariantInit(&result
[i
].schema
);
280 PropVariantInit(&result
[i
].id
);
281 PropVariantInit(&result
[i
].value
);
284 result
[0].id
.vt
= VT_LPWSTR
;
285 result
[0].id
.pwszVal
= strdupAtoW("Disposal");
286 result
[0].value
.vt
= VT_UI1
;
287 result
[0].value
.bVal
= (gce_data
.packed
>> 2) & 7;
289 result
[1].id
.vt
= VT_LPWSTR
;
290 result
[1].id
.pwszVal
= strdupAtoW("UserInputFlag");
291 result
[1].value
.vt
= VT_BOOL
;
292 result
[1].value
.boolVal
= (gce_data
.packed
>> 1) & 1;
294 result
[2].id
.vt
= VT_LPWSTR
;
295 result
[2].id
.pwszVal
= strdupAtoW("TransparencyFlag");
296 result
[2].value
.vt
= VT_BOOL
;
297 result
[2].value
.boolVal
= gce_data
.packed
& 1;
299 result
[3].id
.vt
= VT_LPWSTR
;
300 result
[3].id
.pwszVal
= strdupAtoW("Delay");
301 result
[3].value
.vt
= VT_UI2
;
302 result
[3].value
.uiVal
= gce_data
.delay
;
304 result
[4].id
.vt
= VT_LPWSTR
;
305 result
[4].id
.pwszVal
= strdupAtoW("TransparentColorIndex");
306 result
[4].value
.vt
= VT_UI1
;
307 result
[4].value
.bVal
= gce_data
.transparent_color_index
;
315 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
317 &CLSID_WICGCEMetadataReader
,
321 HRESULT
GCEReader_CreateInstance(REFIID iid
, void **ppv
)
323 return MetadataReader_Create(&GCEReader_Vtbl
, iid
, ppv
);
326 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
327 MetadataItem
**items
, DWORD
*count
)
329 #include "pshpack1.h"
330 struct application_extension
332 BYTE extension_introducer
;
333 BYTE extension_label
;
335 BYTE application
[11];
339 ULONG bytesread
, data_size
, i
;
340 MetadataItem
*result
;
347 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
348 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
349 if (ape_data
.extension_introducer
!= 0x21 ||
350 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
351 ape_data
.block_size
!= 11)
359 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
360 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
362 HeapFree(GetProcessHeap(), 0, data
);
365 if (!subblock_size
) break;
368 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
371 BYTE
*new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
374 HeapFree(GetProcessHeap(), 0, data
);
379 data
[data_size
] = subblock_size
;
380 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
381 if (FAILED(hr
) || bytesread
!= subblock_size
)
383 HeapFree(GetProcessHeap(), 0, data
);
386 data_size
+= subblock_size
+ 1;
389 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
) * 2);
392 HeapFree(GetProcessHeap(), 0, data
);
393 return E_OUTOFMEMORY
;
396 for (i
= 0; i
< 2; i
++)
398 PropVariantInit(&result
[i
].schema
);
399 PropVariantInit(&result
[i
].id
);
400 PropVariantInit(&result
[i
].value
);
403 result
[0].id
.vt
= VT_LPWSTR
;
404 result
[0].id
.pwszVal
= strdupAtoW("Application");
405 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
406 result
[0].value
.caub
.cElems
= sizeof(ape_data
.application
);
407 result
[0].value
.caub
.pElems
= HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data
.application
));
408 memcpy(result
[0].value
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
410 result
[1].id
.vt
= VT_LPWSTR
;
411 result
[1].id
.pwszVal
= strdupAtoW("Data");
412 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
413 result
[1].value
.caub
.cElems
= data_size
;
414 result
[1].value
.caub
.pElems
= data
;
422 static const MetadataHandlerVtbl APEReader_Vtbl
= {
424 &CLSID_WICAPEMetadataReader
,
428 HRESULT
APEReader_CreateInstance(REFIID iid
, void **ppv
)
430 return MetadataReader_Create(&APEReader_Vtbl
, iid
, ppv
);
433 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
434 MetadataItem
**items
, DWORD
*count
)
436 #include "pshpack1.h"
439 BYTE extension_introducer
;
440 BYTE extension_label
;
444 ULONG bytesread
, data_size
;
445 MetadataItem
*result
;
452 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
453 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
454 if (ext_data
.extension_introducer
!= 0x21 ||
455 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
463 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
464 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
466 HeapFree(GetProcessHeap(), 0, data
);
469 if (!subblock_size
) break;
472 data
= HeapAlloc(GetProcessHeap(), 0, subblock_size
+ 1);
475 char *new_data
= HeapReAlloc(GetProcessHeap(), 0, data
, data_size
+ subblock_size
+ 1);
478 HeapFree(GetProcessHeap(), 0, data
);
483 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
484 if (FAILED(hr
) || bytesread
!= subblock_size
)
486 HeapFree(GetProcessHeap(), 0, data
);
489 data_size
+= subblock_size
;
494 result
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(MetadataItem
));
497 HeapFree(GetProcessHeap(), 0, data
);
498 return E_OUTOFMEMORY
;
501 PropVariantInit(&result
->schema
);
502 PropVariantInit(&result
->id
);
503 PropVariantInit(&result
->value
);
505 result
->id
.vt
= VT_LPWSTR
;
506 result
->id
.pwszVal
= strdupAtoW("TextEntry");
507 result
->value
.vt
= VT_LPSTR
;
508 result
->value
.pszVal
= data
;
516 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
518 &CLSID_WICGifCommentMetadataReader
,
519 load_GifComment_metadata
522 HRESULT
GifCommentReader_CreateInstance(REFIID iid
, void **ppv
)
524 return MetadataReader_Create(&GifCommentReader_Vtbl
, iid
, ppv
);
527 static IStream
*create_stream(const void *data
, int data_size
)
534 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
535 if (!hdata
) return NULL
;
537 locked_data
= GlobalLock(hdata
);
538 memcpy(locked_data
, data
, data_size
);
541 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
542 return FAILED(hr
) ? NULL
: stream
;
545 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
546 class_constructor constructor
,
547 IWICMetadataReader
**reader
)
550 IWICMetadataReader
*metadata_reader
;
551 IWICPersistStream
*persist
;
554 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
556 hr
= constructor(&IID_IWICMetadataReader
, (void**)&metadata_reader
);
557 if (FAILED(hr
)) return hr
;
559 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
562 IWICMetadataReader_Release(metadata_reader
);
566 stream
= create_stream(data
, data_size
);
567 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
568 IStream_Release(stream
);
570 IWICPersistStream_Release(persist
);
572 *reader
= metadata_reader
;
577 IWICBitmapDecoder IWICBitmapDecoder_iface
;
578 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
580 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
585 CRITICAL_SECTION lock
;
589 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
590 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
596 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
598 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
601 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
603 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
606 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
608 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
611 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
613 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
616 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
619 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
620 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
622 if (!ppv
) return E_INVALIDARG
;
624 if (IsEqualIID(&IID_IUnknown
, iid
) ||
625 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
626 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
628 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
630 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
632 *ppv
= &This
->IWICMetadataBlockReader_iface
;
637 return E_NOINTERFACE
;
640 IUnknown_AddRef((IUnknown
*)*ppv
);
644 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
646 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
647 ULONG ref
= InterlockedIncrement(&This
->ref
);
649 TRACE("(%p) refcount=%lu\n", iface
, ref
);
654 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
656 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
657 ULONG ref
= InterlockedDecrement(&This
->ref
);
659 TRACE("(%p) refcount=%lu\n", iface
, ref
);
663 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
664 HeapFree(GetProcessHeap(), 0, This
);
670 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
671 UINT
*puiWidth
, UINT
*puiHeight
)
673 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
674 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
676 *puiWidth
= This
->frame
->ImageDesc
.Width
;
677 *puiHeight
= This
->frame
->ImageDesc
.Height
;
682 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
683 WICPixelFormatGUID
*pPixelFormat
)
685 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
690 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
691 double *pDpiX
, double *pDpiY
)
693 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
694 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
695 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
696 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
698 *pDpiX
= 96.0 / aspect
;
704 static void copy_palette(ColorMapObject
*cm
, Extensions
*extensions
, int count
, WICColor
*colors
)
710 for (i
= 0; i
< count
; i
++)
712 colors
[i
] = 0xff000000 | /* alpha */
713 cm
->Colors
[i
].Red
<< 16 |
714 cm
->Colors
[i
].Green
<< 8 |
720 colors
[0] = 0xff000000;
721 colors
[1] = 0xffffffff;
722 for (i
= 2; i
< count
; i
++)
723 colors
[i
] = 0xff000000;
726 /* look for the transparent color extension */
727 for (i
= 0; i
< extensions
->ExtensionBlockCount
; i
++)
729 ExtensionBlock
*eb
= extensions
->ExtensionBlocks
+ i
;
730 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&&
731 eb
->ByteCount
== 8 && eb
->Bytes
[3] & 1)
733 int trans
= (unsigned char)eb
->Bytes
[6];
734 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
740 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
741 IWICPalette
*pIPalette
)
743 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
744 WICColor colors
[256];
745 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
748 TRACE("(%p,%p)\n", iface
, pIPalette
);
751 count
= cm
->ColorCount
;
754 cm
= This
->parent
->gif
->SColorMap
;
755 count
= This
->parent
->gif
->SColorTableSize
;
760 ERR("GIF contains %i colors???\n", count
);
764 copy_palette(cm
, &This
->frame
->Extensions
, count
, colors
);
766 return IWICPalette_InitializeCustom(pIPalette
, colors
, count
);
769 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
770 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
771 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
773 UINT row_offset
; /* number of bytes into the source rows where the data starts */
783 rect
.Width
= srcwidth
;
784 rect
.Height
= srcheight
;
789 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
793 if (dststride
< rc
->Width
)
796 if ((dststride
* rc
->Height
) > dstbuffersize
)
802 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
805 src
= srcbuffer
+ srcstride
* (y
/8);
807 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
809 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
811 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
813 memcpy(dst
, src
, rc
->Width
);
819 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
820 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
822 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
823 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
825 if (This
->frame
->ImageDesc
.Interlace
)
827 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
828 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
829 prc
, cbStride
, cbBufferSize
, pbBuffer
);
833 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
834 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
835 prc
, cbStride
, cbBufferSize
, pbBuffer
);
839 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
840 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
842 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
844 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
846 if (!ppIMetadataQueryReader
)
849 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
852 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
853 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
855 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
856 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
859 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
860 IWICBitmapSource
**ppIThumbnail
)
862 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
863 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
866 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
867 GifFrameDecode_QueryInterface
,
868 GifFrameDecode_AddRef
,
869 GifFrameDecode_Release
,
870 GifFrameDecode_GetSize
,
871 GifFrameDecode_GetPixelFormat
,
872 GifFrameDecode_GetResolution
,
873 GifFrameDecode_CopyPalette
,
874 GifFrameDecode_CopyPixels
,
875 GifFrameDecode_GetMetadataQueryReader
,
876 GifFrameDecode_GetColorContexts
,
877 GifFrameDecode_GetThumbnail
880 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
881 REFIID iid
, void **ppv
)
883 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
884 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
887 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
889 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
890 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
893 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
895 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
896 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
899 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
902 TRACE("(%p,%p)\n", iface
, guid
);
904 if (!guid
) return E_INVALIDARG
;
906 *guid
= GUID_ContainerFormatGif
;
910 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
913 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
915 TRACE("%p,%p\n", iface
, count
);
917 if (!count
) return E_INVALIDARG
;
919 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
923 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
926 IWICMetadataReader
*metadata_reader
;
927 IWICPersistStream
*persist
;
929 struct image_descriptor IMD_data
;
931 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
933 hr
= IMDReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
934 if (FAILED(hr
)) return hr
;
936 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
939 IWICMetadataReader_Release(metadata_reader
);
943 /* recreate IMD structure from GIF decoder data */
944 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
945 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
946 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
947 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
950 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
951 if (This
->frame
->ImageDesc
.ColorMap
)
953 /* local_color_table_flag */
954 IMD_data
.packed
|= 1 << 7;
955 /* local_color_table_size */
956 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
958 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
961 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
962 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
963 IStream_Release(stream
);
965 IWICPersistStream_Release(persist
);
967 *reader
= metadata_reader
;
971 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
972 UINT index
, IWICMetadataReader
**reader
)
974 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
975 class_constructor constructor
;
980 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
982 if (!reader
) return E_INVALIDARG
;
985 return create_IMD_metadata_reader(This
, reader
);
987 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
990 ext
= This
->frame
->Extensions
.ExtensionBlocks
+ index
- 1;
991 if (ext
->Function
== GRAPHICS_EXT_FUNC_CODE
)
993 constructor
= GCEReader_CreateInstance
;
994 data
= ext
->Bytes
+ 3;
995 data_size
= ext
->ByteCount
- 4;
997 else if (ext
->Function
== COMMENT_EXT_FUNC_CODE
)
999 constructor
= GifCommentReader_CreateInstance
;
1001 data_size
= ext
->ByteCount
;
1005 constructor
= UnknownMetadataReader_CreateInstance
;
1007 data_size
= ext
->ByteCount
;
1010 return create_metadata_reader(data
, data_size
, constructor
, reader
);
1013 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1014 IEnumUnknown
**enumerator
)
1016 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1020 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
1022 GifFrameDecode_Block_QueryInterface
,
1023 GifFrameDecode_Block_AddRef
,
1024 GifFrameDecode_Block_Release
,
1025 GifFrameDecode_Block_GetContainerFormat
,
1026 GifFrameDecode_Block_GetCount
,
1027 GifFrameDecode_Block_GetReaderByIndex
,
1028 GifFrameDecode_Block_GetEnumerator
1031 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1034 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1035 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1037 if (!ppv
) return E_INVALIDARG
;
1039 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1040 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1042 *ppv
= &This
->IWICBitmapDecoder_iface
;
1044 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1046 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1051 return E_NOINTERFACE
;
1054 IUnknown_AddRef((IUnknown
*)*ppv
);
1058 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1060 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1061 ULONG ref
= InterlockedIncrement(&This
->ref
);
1063 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1068 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1070 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1071 ULONG ref
= InterlockedDecrement(&This
->ref
);
1073 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1079 IStream_Release(This
->stream
);
1080 DGifCloseFile(This
->gif
);
1082 This
->lock
.DebugInfo
->Spare
[0] = 0;
1083 DeleteCriticalSection(&This
->lock
);
1084 HeapFree(GetProcessHeap(), 0, This
);
1090 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1095 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1097 if (!stream
|| !capability
) return E_INVALIDARG
;
1099 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1100 if (hr
!= S_OK
) return hr
;
1102 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1103 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1104 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1108 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1109 IStream
*stream
= gif
->UserData
;
1115 ERR("attempting to read file after initialization\n");
1119 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1120 if (FAILED(hr
)) bytesread
= 0;
1124 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1125 WICDecodeOptions cacheOptions
)
1127 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1131 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1133 EnterCriticalSection(&This
->lock
);
1135 if (This
->initialized
|| This
->gif
)
1137 WARN("already initialized\n");
1138 LeaveCriticalSection(&This
->lock
);
1139 return WINCODEC_ERR_WRONGSTATE
;
1142 /* seek to start of stream */
1144 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1146 /* read all data from the stream */
1147 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1150 LeaveCriticalSection(&This
->lock
);
1154 ret
= DGifSlurp(This
->gif
);
1155 if (ret
== GIF_ERROR
)
1157 LeaveCriticalSection(&This
->lock
);
1161 /* make sure we don't use the stream after this method returns */
1162 This
->gif
->UserData
= NULL
;
1165 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1166 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1168 This
->stream
= pIStream
;
1169 IStream_AddRef(This
->stream
);
1171 This
->initialized
= TRUE
;
1173 LeaveCriticalSection(&This
->lock
);
1178 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1179 GUID
*pguidContainerFormat
)
1181 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1185 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1186 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1188 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1190 return get_decoder_info(&CLSID_WICGifDecoder
, ppIDecoderInfo
);
1193 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1195 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1196 WICColor colors
[256];
1200 TRACE("(%p,%p)\n", iface
, palette
);
1203 return WINCODEC_ERR_WRONGSTATE
;
1205 cm
= This
->gif
->SColorMap
;
1206 count
= This
->gif
->SColorTableSize
;
1210 ERR("GIF contains invalid number of colors: %d\n", count
);
1214 copy_palette(cm
, &This
->gif
->SavedImages
[This
->current_frame
].Extensions
, count
, colors
);
1216 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1219 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1220 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1222 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1224 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1226 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
1228 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1231 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1232 IWICBitmapSource
**ppIBitmapSource
)
1234 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1235 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1238 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1239 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1241 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1242 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1245 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1246 IWICBitmapSource
**ppIThumbnail
)
1248 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1249 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1252 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1255 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1257 if (!pCount
) return E_INVALIDARG
;
1259 EnterCriticalSection(&This
->lock
);
1260 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1261 LeaveCriticalSection(&This
->lock
);
1263 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1268 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1269 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1271 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1272 GifFrameDecode
*result
;
1273 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1275 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1277 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1279 result
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode
));
1280 if (!result
) return E_OUTOFMEMORY
;
1282 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1283 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1285 result
->frame
= &This
->gif
->SavedImages
[index
];
1286 IWICBitmapDecoder_AddRef(iface
);
1287 result
->parent
= This
;
1288 This
->current_frame
= index
;
1290 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1295 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1296 GifDecoder_QueryInterface
,
1299 GifDecoder_QueryCapability
,
1300 GifDecoder_Initialize
,
1301 GifDecoder_GetContainerFormat
,
1302 GifDecoder_GetDecoderInfo
,
1303 GifDecoder_CopyPalette
,
1304 GifDecoder_GetMetadataQueryReader
,
1305 GifDecoder_GetPreview
,
1306 GifDecoder_GetColorContexts
,
1307 GifDecoder_GetThumbnail
,
1308 GifDecoder_GetFrameCount
,
1312 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1313 REFIID iid
, void **ppv
)
1315 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1316 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1319 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1321 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1322 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1325 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1327 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1328 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1331 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1334 TRACE("(%p,%p)\n", iface
, guid
);
1336 if (!guid
) return E_INVALIDARG
;
1338 *guid
= GUID_ContainerFormatGif
;
1342 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1345 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1347 TRACE("%p,%p\n", iface
, count
);
1349 if (!count
) return E_INVALIDARG
;
1351 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1355 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1356 UINT index
, IWICMetadataReader
**reader
)
1358 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1361 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1363 if (!reader
) return E_INVALIDARG
;
1366 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1367 LSDReader_CreateInstance
, reader
);
1369 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1371 class_constructor constructor
;
1373 if (index
!= i
+ 1) continue;
1375 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1376 constructor
= APEReader_CreateInstance
;
1377 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1378 constructor
= GifCommentReader_CreateInstance
;
1380 constructor
= UnknownMetadataReader_CreateInstance
;
1382 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1383 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1384 constructor
, reader
);
1387 return E_INVALIDARG
;
1390 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1391 IEnumUnknown
**enumerator
)
1393 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1397 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1399 GifDecoder_Block_QueryInterface
,
1400 GifDecoder_Block_AddRef
,
1401 GifDecoder_Block_Release
,
1402 GifDecoder_Block_GetContainerFormat
,
1403 GifDecoder_Block_GetCount
,
1404 GifDecoder_Block_GetReaderByIndex
,
1405 GifDecoder_Block_GetEnumerator
1408 HRESULT
GifDecoder_CreateInstance(REFIID iid
, void** ppv
)
1413 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1417 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder
));
1418 if (!This
) return E_OUTOFMEMORY
;
1420 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1421 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1422 This
->stream
= NULL
;
1424 This
->initialized
= FALSE
;
1426 This
->current_frame
= 0;
1427 InitializeCriticalSection(&This
->lock
);
1428 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1430 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1431 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1436 typedef struct GifEncoder
1438 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1441 CRITICAL_SECTION lock
;
1442 BOOL initialized
, info_written
, committed
;
1444 WICColor palette
[256];
1448 static inline GifEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1450 return CONTAINING_RECORD(iface
, GifEncoder
, IWICBitmapEncoder_iface
);
1453 typedef struct GifFrameEncode
1455 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1456 IWICMetadataBlockWriter IWICMetadataBlockWriter_iface
;
1458 GifEncoder
*encoder
;
1459 BOOL initialized
, interlace
, committed
;
1460 UINT width
, height
, lines
;
1462 WICColor palette
[256];
1467 static inline GifFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1469 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICBitmapFrameEncode_iface
);
1472 static inline GifFrameEncode
*impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter
*iface
)
1474 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICMetadataBlockWriter_iface
);
1477 static HRESULT WINAPI
GifFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
, void **ppv
)
1479 GifFrameEncode
*encoder
= impl_from_IWICBitmapFrameEncode(iface
);
1481 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
1483 if (!ppv
) return E_INVALIDARG
;
1485 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1486 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1490 else if (IsEqualIID(&IID_IWICMetadataBlockWriter
, iid
))
1492 *ppv
= &encoder
->IWICMetadataBlockWriter_iface
;
1497 return E_NOINTERFACE
;
1500 IUnknown_AddRef((IUnknown
*)*ppv
);
1504 static ULONG WINAPI
GifFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1506 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1507 ULONG ref
= InterlockedIncrement(&This
->ref
);
1509 TRACE("%p -> %lu\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 -> %lu\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
->colors
, 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 GifFrameEncode
*encode
= impl_from_IWICBitmapFrameEncode(iface
);
2102 TRACE("iface, %p, writer %p.\n", iface
, writer
);
2105 return E_INVALIDARG
;
2107 if (!encode
->initialized
)
2108 return WINCODEC_ERR_NOTINITIALIZED
;
2110 return MetadataQueryWriter_CreateInstance(&encode
->IWICMetadataBlockWriter_iface
, NULL
, writer
);
2113 static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl
=
2115 GifFrameEncode_QueryInterface
,
2116 GifFrameEncode_AddRef
,
2117 GifFrameEncode_Release
,
2118 GifFrameEncode_Initialize
,
2119 GifFrameEncode_SetSize
,
2120 GifFrameEncode_SetResolution
,
2121 GifFrameEncode_SetPixelFormat
,
2122 GifFrameEncode_SetColorContexts
,
2123 GifFrameEncode_SetPalette
,
2124 GifFrameEncode_SetThumbnail
,
2125 GifFrameEncode_WritePixels
,
2126 GifFrameEncode_WriteSource
,
2127 GifFrameEncode_Commit
,
2128 GifFrameEncode_GetMetadataQueryWriter
2131 static HRESULT WINAPI
GifEncoder_QueryInterface(IWICBitmapEncoder
*iface
, REFIID iid
, void **ppv
)
2133 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
2135 if (!ppv
) return E_INVALIDARG
;
2137 if (IsEqualIID(&IID_IUnknown
, iid
) ||
2138 IsEqualIID(&IID_IWICBitmapEncoder
, iid
))
2140 IWICBitmapEncoder_AddRef(iface
);
2146 return E_NOINTERFACE
;
2149 static ULONG WINAPI
GifEncoder_AddRef(IWICBitmapEncoder
*iface
)
2151 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2152 ULONG ref
= InterlockedIncrement(&This
->ref
);
2154 TRACE("%p -> %lu\n", iface
, ref
);
2158 static ULONG WINAPI
GifEncoder_Release(IWICBitmapEncoder
*iface
)
2160 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2161 ULONG ref
= InterlockedDecrement(&This
->ref
);
2163 TRACE("%p -> %lu\n", iface
, ref
);
2167 if (This
->stream
) IStream_Release(This
->stream
);
2168 This
->lock
.DebugInfo
->Spare
[0] = 0;
2169 DeleteCriticalSection(&This
->lock
);
2170 HeapFree(GetProcessHeap(), 0, This
);
2176 static HRESULT WINAPI
GifEncoder_Initialize(IWICBitmapEncoder
*iface
, IStream
*stream
, WICBitmapEncoderCacheOption option
)
2178 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2181 TRACE("%p,%p,%#x\n", iface
, stream
, option
);
2183 if (!stream
) return E_INVALIDARG
;
2185 EnterCriticalSection(&This
->lock
);
2187 if (!This
->initialized
)
2189 IStream_AddRef(stream
);
2190 This
->stream
= stream
;
2191 This
->initialized
= TRUE
;
2195 hr
= WINCODEC_ERR_WRONGSTATE
;
2197 LeaveCriticalSection(&This
->lock
);
2202 static HRESULT WINAPI
GifEncoder_GetContainerFormat(IWICBitmapEncoder
*iface
, GUID
*format
)
2204 if (!format
) return E_INVALIDARG
;
2206 *format
= GUID_ContainerFormatGif
;
2210 static HRESULT WINAPI
GifEncoder_GetEncoderInfo(IWICBitmapEncoder
*iface
, IWICBitmapEncoderInfo
**info
)
2212 IWICComponentInfo
*comp_info
;
2215 TRACE("%p,%p\n", iface
, info
);
2217 if (!info
) return E_INVALIDARG
;
2219 hr
= CreateComponentInfo(&CLSID_WICGifEncoder
, &comp_info
);
2222 hr
= IWICComponentInfo_QueryInterface(comp_info
, &IID_IWICBitmapEncoderInfo
, (void **)info
);
2223 IWICComponentInfo_Release(comp_info
);
2228 static HRESULT WINAPI
GifEncoder_SetColorContexts(IWICBitmapEncoder
*iface
, UINT count
, IWICColorContext
**context
)
2230 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
2234 static HRESULT WINAPI
GifEncoder_SetPalette(IWICBitmapEncoder
*iface
, IWICPalette
*palette
)
2236 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2239 TRACE("%p,%p\n", iface
, palette
);
2241 if (!palette
) return E_INVALIDARG
;
2243 EnterCriticalSection(&This
->lock
);
2245 if (This
->initialized
)
2246 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
2248 hr
= WINCODEC_ERR_NOTINITIALIZED
;
2250 LeaveCriticalSection(&This
->lock
);
2254 static HRESULT WINAPI
GifEncoder_SetThumbnail(IWICBitmapEncoder
*iface
, IWICBitmapSource
*thumbnail
)
2256 TRACE("%p,%p\n", iface
, thumbnail
);
2257 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2260 static HRESULT WINAPI
GifEncoder_SetPreview(IWICBitmapEncoder
*iface
, IWICBitmapSource
*preview
)
2262 TRACE("%p,%p\n", iface
, preview
);
2263 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
2266 static HRESULT WINAPI
GifEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter
*iface
, REFIID iid
, void **ppv
)
2268 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2270 return IWICBitmapFrameEncode_QueryInterface(&frame_encoder
->IWICBitmapFrameEncode_iface
, iid
, ppv
);
2273 static ULONG WINAPI
GifEncoderFrame_Block_AddRef(IWICMetadataBlockWriter
*iface
)
2275 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2277 return IWICBitmapFrameEncode_AddRef(&frame_encoder
->IWICBitmapFrameEncode_iface
);
2280 static ULONG WINAPI
GifEncoderFrame_Block_Release(IWICMetadataBlockWriter
*iface
)
2282 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2284 return IWICBitmapFrameEncode_Release(&frame_encoder
->IWICBitmapFrameEncode_iface
);
2287 static HRESULT WINAPI
GifEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter
*iface
, GUID
*container_format
)
2289 FIXME("iface %p, container_format %p stub.\n", iface
, container_format
);
2294 static HRESULT WINAPI
GifEncoderFrame_Block_GetCount(IWICMetadataBlockWriter
*iface
, UINT
*count
)
2296 FIXME("iface %p, count %p stub.\n", iface
, count
);
2301 static HRESULT WINAPI
GifEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter
*iface
,
2302 UINT index
, IWICMetadataReader
**metadata_reader
)
2304 FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface
, index
, metadata_reader
);
2309 static HRESULT WINAPI
GifEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter
*iface
, IEnumUnknown
**enum_metadata
)
2311 FIXME("iface %p, enum_metadata %p stub.\n", iface
, enum_metadata
);
2316 static HRESULT WINAPI
GifEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter
*iface
,
2317 IWICMetadataBlockReader
*block_reader
)
2319 FIXME("iface %p, block_reader %p stub.\n", iface
, block_reader
);
2324 static HRESULT WINAPI
GifEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
,
2325 IWICMetadataWriter
**metadata_writer
)
2327 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface
, index
, metadata_writer
);
2332 static HRESULT WINAPI
GifEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter
*iface
, IWICMetadataWriter
*metadata_writer
)
2334 FIXME("iface %p, metadata_writer %p stub.\n", iface
, metadata_writer
);
2339 static HRESULT WINAPI
GifEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
,
2340 IWICMetadataWriter
*metadata_writer
)
2342 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface
, index
, metadata_writer
);
2347 static HRESULT WINAPI
GifEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
)
2349 FIXME("iface %p, index %u stub.\n", iface
, index
);
2354 static const IWICMetadataBlockWriterVtbl GifFrameEncode_BlockVtbl
= {
2355 GifEncoderFrame_Block_QueryInterface
,
2356 GifEncoderFrame_Block_AddRef
,
2357 GifEncoderFrame_Block_Release
,
2358 GifEncoderFrame_Block_GetContainerFormat
,
2359 GifEncoderFrame_Block_GetCount
,
2360 GifEncoderFrame_Block_GetReaderByIndex
,
2361 GifEncoderFrame_Block_GetEnumerator
,
2362 GifEncoderFrame_Block_InitializeFromBlockReader
,
2363 GifEncoderFrame_Block_GetWriterByIndex
,
2364 GifEncoderFrame_Block_AddWriter
,
2365 GifEncoderFrame_Block_SetWriterByIndex
,
2366 GifEncoderFrame_Block_RemoveWriterByIndex
,
2369 static HRESULT WINAPI
GifEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
, IWICBitmapFrameEncode
**frame
, IPropertyBag2
**options
)
2371 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2374 TRACE("%p,%p,%p\n", iface
, frame
, options
);
2376 if (!frame
) return E_INVALIDARG
;
2378 EnterCriticalSection(&This
->lock
);
2380 if (This
->initialized
&& !This
->committed
)
2382 GifFrameEncode
*ret
= HeapAlloc(GetProcessHeap(), 0, sizeof(*ret
));
2387 ret
->IWICBitmapFrameEncode_iface
.lpVtbl
= &GifFrameEncode_Vtbl
;
2388 ret
->IWICMetadataBlockWriter_iface
.lpVtbl
= &GifFrameEncode_BlockVtbl
;
2391 ret
->encoder
= This
;
2392 ret
->initialized
= FALSE
;
2393 ret
->interlace
= FALSE
; /* FIXME: read from the properties */
2394 ret
->committed
= FALSE
;
2401 ret
->image_data
= NULL
;
2402 IWICBitmapEncoder_AddRef(iface
);
2403 *frame
= &ret
->IWICBitmapFrameEncode_iface
;
2409 hr
= CreatePropertyBag2(NULL
, 0, options
);
2412 IWICBitmapFrameEncode_Release(*frame
);
2421 hr
= WINCODEC_ERR_WRONGSTATE
;
2423 LeaveCriticalSection(&This
->lock
);
2429 static HRESULT WINAPI
GifEncoder_Commit(IWICBitmapEncoder
*iface
)
2431 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2434 TRACE("%p\n", iface
);
2436 EnterCriticalSection(&This
->lock
);
2438 if (This
->initialized
&& !This
->committed
)
2440 char gif_trailer
= 0x3b;
2442 /* FIXME: write text, comment GIF extensions */
2444 hr
= IStream_Write(This
->stream
, &gif_trailer
, sizeof(gif_trailer
), NULL
);
2446 This
->committed
= TRUE
;
2449 hr
= WINCODEC_ERR_WRONGSTATE
;
2451 LeaveCriticalSection(&This
->lock
);
2455 static HRESULT WINAPI
GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
, IWICMetadataQueryWriter
**writer
)
2457 FIXME("%p,%p: stub\n", iface
, writer
);
2461 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl
=
2463 GifEncoder_QueryInterface
,
2466 GifEncoder_Initialize
,
2467 GifEncoder_GetContainerFormat
,
2468 GifEncoder_GetEncoderInfo
,
2469 GifEncoder_SetColorContexts
,
2470 GifEncoder_SetPalette
,
2471 GifEncoder_SetThumbnail
,
2472 GifEncoder_SetPreview
,
2473 GifEncoder_CreateNewFrame
,
2475 GifEncoder_GetMetadataQueryWriter
2478 HRESULT
GifEncoder_CreateInstance(REFIID iid
, void **ppv
)
2483 TRACE("%s,%p\n", debugstr_guid(iid
), ppv
);
2487 This
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
));
2488 if (!This
) return E_OUTOFMEMORY
;
2490 This
->IWICBitmapEncoder_iface
.lpVtbl
= &GifEncoder_Vtbl
;
2492 This
->stream
= NULL
;
2493 InitializeCriticalSection(&This
->lock
);
2494 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifEncoder.lock");
2495 This
->initialized
= FALSE
;
2496 This
->info_written
= FALSE
;
2497 This
->committed
= FALSE
;
2501 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2502 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);