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
30 #include "wincodecs_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs
);
38 struct logical_screen_descriptor
44 /* global_color_table_flag : 1;
45 * color_resolution : 3;
47 * global_color_table_size : 3;
49 BYTE background_color_index
;
50 BYTE pixel_aspect_ratio
;
53 struct image_descriptor
60 /* local_color_table_flag : 1;
64 * local_color_table_size : 3;
70 static HRESULT
load_LSD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
71 MetadataItem
**items
, DWORD
*count
)
73 struct logical_screen_descriptor lsd_data
;
81 hr
= IStream_Read(stream
, &lsd_data
, sizeof(lsd_data
), &bytesread
);
82 if (FAILED(hr
) || bytesread
!= sizeof(lsd_data
)) return S_OK
;
84 result
= calloc(9, sizeof(MetadataItem
));
85 if (!result
) return E_OUTOFMEMORY
;
87 for (i
= 0; i
< 9; i
++)
89 PropVariantInit(&result
[i
].schema
);
90 PropVariantInit(&result
[i
].id
);
91 PropVariantInit(&result
[i
].value
);
94 result
[0].id
.vt
= VT_LPWSTR
;
95 SHStrDupW(L
"Signature", &result
[0].id
.pwszVal
);
96 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
97 result
[0].value
.caub
.cElems
= sizeof(lsd_data
.signature
);
98 result
[0].value
.caub
.pElems
= CoTaskMemAlloc(sizeof(lsd_data
.signature
));
99 memcpy(result
[0].value
.caub
.pElems
, lsd_data
.signature
, sizeof(lsd_data
.signature
));
101 result
[1].id
.vt
= VT_LPWSTR
;
102 SHStrDupW(L
"Width", &result
[1].id
.pwszVal
);
103 result
[1].value
.vt
= VT_UI2
;
104 result
[1].value
.uiVal
= lsd_data
.width
;
106 result
[2].id
.vt
= VT_LPWSTR
;
107 SHStrDupW(L
"Height", &result
[2].id
.pwszVal
);
108 result
[2].value
.vt
= VT_UI2
;
109 result
[2].value
.uiVal
= lsd_data
.height
;
111 result
[3].id
.vt
= VT_LPWSTR
;
112 SHStrDupW(L
"GlobalColorTableFlag", &result
[3].id
.pwszVal
);
113 result
[3].value
.vt
= VT_BOOL
;
114 result
[3].value
.boolVal
= (lsd_data
.packed
>> 7) & 1;
116 result
[4].id
.vt
= VT_LPWSTR
;
117 SHStrDupW(L
"ColorResolution", &result
[4].id
.pwszVal
);
118 result
[4].value
.vt
= VT_UI1
;
119 result
[4].value
.bVal
= (lsd_data
.packed
>> 4) & 7;
121 result
[5].id
.vt
= VT_LPWSTR
;
122 SHStrDupW(L
"SortFlag", &result
[5].id
.pwszVal
);
123 result
[5].value
.vt
= VT_BOOL
;
124 result
[5].value
.boolVal
= (lsd_data
.packed
>> 3) & 1;
126 result
[6].id
.vt
= VT_LPWSTR
;
127 SHStrDupW(L
"GlobalColorTableSize", &result
[6].id
.pwszVal
);
128 result
[6].value
.vt
= VT_UI1
;
129 result
[6].value
.bVal
= lsd_data
.packed
& 7;
131 result
[7].id
.vt
= VT_LPWSTR
;
132 SHStrDupW(L
"BackgroundColorIndex", &result
[7].id
.pwszVal
);
133 result
[7].value
.vt
= VT_UI1
;
134 result
[7].value
.bVal
= lsd_data
.background_color_index
;
136 result
[8].id
.vt
= VT_LPWSTR
;
137 SHStrDupW(L
"PixelAspectRatio", &result
[8].id
.pwszVal
);
138 result
[8].value
.vt
= VT_UI1
;
139 result
[8].value
.bVal
= lsd_data
.pixel_aspect_ratio
;
147 static const MetadataHandlerVtbl LSDReader_Vtbl
= {
149 &CLSID_WICLSDMetadataReader
,
153 HRESULT
LSDReader_CreateInstance(REFIID iid
, void **ppv
)
155 return MetadataReader_Create(&LSDReader_Vtbl
, iid
, ppv
);
158 static HRESULT
load_IMD_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
159 MetadataItem
**items
, DWORD
*count
)
161 struct image_descriptor imd_data
;
164 MetadataItem
*result
;
169 hr
= IStream_Read(stream
, &imd_data
, sizeof(imd_data
), &bytesread
);
170 if (FAILED(hr
) || bytesread
!= sizeof(imd_data
)) return S_OK
;
172 result
= calloc(8, sizeof(MetadataItem
));
173 if (!result
) return E_OUTOFMEMORY
;
175 for (i
= 0; i
< 8; i
++)
177 PropVariantInit(&result
[i
].schema
);
178 PropVariantInit(&result
[i
].id
);
179 PropVariantInit(&result
[i
].value
);
182 result
[0].id
.vt
= VT_LPWSTR
;
183 SHStrDupW(L
"Left", &result
[0].id
.pwszVal
);
184 result
[0].value
.vt
= VT_UI2
;
185 result
[0].value
.uiVal
= imd_data
.left
;
187 result
[1].id
.vt
= VT_LPWSTR
;
188 SHStrDupW(L
"Top", &result
[1].id
.pwszVal
);
189 result
[1].value
.vt
= VT_UI2
;
190 result
[1].value
.uiVal
= imd_data
.top
;
192 result
[2].id
.vt
= VT_LPWSTR
;
193 SHStrDupW(L
"Width", &result
[2].id
.pwszVal
);
194 result
[2].value
.vt
= VT_UI2
;
195 result
[2].value
.uiVal
= imd_data
.width
;
197 result
[3].id
.vt
= VT_LPWSTR
;
198 SHStrDupW(L
"Height", &result
[3].id
.pwszVal
);
199 result
[3].value
.vt
= VT_UI2
;
200 result
[3].value
.uiVal
= imd_data
.height
;
202 result
[4].id
.vt
= VT_LPWSTR
;
203 SHStrDupW(L
"LocalColorTableFlag", &result
[4].id
.pwszVal
);
204 result
[4].value
.vt
= VT_BOOL
;
205 result
[4].value
.boolVal
= (imd_data
.packed
>> 7) & 1;
207 result
[5].id
.vt
= VT_LPWSTR
;
208 SHStrDupW(L
"InterlaceFlag", &result
[5].id
.pwszVal
);
209 result
[5].value
.vt
= VT_BOOL
;
210 result
[5].value
.boolVal
= (imd_data
.packed
>> 6) & 1;
212 result
[6].id
.vt
= VT_LPWSTR
;
213 SHStrDupW(L
"SortFlag", &result
[6].id
.pwszVal
);
214 result
[6].value
.vt
= VT_BOOL
;
215 result
[6].value
.boolVal
= (imd_data
.packed
>> 5) & 1;
217 result
[7].id
.vt
= VT_LPWSTR
;
218 SHStrDupW(L
"LocalColorTableSize", &result
[7].id
.pwszVal
);
219 result
[7].value
.vt
= VT_UI1
;
220 result
[7].value
.bVal
= imd_data
.packed
& 7;
228 static const MetadataHandlerVtbl IMDReader_Vtbl
= {
230 &CLSID_WICIMDMetadataReader
,
234 HRESULT
IMDReader_CreateInstance(REFIID iid
, void **ppv
)
236 return MetadataReader_Create(&IMDReader_Vtbl
, iid
, ppv
);
239 static HRESULT
load_GCE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
240 MetadataItem
**items
, DWORD
*count
)
242 #include "pshpack1.h"
243 struct graphic_control_extension
248 * user_input_flag : 1;
249 * transparency_flag : 1;
252 BYTE transparent_color_index
;
257 MetadataItem
*result
;
262 hr
= IStream_Read(stream
, &gce_data
, sizeof(gce_data
), &bytesread
);
263 if (FAILED(hr
) || bytesread
!= sizeof(gce_data
)) return S_OK
;
265 result
= calloc(5, sizeof(MetadataItem
));
266 if (!result
) return E_OUTOFMEMORY
;
268 for (i
= 0; i
< 5; i
++)
270 PropVariantInit(&result
[i
].schema
);
271 PropVariantInit(&result
[i
].id
);
272 PropVariantInit(&result
[i
].value
);
275 result
[0].id
.vt
= VT_LPWSTR
;
276 SHStrDupW(L
"Disposal", &result
[0].id
.pwszVal
);
277 result
[0].value
.vt
= VT_UI1
;
278 result
[0].value
.bVal
= (gce_data
.packed
>> 2) & 7;
280 result
[1].id
.vt
= VT_LPWSTR
;
281 SHStrDupW(L
"UserInputFlag", &result
[1].id
.pwszVal
);
282 result
[1].value
.vt
= VT_BOOL
;
283 result
[1].value
.boolVal
= (gce_data
.packed
>> 1) & 1;
285 result
[2].id
.vt
= VT_LPWSTR
;
286 SHStrDupW(L
"TransparencyFlag", &result
[2].id
.pwszVal
);
287 result
[2].value
.vt
= VT_BOOL
;
288 result
[2].value
.boolVal
= gce_data
.packed
& 1;
290 result
[3].id
.vt
= VT_LPWSTR
;
291 SHStrDupW(L
"Delay", &result
[3].id
.pwszVal
);
292 result
[3].value
.vt
= VT_UI2
;
293 result
[3].value
.uiVal
= gce_data
.delay
;
295 result
[4].id
.vt
= VT_LPWSTR
;
296 SHStrDupW(L
"TransparentColorIndex", &result
[4].id
.pwszVal
);
297 result
[4].value
.vt
= VT_UI1
;
298 result
[4].value
.bVal
= gce_data
.transparent_color_index
;
306 static const MetadataHandlerVtbl GCEReader_Vtbl
= {
308 &CLSID_WICGCEMetadataReader
,
312 HRESULT
GCEReader_CreateInstance(REFIID iid
, void **ppv
)
314 return MetadataReader_Create(&GCEReader_Vtbl
, iid
, ppv
);
317 static HRESULT
load_APE_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
318 MetadataItem
**items
, DWORD
*count
)
320 #include "pshpack1.h"
321 struct application_extension
323 BYTE extension_introducer
;
324 BYTE extension_label
;
326 BYTE application
[11];
330 ULONG bytesread
, data_size
, i
;
331 MetadataItem
*result
;
338 hr
= IStream_Read(stream
, &ape_data
, sizeof(ape_data
), &bytesread
);
339 if (FAILED(hr
) || bytesread
!= sizeof(ape_data
)) return S_OK
;
340 if (ape_data
.extension_introducer
!= 0x21 ||
341 ape_data
.extension_label
!= APPLICATION_EXT_FUNC_CODE
||
342 ape_data
.block_size
!= 11)
350 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
351 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
356 if (!subblock_size
) break;
359 data
= CoTaskMemAlloc(subblock_size
+ 1);
362 BYTE
*new_data
= CoTaskMemRealloc(data
, data_size
+ subblock_size
+ 1);
370 data
[data_size
] = subblock_size
;
371 hr
= IStream_Read(stream
, data
+ data_size
+ 1, subblock_size
, &bytesread
);
372 if (FAILED(hr
) || bytesread
!= subblock_size
)
377 data_size
+= subblock_size
+ 1;
380 result
= calloc(2, sizeof(MetadataItem
));
384 return E_OUTOFMEMORY
;
387 for (i
= 0; i
< 2; i
++)
389 PropVariantInit(&result
[i
].schema
);
390 PropVariantInit(&result
[i
].id
);
391 PropVariantInit(&result
[i
].value
);
394 result
[0].id
.vt
= VT_LPWSTR
;
395 SHStrDupW(L
"Application", &result
[0].id
.pwszVal
);
396 result
[0].value
.vt
= VT_UI1
|VT_VECTOR
;
397 result
[0].value
.caub
.cElems
= sizeof(ape_data
.application
);
398 result
[0].value
.caub
.pElems
= CoTaskMemAlloc(sizeof(ape_data
.application
));
399 memcpy(result
[0].value
.caub
.pElems
, ape_data
.application
, sizeof(ape_data
.application
));
401 result
[1].id
.vt
= VT_LPWSTR
;
402 SHStrDupW(L
"Data", &result
[1].id
.pwszVal
);
403 result
[1].value
.vt
= VT_UI1
|VT_VECTOR
;
404 result
[1].value
.caub
.cElems
= data_size
;
405 result
[1].value
.caub
.pElems
= data
;
413 static const MetadataHandlerVtbl APEReader_Vtbl
= {
415 &CLSID_WICAPEMetadataReader
,
419 HRESULT
APEReader_CreateInstance(REFIID iid
, void **ppv
)
421 return MetadataReader_Create(&APEReader_Vtbl
, iid
, ppv
);
424 static HRESULT
load_GifComment_metadata(IStream
*stream
, const GUID
*vendor
, DWORD options
,
425 MetadataItem
**items
, DWORD
*count
)
427 #include "pshpack1.h"
430 BYTE extension_introducer
;
431 BYTE extension_label
;
435 ULONG bytesread
, data_size
;
436 MetadataItem
*result
;
443 hr
= IStream_Read(stream
, &ext_data
, sizeof(ext_data
), &bytesread
);
444 if (FAILED(hr
) || bytesread
!= sizeof(ext_data
)) return S_OK
;
445 if (ext_data
.extension_introducer
!= 0x21 ||
446 ext_data
.extension_label
!= COMMENT_EXT_FUNC_CODE
)
454 hr
= IStream_Read(stream
, &subblock_size
, sizeof(subblock_size
), &bytesread
);
455 if (FAILED(hr
) || bytesread
!= sizeof(subblock_size
))
460 if (!subblock_size
) break;
463 data
= CoTaskMemAlloc(subblock_size
+ 1);
466 char *new_data
= CoTaskMemRealloc(data
, data_size
+ subblock_size
+ 1);
474 hr
= IStream_Read(stream
, data
+ data_size
, subblock_size
, &bytesread
);
475 if (FAILED(hr
) || bytesread
!= subblock_size
)
480 data_size
+= subblock_size
;
485 result
= calloc(1, sizeof(MetadataItem
));
489 return E_OUTOFMEMORY
;
492 PropVariantInit(&result
->schema
);
493 PropVariantInit(&result
->id
);
494 PropVariantInit(&result
->value
);
496 result
->id
.vt
= VT_LPWSTR
;
497 SHStrDupW(L
"TextEntry", &result
->id
.pwszVal
);
498 result
->value
.vt
= VT_LPSTR
;
499 result
->value
.pszVal
= data
;
507 static const MetadataHandlerVtbl GifCommentReader_Vtbl
= {
509 &CLSID_WICGifCommentMetadataReader
,
510 load_GifComment_metadata
513 HRESULT
GifCommentReader_CreateInstance(REFIID iid
, void **ppv
)
515 return MetadataReader_Create(&GifCommentReader_Vtbl
, iid
, ppv
);
518 static IStream
*create_stream(const void *data
, int data_size
)
525 hdata
= GlobalAlloc(GMEM_MOVEABLE
, data_size
);
526 if (!hdata
) return NULL
;
528 locked_data
= GlobalLock(hdata
);
529 memcpy(locked_data
, data
, data_size
);
532 hr
= CreateStreamOnHGlobal(hdata
, TRUE
, &stream
);
533 return FAILED(hr
) ? NULL
: stream
;
536 static HRESULT
create_metadata_reader(const void *data
, int data_size
,
537 class_constructor constructor
,
538 IWICMetadataReader
**reader
)
541 IWICMetadataReader
*metadata_reader
;
542 IWICPersistStream
*persist
;
545 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
547 hr
= constructor(&IID_IWICMetadataReader
, (void**)&metadata_reader
);
548 if (FAILED(hr
)) return hr
;
550 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
553 IWICMetadataReader_Release(metadata_reader
);
557 stream
= create_stream(data
, data_size
);
558 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
559 IStream_Release(stream
);
561 IWICPersistStream_Release(persist
);
563 *reader
= metadata_reader
;
568 IWICBitmapDecoder IWICBitmapDecoder_iface
;
569 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
571 BYTE LSD_data
[13]; /* Logical Screen Descriptor */
576 CRITICAL_SECTION lock
;
580 IWICBitmapFrameDecode IWICBitmapFrameDecode_iface
;
581 IWICMetadataBlockReader IWICMetadataBlockReader_iface
;
587 static inline GifDecoder
*impl_from_IWICBitmapDecoder(IWICBitmapDecoder
*iface
)
589 return CONTAINING_RECORD(iface
, GifDecoder
, IWICBitmapDecoder_iface
);
592 static inline GifDecoder
*impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
594 return CONTAINING_RECORD(iface
, GifDecoder
, IWICMetadataBlockReader_iface
);
597 static inline GifFrameDecode
*impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode
*iface
)
599 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICBitmapFrameDecode_iface
);
602 static inline GifFrameDecode
*frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader
*iface
)
604 return CONTAINING_RECORD(iface
, GifFrameDecode
, IWICMetadataBlockReader_iface
);
607 static HRESULT WINAPI
GifFrameDecode_QueryInterface(IWICBitmapFrameDecode
*iface
, REFIID iid
,
610 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
611 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
613 if (!ppv
) return E_INVALIDARG
;
615 if (IsEqualIID(&IID_IUnknown
, iid
) ||
616 IsEqualIID(&IID_IWICBitmapSource
, iid
) ||
617 IsEqualIID(&IID_IWICBitmapFrameDecode
, iid
))
619 *ppv
= &This
->IWICBitmapFrameDecode_iface
;
621 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
623 *ppv
= &This
->IWICMetadataBlockReader_iface
;
628 return E_NOINTERFACE
;
631 IUnknown_AddRef((IUnknown
*)*ppv
);
635 static ULONG WINAPI
GifFrameDecode_AddRef(IWICBitmapFrameDecode
*iface
)
637 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
638 ULONG ref
= InterlockedIncrement(&This
->ref
);
640 TRACE("(%p) refcount=%lu\n", iface
, ref
);
645 static ULONG WINAPI
GifFrameDecode_Release(IWICBitmapFrameDecode
*iface
)
647 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
648 ULONG ref
= InterlockedDecrement(&This
->ref
);
650 TRACE("(%p) refcount=%lu\n", iface
, ref
);
654 IWICBitmapDecoder_Release(&This
->parent
->IWICBitmapDecoder_iface
);
661 static HRESULT WINAPI
GifFrameDecode_GetSize(IWICBitmapFrameDecode
*iface
,
662 UINT
*puiWidth
, UINT
*puiHeight
)
664 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
665 TRACE("(%p,%p,%p)\n", iface
, puiWidth
, puiHeight
);
667 *puiWidth
= This
->frame
->ImageDesc
.Width
;
668 *puiHeight
= This
->frame
->ImageDesc
.Height
;
673 static HRESULT WINAPI
GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode
*iface
,
674 WICPixelFormatGUID
*pPixelFormat
)
676 memcpy(pPixelFormat
, &GUID_WICPixelFormat8bppIndexed
, sizeof(GUID
));
681 static HRESULT WINAPI
GifFrameDecode_GetResolution(IWICBitmapFrameDecode
*iface
,
682 double *pDpiX
, double *pDpiY
)
684 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
685 const GifWord aspect_word
= This
->parent
->gif
->SAspectRatio
;
686 const double aspect
= (aspect_word
> 0) ? ((aspect_word
+ 15.0) / 64.0) : 1.0;
687 TRACE("(%p,%p,%p)\n", iface
, pDpiX
, pDpiY
);
689 *pDpiX
= 96.0 / aspect
;
695 static void copy_palette(ColorMapObject
*cm
, Extensions
*extensions
, int count
, WICColor
*colors
)
701 for (i
= 0; i
< count
; i
++)
703 colors
[i
] = 0xff000000 | /* alpha */
704 cm
->Colors
[i
].Red
<< 16 |
705 cm
->Colors
[i
].Green
<< 8 |
711 colors
[0] = 0xff000000;
712 colors
[1] = 0xffffffff;
713 for (i
= 2; i
< count
; i
++)
714 colors
[i
] = 0xff000000;
717 /* look for the transparent color extension */
718 for (i
= 0; i
< extensions
->ExtensionBlockCount
; i
++)
720 ExtensionBlock
*eb
= extensions
->ExtensionBlocks
+ i
;
721 if (eb
->Function
== GRAPHICS_EXT_FUNC_CODE
&&
722 eb
->ByteCount
== 8 && eb
->Bytes
[3] & 1)
724 int trans
= (unsigned char)eb
->Bytes
[6];
725 colors
[trans
] &= 0xffffff; /* set alpha to 0 */
731 static HRESULT WINAPI
GifFrameDecode_CopyPalette(IWICBitmapFrameDecode
*iface
,
732 IWICPalette
*pIPalette
)
734 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
735 WICColor colors
[256];
736 ColorMapObject
*cm
= This
->frame
->ImageDesc
.ColorMap
;
739 TRACE("(%p,%p)\n", iface
, pIPalette
);
742 count
= cm
->ColorCount
;
745 cm
= This
->parent
->gif
->SColorMap
;
746 count
= This
->parent
->gif
->SColorTableSize
;
751 ERR("GIF contains %i colors???\n", count
);
755 copy_palette(cm
, &This
->frame
->Extensions
, count
, colors
);
757 return IWICPalette_InitializeCustom(pIPalette
, colors
, count
);
760 static HRESULT
copy_interlaced_pixels(const BYTE
*srcbuffer
,
761 UINT srcwidth
, UINT srcheight
, INT srcstride
, const WICRect
*rc
,
762 UINT dststride
, UINT dstbuffersize
, BYTE
*dstbuffer
)
764 UINT row_offset
; /* number of bytes into the source rows where the data starts */
774 rect
.Width
= srcwidth
;
775 rect
.Height
= srcheight
;
780 if (rc
->X
< 0 || rc
->Y
< 0 || rc
->X
+rc
->Width
> srcwidth
|| rc
->Y
+rc
->Height
> srcheight
)
784 if (dststride
< rc
->Width
)
787 if ((dststride
* rc
->Height
) > dstbuffersize
)
793 for (y
=rc
->Y
; y
-rc
->Y
< rc
->Height
; y
++)
796 src
= srcbuffer
+ srcstride
* (y
/8);
798 src
= srcbuffer
+ srcstride
* ((srcheight
+7)/8 + y
/8);
800 src
= srcbuffer
+ srcstride
* ((srcheight
+3)/4 + y
/4);
802 src
= srcbuffer
+ srcstride
* ((srcheight
+1)/2 + y
/2);
804 memcpy(dst
, src
, rc
->Width
);
810 static HRESULT WINAPI
GifFrameDecode_CopyPixels(IWICBitmapFrameDecode
*iface
,
811 const WICRect
*prc
, UINT cbStride
, UINT cbBufferSize
, BYTE
*pbBuffer
)
813 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
814 TRACE("(%p,%s,%u,%u,%p)\n", iface
, debug_wic_rect(prc
), cbStride
, cbBufferSize
, pbBuffer
);
816 if (This
->frame
->ImageDesc
.Interlace
)
818 return copy_interlaced_pixels(This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
819 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
820 prc
, cbStride
, cbBufferSize
, pbBuffer
);
824 return copy_pixels(8, This
->frame
->RasterBits
, This
->frame
->ImageDesc
.Width
,
825 This
->frame
->ImageDesc
.Height
, This
->frame
->ImageDesc
.Width
,
826 prc
, cbStride
, cbBufferSize
, pbBuffer
);
830 static HRESULT WINAPI
GifFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode
*iface
,
831 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
833 GifFrameDecode
*This
= impl_from_IWICBitmapFrameDecode(iface
);
835 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
837 if (!ppIMetadataQueryReader
)
840 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
843 static HRESULT WINAPI
GifFrameDecode_GetColorContexts(IWICBitmapFrameDecode
*iface
,
844 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
846 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
847 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
850 static HRESULT WINAPI
GifFrameDecode_GetThumbnail(IWICBitmapFrameDecode
*iface
,
851 IWICBitmapSource
**ppIThumbnail
)
853 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
854 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
857 static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl
= {
858 GifFrameDecode_QueryInterface
,
859 GifFrameDecode_AddRef
,
860 GifFrameDecode_Release
,
861 GifFrameDecode_GetSize
,
862 GifFrameDecode_GetPixelFormat
,
863 GifFrameDecode_GetResolution
,
864 GifFrameDecode_CopyPalette
,
865 GifFrameDecode_CopyPixels
,
866 GifFrameDecode_GetMetadataQueryReader
,
867 GifFrameDecode_GetColorContexts
,
868 GifFrameDecode_GetThumbnail
871 static HRESULT WINAPI
GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
872 REFIID iid
, void **ppv
)
874 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
875 return IWICBitmapFrameDecode_QueryInterface(&This
->IWICBitmapFrameDecode_iface
, iid
, ppv
);
878 static ULONG WINAPI
GifFrameDecode_Block_AddRef(IWICMetadataBlockReader
*iface
)
880 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
881 return IWICBitmapFrameDecode_AddRef(&This
->IWICBitmapFrameDecode_iface
);
884 static ULONG WINAPI
GifFrameDecode_Block_Release(IWICMetadataBlockReader
*iface
)
886 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
887 return IWICBitmapFrameDecode_Release(&This
->IWICBitmapFrameDecode_iface
);
890 static HRESULT WINAPI
GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
893 TRACE("(%p,%p)\n", iface
, guid
);
895 if (!guid
) return E_INVALIDARG
;
897 *guid
= GUID_ContainerFormatGif
;
901 static HRESULT WINAPI
GifFrameDecode_Block_GetCount(IWICMetadataBlockReader
*iface
,
904 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
906 TRACE("%p,%p\n", iface
, count
);
908 if (!count
) return E_INVALIDARG
;
910 *count
= This
->frame
->Extensions
.ExtensionBlockCount
+ 1;
914 static HRESULT
create_IMD_metadata_reader(GifFrameDecode
*This
, IWICMetadataReader
**reader
)
917 IWICMetadataReader
*metadata_reader
;
918 IWICPersistStream
*persist
;
920 struct image_descriptor IMD_data
;
922 /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
924 hr
= IMDReader_CreateInstance(&IID_IWICMetadataReader
, (void **)&metadata_reader
);
925 if (FAILED(hr
)) return hr
;
927 hr
= IWICMetadataReader_QueryInterface(metadata_reader
, &IID_IWICPersistStream
, (void **)&persist
);
930 IWICMetadataReader_Release(metadata_reader
);
934 /* recreate IMD structure from GIF decoder data */
935 IMD_data
.left
= This
->frame
->ImageDesc
.Left
;
936 IMD_data
.top
= This
->frame
->ImageDesc
.Top
;
937 IMD_data
.width
= This
->frame
->ImageDesc
.Width
;
938 IMD_data
.height
= This
->frame
->ImageDesc
.Height
;
941 IMD_data
.packed
|= This
->frame
->ImageDesc
.Interlace
? (1 << 6) : 0;
942 if (This
->frame
->ImageDesc
.ColorMap
)
944 /* local_color_table_flag */
945 IMD_data
.packed
|= 1 << 7;
946 /* local_color_table_size */
947 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->BitsPerPixel
- 1;
949 IMD_data
.packed
|= This
->frame
->ImageDesc
.ColorMap
->SortFlag
? 0x20 : 0;
952 stream
= create_stream(&IMD_data
, sizeof(IMD_data
));
953 IWICPersistStream_LoadEx(persist
, stream
, NULL
, WICPersistOptionDefault
);
954 IStream_Release(stream
);
956 IWICPersistStream_Release(persist
);
958 *reader
= metadata_reader
;
962 static HRESULT WINAPI
GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
963 UINT index
, IWICMetadataReader
**reader
)
965 GifFrameDecode
*This
= frame_from_IWICMetadataBlockReader(iface
);
966 class_constructor constructor
;
971 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
973 if (!reader
) return E_INVALIDARG
;
976 return create_IMD_metadata_reader(This
, reader
);
978 if (index
>= This
->frame
->Extensions
.ExtensionBlockCount
+ 1)
981 ext
= This
->frame
->Extensions
.ExtensionBlocks
+ index
- 1;
982 if (ext
->Function
== GRAPHICS_EXT_FUNC_CODE
)
984 constructor
= GCEReader_CreateInstance
;
985 data
= ext
->Bytes
+ 3;
986 data_size
= ext
->ByteCount
- 4;
988 else if (ext
->Function
== COMMENT_EXT_FUNC_CODE
)
990 constructor
= GifCommentReader_CreateInstance
;
992 data_size
= ext
->ByteCount
;
996 constructor
= UnknownMetadataReader_CreateInstance
;
998 data_size
= ext
->ByteCount
;
1001 return create_metadata_reader(data
, data_size
, constructor
, reader
);
1004 static HRESULT WINAPI
GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1005 IEnumUnknown
**enumerator
)
1007 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1011 static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl
=
1013 GifFrameDecode_Block_QueryInterface
,
1014 GifFrameDecode_Block_AddRef
,
1015 GifFrameDecode_Block_Release
,
1016 GifFrameDecode_Block_GetContainerFormat
,
1017 GifFrameDecode_Block_GetCount
,
1018 GifFrameDecode_Block_GetReaderByIndex
,
1019 GifFrameDecode_Block_GetEnumerator
1022 static HRESULT WINAPI
GifDecoder_QueryInterface(IWICBitmapDecoder
*iface
, REFIID iid
,
1025 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1026 TRACE("(%p,%s,%p)\n", iface
, debugstr_guid(iid
), ppv
);
1028 if (!ppv
) return E_INVALIDARG
;
1030 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1031 IsEqualIID(&IID_IWICBitmapDecoder
, iid
))
1033 *ppv
= &This
->IWICBitmapDecoder_iface
;
1035 else if (IsEqualIID(&IID_IWICMetadataBlockReader
, iid
))
1037 *ppv
= &This
->IWICMetadataBlockReader_iface
;
1042 return E_NOINTERFACE
;
1045 IUnknown_AddRef((IUnknown
*)*ppv
);
1049 static ULONG WINAPI
GifDecoder_AddRef(IWICBitmapDecoder
*iface
)
1051 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1052 ULONG ref
= InterlockedIncrement(&This
->ref
);
1054 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1059 static ULONG WINAPI
GifDecoder_Release(IWICBitmapDecoder
*iface
)
1061 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1062 ULONG ref
= InterlockedDecrement(&This
->ref
);
1064 TRACE("(%p) refcount=%lu\n", iface
, ref
);
1070 IStream_Release(This
->stream
);
1071 DGifCloseFile(This
->gif
);
1073 This
->lock
.DebugInfo
->Spare
[0] = 0;
1074 DeleteCriticalSection(&This
->lock
);
1081 static HRESULT WINAPI
GifDecoder_QueryCapability(IWICBitmapDecoder
*iface
, IStream
*stream
,
1086 TRACE("(%p,%p,%p)\n", iface
, stream
, capability
);
1088 if (!stream
|| !capability
) return E_INVALIDARG
;
1090 hr
= IWICBitmapDecoder_Initialize(iface
, stream
, WICDecodeMetadataCacheOnDemand
);
1091 if (hr
!= S_OK
) return hr
;
1093 *capability
= WICBitmapDecoderCapabilityCanDecodeAllImages
|
1094 WICBitmapDecoderCapabilityCanDecodeSomeImages
|
1095 WICBitmapDecoderCapabilityCanEnumerateMetadata
;
1099 static int _gif_inputfunc(GifFileType
*gif
, GifByteType
*data
, int len
) {
1100 IStream
*stream
= gif
->UserData
;
1106 ERR("attempting to read file after initialization\n");
1110 hr
= IStream_Read(stream
, data
, len
, &bytesread
);
1111 if (FAILED(hr
)) bytesread
= 0;
1115 static HRESULT WINAPI
GifDecoder_Initialize(IWICBitmapDecoder
*iface
, IStream
*pIStream
,
1116 WICDecodeOptions cacheOptions
)
1118 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1122 TRACE("(%p,%p,%x)\n", iface
, pIStream
, cacheOptions
);
1124 EnterCriticalSection(&This
->lock
);
1126 if (This
->initialized
|| This
->gif
)
1128 WARN("already initialized\n");
1129 LeaveCriticalSection(&This
->lock
);
1130 return WINCODEC_ERR_WRONGSTATE
;
1133 /* seek to start of stream */
1135 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1137 /* read all data from the stream */
1138 This
->gif
= DGifOpen((void*)pIStream
, _gif_inputfunc
);
1141 LeaveCriticalSection(&This
->lock
);
1145 ret
= DGifSlurp(This
->gif
);
1146 if (ret
== GIF_ERROR
)
1148 LeaveCriticalSection(&This
->lock
);
1152 /* make sure we don't use the stream after this method returns */
1153 This
->gif
->UserData
= NULL
;
1156 IStream_Seek(pIStream
, seek
, STREAM_SEEK_SET
, NULL
);
1157 IStream_Read(pIStream
, This
->LSD_data
, sizeof(This
->LSD_data
), NULL
);
1159 This
->stream
= pIStream
;
1160 IStream_AddRef(This
->stream
);
1162 This
->initialized
= TRUE
;
1164 LeaveCriticalSection(&This
->lock
);
1169 static HRESULT WINAPI
GifDecoder_GetContainerFormat(IWICBitmapDecoder
*iface
,
1170 GUID
*pguidContainerFormat
)
1172 memcpy(pguidContainerFormat
, &GUID_ContainerFormatGif
, sizeof(GUID
));
1176 static HRESULT WINAPI
GifDecoder_GetDecoderInfo(IWICBitmapDecoder
*iface
,
1177 IWICBitmapDecoderInfo
**ppIDecoderInfo
)
1179 TRACE("(%p,%p)\n", iface
, ppIDecoderInfo
);
1181 return get_decoder_info(&CLSID_WICGifDecoder
, ppIDecoderInfo
);
1184 static HRESULT WINAPI
GifDecoder_CopyPalette(IWICBitmapDecoder
*iface
, IWICPalette
*palette
)
1186 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1187 WICColor colors
[256];
1191 TRACE("(%p,%p)\n", iface
, palette
);
1194 return WINCODEC_ERR_WRONGSTATE
;
1196 cm
= This
->gif
->SColorMap
;
1197 count
= This
->gif
->SColorTableSize
;
1201 ERR("GIF contains invalid number of colors: %d\n", count
);
1205 copy_palette(cm
, &This
->gif
->SavedImages
[This
->current_frame
].Extensions
, count
, colors
);
1207 return IWICPalette_InitializeCustom(palette
, colors
, count
);
1210 static HRESULT WINAPI
GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder
*iface
,
1211 IWICMetadataQueryReader
**ppIMetadataQueryReader
)
1213 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1215 TRACE("(%p,%p)\n", iface
, ppIMetadataQueryReader
);
1217 if (!ppIMetadataQueryReader
) return E_INVALIDARG
;
1219 return MetadataQueryReader_CreateInstance(&This
->IWICMetadataBlockReader_iface
, NULL
, ppIMetadataQueryReader
);
1222 static HRESULT WINAPI
GifDecoder_GetPreview(IWICBitmapDecoder
*iface
,
1223 IWICBitmapSource
**ppIBitmapSource
)
1225 TRACE("(%p,%p)\n", iface
, ppIBitmapSource
);
1226 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1229 static HRESULT WINAPI
GifDecoder_GetColorContexts(IWICBitmapDecoder
*iface
,
1230 UINT cCount
, IWICColorContext
**ppIColorContexts
, UINT
*pcActualCount
)
1232 TRACE("(%p,%u,%p,%p)\n", iface
, cCount
, ppIColorContexts
, pcActualCount
);
1233 return WINCODEC_ERR_UNSUPPORTEDOPERATION
;
1236 static HRESULT WINAPI
GifDecoder_GetThumbnail(IWICBitmapDecoder
*iface
,
1237 IWICBitmapSource
**ppIThumbnail
)
1239 TRACE("(%p,%p)\n", iface
, ppIThumbnail
);
1240 return WINCODEC_ERR_CODECNOTHUMBNAIL
;
1243 static HRESULT WINAPI
GifDecoder_GetFrameCount(IWICBitmapDecoder
*iface
,
1246 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1248 if (!pCount
) return E_INVALIDARG
;
1250 EnterCriticalSection(&This
->lock
);
1251 *pCount
= This
->gif
? This
->gif
->ImageCount
: 0;
1252 LeaveCriticalSection(&This
->lock
);
1254 TRACE("(%p) <-- %d\n", iface
, *pCount
);
1259 static HRESULT WINAPI
GifDecoder_GetFrame(IWICBitmapDecoder
*iface
,
1260 UINT index
, IWICBitmapFrameDecode
**ppIBitmapFrame
)
1262 GifDecoder
*This
= impl_from_IWICBitmapDecoder(iface
);
1263 GifFrameDecode
*result
;
1264 TRACE("(%p,%u,%p)\n", iface
, index
, ppIBitmapFrame
);
1266 if (!This
->initialized
) return WINCODEC_ERR_FRAMEMISSING
;
1268 if (index
>= This
->gif
->ImageCount
) return E_INVALIDARG
;
1270 result
= malloc(sizeof(GifFrameDecode
));
1271 if (!result
) return E_OUTOFMEMORY
;
1273 result
->IWICBitmapFrameDecode_iface
.lpVtbl
= &GifFrameDecode_Vtbl
;
1274 result
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifFrameDecode_BlockVtbl
;
1276 result
->frame
= &This
->gif
->SavedImages
[index
];
1277 IWICBitmapDecoder_AddRef(iface
);
1278 result
->parent
= This
;
1279 This
->current_frame
= index
;
1281 *ppIBitmapFrame
= &result
->IWICBitmapFrameDecode_iface
;
1286 static const IWICBitmapDecoderVtbl GifDecoder_Vtbl
= {
1287 GifDecoder_QueryInterface
,
1290 GifDecoder_QueryCapability
,
1291 GifDecoder_Initialize
,
1292 GifDecoder_GetContainerFormat
,
1293 GifDecoder_GetDecoderInfo
,
1294 GifDecoder_CopyPalette
,
1295 GifDecoder_GetMetadataQueryReader
,
1296 GifDecoder_GetPreview
,
1297 GifDecoder_GetColorContexts
,
1298 GifDecoder_GetThumbnail
,
1299 GifDecoder_GetFrameCount
,
1303 static HRESULT WINAPI
GifDecoder_Block_QueryInterface(IWICMetadataBlockReader
*iface
,
1304 REFIID iid
, void **ppv
)
1306 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1307 return IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1310 static ULONG WINAPI
GifDecoder_Block_AddRef(IWICMetadataBlockReader
*iface
)
1312 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1313 return IWICBitmapDecoder_AddRef(&This
->IWICBitmapDecoder_iface
);
1316 static ULONG WINAPI
GifDecoder_Block_Release(IWICMetadataBlockReader
*iface
)
1318 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1319 return IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1322 static HRESULT WINAPI
GifDecoder_Block_GetContainerFormat(IWICMetadataBlockReader
*iface
,
1325 TRACE("(%p,%p)\n", iface
, guid
);
1327 if (!guid
) return E_INVALIDARG
;
1329 *guid
= GUID_ContainerFormatGif
;
1333 static HRESULT WINAPI
GifDecoder_Block_GetCount(IWICMetadataBlockReader
*iface
,
1336 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1338 TRACE("%p,%p\n", iface
, count
);
1340 if (!count
) return E_INVALIDARG
;
1342 *count
= This
->gif
->Extensions
.ExtensionBlockCount
+ 1;
1346 static HRESULT WINAPI
GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader
*iface
,
1347 UINT index
, IWICMetadataReader
**reader
)
1349 GifDecoder
*This
= impl_from_IWICMetadataBlockReader(iface
);
1352 TRACE("(%p,%u,%p)\n", iface
, index
, reader
);
1354 if (!reader
) return E_INVALIDARG
;
1357 return create_metadata_reader(This
->LSD_data
, sizeof(This
->LSD_data
),
1358 LSDReader_CreateInstance
, reader
);
1360 for (i
= 0; i
< This
->gif
->Extensions
.ExtensionBlockCount
; i
++)
1362 class_constructor constructor
;
1364 if (index
!= i
+ 1) continue;
1366 if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== APPLICATION_EXT_FUNC_CODE
)
1367 constructor
= APEReader_CreateInstance
;
1368 else if (This
->gif
->Extensions
.ExtensionBlocks
[i
].Function
== COMMENT_EXT_FUNC_CODE
)
1369 constructor
= GifCommentReader_CreateInstance
;
1371 constructor
= UnknownMetadataReader_CreateInstance
;
1373 return create_metadata_reader(This
->gif
->Extensions
.ExtensionBlocks
[i
].Bytes
,
1374 This
->gif
->Extensions
.ExtensionBlocks
[i
].ByteCount
,
1375 constructor
, reader
);
1378 return E_INVALIDARG
;
1381 static HRESULT WINAPI
GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader
*iface
,
1382 IEnumUnknown
**enumerator
)
1384 FIXME("(%p,%p): stub\n", iface
, enumerator
);
1388 static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl
=
1390 GifDecoder_Block_QueryInterface
,
1391 GifDecoder_Block_AddRef
,
1392 GifDecoder_Block_Release
,
1393 GifDecoder_Block_GetContainerFormat
,
1394 GifDecoder_Block_GetCount
,
1395 GifDecoder_Block_GetReaderByIndex
,
1396 GifDecoder_Block_GetEnumerator
1399 HRESULT
GifDecoder_CreateInstance(REFIID iid
, void** ppv
)
1404 TRACE("(%s,%p)\n", debugstr_guid(iid
), ppv
);
1408 This
= malloc(sizeof(GifDecoder
));
1409 if (!This
) return E_OUTOFMEMORY
;
1411 This
->IWICBitmapDecoder_iface
.lpVtbl
= &GifDecoder_Vtbl
;
1412 This
->IWICMetadataBlockReader_iface
.lpVtbl
= &GifDecoder_BlockVtbl
;
1413 This
->stream
= NULL
;
1415 This
->initialized
= FALSE
;
1417 This
->current_frame
= 0;
1418 InitializeCriticalSection(&This
->lock
);
1419 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifDecoder.lock");
1421 ret
= IWICBitmapDecoder_QueryInterface(&This
->IWICBitmapDecoder_iface
, iid
, ppv
);
1422 IWICBitmapDecoder_Release(&This
->IWICBitmapDecoder_iface
);
1427 typedef struct GifEncoder
1429 IWICBitmapEncoder IWICBitmapEncoder_iface
;
1432 CRITICAL_SECTION lock
;
1433 BOOL initialized
, info_written
, committed
;
1435 WICColor palette
[256];
1439 static inline GifEncoder
*impl_from_IWICBitmapEncoder(IWICBitmapEncoder
*iface
)
1441 return CONTAINING_RECORD(iface
, GifEncoder
, IWICBitmapEncoder_iface
);
1444 typedef struct GifFrameEncode
1446 IWICBitmapFrameEncode IWICBitmapFrameEncode_iface
;
1447 IWICMetadataBlockWriter IWICMetadataBlockWriter_iface
;
1449 GifEncoder
*encoder
;
1450 BOOL initialized
, interlace
, committed
;
1451 UINT width
, height
, lines
;
1453 WICColor palette
[256];
1458 static inline GifFrameEncode
*impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode
*iface
)
1460 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICBitmapFrameEncode_iface
);
1463 static inline GifFrameEncode
*impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter
*iface
)
1465 return CONTAINING_RECORD(iface
, GifFrameEncode
, IWICMetadataBlockWriter_iface
);
1468 static HRESULT WINAPI
GifFrameEncode_QueryInterface(IWICBitmapFrameEncode
*iface
, REFIID iid
, void **ppv
)
1470 GifFrameEncode
*encoder
= impl_from_IWICBitmapFrameEncode(iface
);
1472 TRACE("%p,%s,%p\n", iface
, debugstr_guid(iid
), ppv
);
1474 if (!ppv
) return E_INVALIDARG
;
1476 if (IsEqualIID(&IID_IUnknown
, iid
) ||
1477 IsEqualIID(&IID_IWICBitmapFrameEncode
, iid
))
1481 else if (IsEqualIID(&IID_IWICMetadataBlockWriter
, iid
))
1483 *ppv
= &encoder
->IWICMetadataBlockWriter_iface
;
1488 return E_NOINTERFACE
;
1491 IUnknown_AddRef((IUnknown
*)*ppv
);
1495 static ULONG WINAPI
GifFrameEncode_AddRef(IWICBitmapFrameEncode
*iface
)
1497 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1498 ULONG ref
= InterlockedIncrement(&This
->ref
);
1500 TRACE("%p -> %lu\n", iface
, ref
);
1504 static ULONG WINAPI
GifFrameEncode_Release(IWICBitmapFrameEncode
*iface
)
1506 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1507 ULONG ref
= InterlockedDecrement(&This
->ref
);
1509 TRACE("%p -> %lu\n", iface
, ref
);
1513 IWICBitmapEncoder_Release(&This
->encoder
->IWICBitmapEncoder_iface
);
1514 free(This
->image_data
);
1521 static HRESULT WINAPI
GifFrameEncode_Initialize(IWICBitmapFrameEncode
*iface
, IPropertyBag2
*options
)
1523 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1526 TRACE("%p,%p\n", iface
, options
);
1528 EnterCriticalSection(&This
->encoder
->lock
);
1530 if (!This
->initialized
)
1532 This
->initialized
= TRUE
;
1536 hr
= WINCODEC_ERR_WRONGSTATE
;
1538 LeaveCriticalSection(&This
->encoder
->lock
);
1543 static HRESULT WINAPI
GifFrameEncode_SetSize(IWICBitmapFrameEncode
*iface
, UINT width
, UINT height
)
1545 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1548 TRACE("%p,%u,%u\n", iface
, width
, height
);
1550 if (!width
|| !height
) return E_INVALIDARG
;
1552 EnterCriticalSection(&This
->encoder
->lock
);
1554 if (This
->initialized
)
1556 free(This
->image_data
);
1558 This
->image_data
= malloc(width
* height
);
1559 if (This
->image_data
)
1561 This
->width
= width
;
1562 This
->height
= height
;
1569 hr
= WINCODEC_ERR_WRONGSTATE
;
1571 LeaveCriticalSection(&This
->encoder
->lock
);
1576 static HRESULT WINAPI
GifFrameEncode_SetResolution(IWICBitmapFrameEncode
*iface
, double xres
, double yres
)
1578 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1581 TRACE("%p,%f,%f\n", iface
, xres
, yres
);
1583 EnterCriticalSection(&This
->encoder
->lock
);
1585 if (This
->initialized
)
1592 hr
= WINCODEC_ERR_WRONGSTATE
;
1594 LeaveCriticalSection(&This
->encoder
->lock
);
1599 static HRESULT WINAPI
GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode
*iface
, WICPixelFormatGUID
*format
)
1601 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1604 TRACE("%p,%s\n", iface
, debugstr_guid(format
));
1606 if (!format
) return E_INVALIDARG
;
1608 EnterCriticalSection(&This
->encoder
->lock
);
1610 if (This
->initialized
)
1612 *format
= GUID_WICPixelFormat8bppIndexed
;
1616 hr
= WINCODEC_ERR_WRONGSTATE
;
1618 LeaveCriticalSection(&This
->encoder
->lock
);
1623 static HRESULT WINAPI
GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode
*iface
, UINT count
, IWICColorContext
**context
)
1625 FIXME("%p,%u,%p: stub\n", iface
, count
, context
);
1629 static HRESULT WINAPI
GifFrameEncode_SetPalette(IWICBitmapFrameEncode
*iface
, IWICPalette
*palette
)
1631 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1634 TRACE("%p,%p\n", iface
, palette
);
1636 if (!palette
) return E_INVALIDARG
;
1638 EnterCriticalSection(&This
->encoder
->lock
);
1640 if (This
->initialized
)
1641 hr
= IWICPalette_GetColors(palette
, 256, This
->palette
, &This
->colors
);
1643 hr
= WINCODEC_ERR_NOTINITIALIZED
;
1645 LeaveCriticalSection(&This
->encoder
->lock
);
1649 static HRESULT WINAPI
GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*thumbnail
)
1651 FIXME("%p,%p: stub\n", iface
, thumbnail
);
1655 static HRESULT WINAPI
GifFrameEncode_WritePixels(IWICBitmapFrameEncode
*iface
, UINT lines
, UINT stride
, UINT size
, BYTE
*pixels
)
1657 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1660 TRACE("%p,%u,%u,%u,%p\n", iface
, lines
, stride
, size
, pixels
);
1662 if (!pixels
) return E_INVALIDARG
;
1664 EnterCriticalSection(&This
->encoder
->lock
);
1666 if (This
->initialized
&& This
->image_data
)
1668 if (This
->lines
+ lines
<= This
->height
)
1674 dst
= This
->image_data
+ This
->lines
* This
->width
;
1676 for (i
= 0; i
< lines
; i
++)
1678 memcpy(dst
, src
, This
->width
);
1683 This
->lines
+= lines
;
1690 hr
= WINCODEC_ERR_WRONGSTATE
;
1692 LeaveCriticalSection(&This
->encoder
->lock
);
1696 static HRESULT WINAPI
GifFrameEncode_WriteSource(IWICBitmapFrameEncode
*iface
, IWICBitmapSource
*source
, WICRect
*rc
)
1698 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1701 TRACE("%p,%p,%p\n", iface
, source
, rc
);
1703 if (!source
) return E_INVALIDARG
;
1705 EnterCriticalSection(&This
->encoder
->lock
);
1707 if (This
->initialized
)
1709 const GUID
*format
= &GUID_WICPixelFormat8bppIndexed
;
1711 hr
= configure_write_source(iface
, source
, rc
, format
,
1712 This
->width
, This
->height
, This
->xres
, This
->yres
);
1714 hr
= write_source(iface
, source
, rc
, format
, 8, !This
->colors
, This
->width
, This
->height
);
1717 hr
= WINCODEC_ERR_WRONGSTATE
;
1719 LeaveCriticalSection(&This
->encoder
->lock
);
1723 #define LZW_DICT_SIZE (1 << 12)
1727 short prefix
[LZW_DICT_SIZE
];
1728 unsigned char suffix
[LZW_DICT_SIZE
];
1733 struct lzw_dict dict
;
1734 short init_code_bits
, code_bits
, next_code
, clear_code
, eof_code
;
1737 int (*user_write_data
)(void *user_ptr
, void *data
, int length
);
1747 struct output_stream
1757 static int lzw_output_code(struct lzw_state
*state
, short code
)
1759 state
->bits_buf
|= code
<< state
->bits_count
;
1760 state
->bits_count
+= state
->code_bits
;
1762 while (state
->bits_count
>= 8)
1764 unsigned char byte
= (unsigned char)state
->bits_buf
;
1765 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1767 state
->bits_buf
>>= 8;
1768 state
->bits_count
-= 8;
1774 static inline int lzw_output_clear_code(struct lzw_state
*state
)
1776 return lzw_output_code(state
, state
->clear_code
);
1779 static inline int lzw_output_eof_code(struct lzw_state
*state
)
1781 return lzw_output_code(state
, state
->eof_code
);
1784 static int lzw_flush_bits(struct lzw_state
*state
)
1788 while (state
->bits_count
>= 8)
1790 byte
= (unsigned char)state
->bits_buf
;
1791 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1793 state
->bits_buf
>>= 8;
1794 state
->bits_count
-= 8;
1797 if (state
->bits_count
)
1799 static const char mask
[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f };
1801 byte
= (unsigned char)state
->bits_buf
& mask
[state
->bits_count
];
1802 if (state
->user_write_data(state
->user_ptr
, &byte
, 1) != 1)
1806 state
->bits_buf
= 0;
1807 state
->bits_count
= 0;
1812 static void lzw_dict_reset(struct lzw_state
*state
)
1816 state
->code_bits
= state
->init_code_bits
+ 1;
1817 state
->next_code
= (1 << state
->init_code_bits
) + 2;
1819 for(i
= 0; i
< LZW_DICT_SIZE
; i
++)
1821 state
->dict
.prefix
[i
] = 1 << 12; /* impossible LZW code value */
1822 state
->dict
.suffix
[i
] = 0;
1826 static void lzw_state_init(struct lzw_state
*state
, short init_code_bits
, void *user_write_data
, void *user_ptr
)
1828 state
->init_code_bits
= init_code_bits
;
1829 state
->clear_code
= 1 << init_code_bits
;
1830 state
->eof_code
= state
->clear_code
+ 1;
1831 state
->bits_buf
= 0;
1832 state
->bits_count
= 0;
1833 state
->user_write_data
= user_write_data
;
1834 state
->user_ptr
= user_ptr
;
1836 lzw_dict_reset(state
);
1839 static int lzw_dict_add(struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1841 if (state
->next_code
< LZW_DICT_SIZE
)
1843 state
->dict
.prefix
[state
->next_code
] = prefix
;
1844 state
->dict
.suffix
[state
->next_code
] = suffix
;
1846 if ((state
->next_code
& (state
->next_code
- 1)) == 0)
1850 return state
->next_code
;
1856 static short lzw_dict_lookup(const struct lzw_state
*state
, short prefix
, unsigned char suffix
)
1860 for (i
= 0; i
< state
->next_code
; i
++)
1862 if (state
->dict
.prefix
[i
] == prefix
&& state
->dict
.suffix
[i
] == suffix
)
1869 static inline int write_byte(struct output_stream
*out
, char byte
)
1871 if (out
->gif_block
.len
== 255)
1873 if (IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
), NULL
) != S_OK
)
1876 out
->gif_block
.len
= 0;
1879 out
->gif_block
.data
[out
->gif_block
.len
++] = byte
;
1884 static int write_data(void *user_ptr
, void *user_data
, int length
)
1886 unsigned char *data
= user_data
;
1887 struct output_stream
*out
= user_ptr
;
1892 if (!write_byte(out
, *data
++)) return 0;
1898 static int flush_output_data(void *user_ptr
)
1900 struct output_stream
*out
= user_ptr
;
1902 if (out
->gif_block
.len
)
1904 if (IStream_Write(out
->out
, &out
->gif_block
, out
->gif_block
.len
+ sizeof(out
->gif_block
.len
), NULL
) != S_OK
)
1908 /* write GIF block terminator */
1909 out
->gif_block
.len
= 0;
1910 return IStream_Write(out
->out
, &out
->gif_block
, sizeof(out
->gif_block
.len
), NULL
) == S_OK
;
1913 static inline int read_byte(struct input_stream
*in
, unsigned char *byte
)
1925 static HRESULT
gif_compress(IStream
*out_stream
, const BYTE
*in_data
, ULONG in_size
)
1927 struct input_stream in
;
1928 struct output_stream out
;
1929 struct lzw_state state
;
1930 short init_code_bits
, prefix
, code
;
1931 unsigned char suffix
;
1936 out
.gif_block
.len
= 0;
1937 out
.out
= out_stream
;
1939 init_code_bits
= suffix
= 8;
1940 if (IStream_Write(out
.out
, &suffix
, sizeof(suffix
), NULL
) != S_OK
)
1943 lzw_state_init(&state
, init_code_bits
, write_data
, &out
);
1945 if (!lzw_output_clear_code(&state
))
1948 if (read_byte(&in
, &suffix
))
1952 while (read_byte(&in
, &suffix
))
1954 code
= lzw_dict_lookup(&state
, prefix
, suffix
);
1957 if (!lzw_output_code(&state
, prefix
))
1960 if (lzw_dict_add(&state
, prefix
, suffix
) == -1)
1962 if (!lzw_output_clear_code(&state
))
1964 lzw_dict_reset(&state
);
1973 if (!lzw_output_code(&state
, prefix
))
1975 if (!lzw_output_eof_code(&state
))
1977 if (!lzw_flush_bits(&state
))
1981 return flush_output_data(&out
) ? S_OK
: E_FAIL
;
1984 static HRESULT WINAPI
GifFrameEncode_Commit(IWICBitmapFrameEncode
*iface
)
1986 GifFrameEncode
*This
= impl_from_IWICBitmapFrameEncode(iface
);
1989 TRACE("%p\n", iface
);
1991 EnterCriticalSection(&This
->encoder
->lock
);
1993 if (This
->image_data
&& This
->lines
== This
->height
&& !This
->committed
)
1995 BYTE gif_palette
[256][3];
1999 if (!This
->encoder
->info_written
)
2001 struct logical_screen_descriptor lsd
;
2003 /* Logical Screen Descriptor */
2004 memcpy(lsd
.signature
, "GIF89a", 6);
2005 lsd
.width
= This
->width
;
2006 lsd
.height
= This
->height
;
2008 if (This
->encoder
->colors
)
2009 lsd
.packed
|= 0x80; /* global color table flag */
2010 lsd
.packed
|= 0x07 << 4; /* color resolution */
2011 lsd
.packed
|= 0x07; /* global color table size */
2012 lsd
.background_color_index
= 0; /* FIXME */
2013 lsd
.pixel_aspect_ratio
= 0;
2014 hr
= IStream_Write(This
->encoder
->stream
, &lsd
, sizeof(lsd
), NULL
);
2015 if (hr
== S_OK
&& This
->encoder
->colors
)
2019 /* Global Color Table */
2020 memset(gif_palette
, 0, sizeof(gif_palette
));
2021 for (i
= 0; i
< This
->encoder
->colors
; i
++)
2023 gif_palette
[i
][0] = (This
->encoder
->palette
[i
] >> 16) & 0xff;
2024 gif_palette
[i
][1] = (This
->encoder
->palette
[i
] >> 8) & 0xff;
2025 gif_palette
[i
][2] = This
->encoder
->palette
[i
] & 0xff;
2027 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2030 /* FIXME: write GCE, APE, etc. GIF extensions */
2033 This
->encoder
->info_written
= TRUE
;
2038 char image_separator
= 0x2c;
2040 hr
= IStream_Write(This
->encoder
->stream
, &image_separator
, sizeof(image_separator
), NULL
);
2043 struct image_descriptor imd
;
2045 /* Image Descriptor */
2048 imd
.width
= This
->width
;
2049 imd
.height
= This
->height
;
2053 imd
.packed
|= 0x80; /* local color table flag */
2054 imd
.packed
|= 0x07; /* local color table size */
2056 /* FIXME: interlace flag */
2057 hr
= IStream_Write(This
->encoder
->stream
, &imd
, sizeof(imd
), NULL
);
2058 if (hr
== S_OK
&& This
->colors
)
2062 /* Local Color Table */
2063 memset(gif_palette
, 0, sizeof(gif_palette
));
2064 for (i
= 0; i
< This
->colors
; i
++)
2066 gif_palette
[i
][0] = (This
->palette
[i
] >> 16) & 0xff;
2067 gif_palette
[i
][1] = (This
->palette
[i
] >> 8) & 0xff;
2068 gif_palette
[i
][2] = This
->palette
[i
] & 0xff;
2070 hr
= IStream_Write(This
->encoder
->stream
, gif_palette
, sizeof(gif_palette
), NULL
);
2074 hr
= gif_compress(This
->encoder
->stream
, This
->image_data
, This
->width
* This
->height
);
2076 This
->committed
= TRUE
;
2083 hr
= WINCODEC_ERR_WRONGSTATE
;
2085 LeaveCriticalSection(&This
->encoder
->lock
);
2089 static HRESULT WINAPI
GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode
*iface
, IWICMetadataQueryWriter
**writer
)
2091 GifFrameEncode
*encode
= impl_from_IWICBitmapFrameEncode(iface
);
2093 TRACE("iface, %p, writer %p.\n", iface
, writer
);
2096 return E_INVALIDARG
;
2098 if (!encode
->initialized
)
2099 return WINCODEC_ERR_NOTINITIALIZED
;
2101 return MetadataQueryWriter_CreateInstance(&encode
->IWICMetadataBlockWriter_iface
, NULL
, 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 -> %lu\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 -> %lu\n", iface
, ref
);
2158 if (This
->stream
) IStream_Release(This
->stream
);
2159 This
->lock
.DebugInfo
->Spare
[0] = 0;
2160 DeleteCriticalSection(&This
->lock
);
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
GifEncoderFrame_Block_QueryInterface(IWICMetadataBlockWriter
*iface
, REFIID iid
, void **ppv
)
2259 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2261 return IWICBitmapFrameEncode_QueryInterface(&frame_encoder
->IWICBitmapFrameEncode_iface
, iid
, ppv
);
2264 static ULONG WINAPI
GifEncoderFrame_Block_AddRef(IWICMetadataBlockWriter
*iface
)
2266 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2268 return IWICBitmapFrameEncode_AddRef(&frame_encoder
->IWICBitmapFrameEncode_iface
);
2271 static ULONG WINAPI
GifEncoderFrame_Block_Release(IWICMetadataBlockWriter
*iface
)
2273 GifFrameEncode
*frame_encoder
= impl_from_IWICMetadataBlockWriter(iface
);
2275 return IWICBitmapFrameEncode_Release(&frame_encoder
->IWICBitmapFrameEncode_iface
);
2278 static HRESULT WINAPI
GifEncoderFrame_Block_GetContainerFormat(IWICMetadataBlockWriter
*iface
, GUID
*container_format
)
2280 FIXME("iface %p, container_format %p stub.\n", iface
, container_format
);
2285 static HRESULT WINAPI
GifEncoderFrame_Block_GetCount(IWICMetadataBlockWriter
*iface
, UINT
*count
)
2287 FIXME("iface %p, count %p stub.\n", iface
, count
);
2292 static HRESULT WINAPI
GifEncoderFrame_Block_GetReaderByIndex(IWICMetadataBlockWriter
*iface
,
2293 UINT index
, IWICMetadataReader
**metadata_reader
)
2295 FIXME("iface %p, index %d, metadata_reader %p stub.\n", iface
, index
, metadata_reader
);
2300 static HRESULT WINAPI
GifEncoderFrame_Block_GetEnumerator(IWICMetadataBlockWriter
*iface
, IEnumUnknown
**enum_metadata
)
2302 FIXME("iface %p, enum_metadata %p stub.\n", iface
, enum_metadata
);
2307 static HRESULT WINAPI
GifEncoderFrame_Block_InitializeFromBlockReader(IWICMetadataBlockWriter
*iface
,
2308 IWICMetadataBlockReader
*block_reader
)
2310 FIXME("iface %p, block_reader %p stub.\n", iface
, block_reader
);
2315 static HRESULT WINAPI
GifEncoderFrame_Block_GetWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
,
2316 IWICMetadataWriter
**metadata_writer
)
2318 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface
, index
, metadata_writer
);
2323 static HRESULT WINAPI
GifEncoderFrame_Block_AddWriter(IWICMetadataBlockWriter
*iface
, IWICMetadataWriter
*metadata_writer
)
2325 FIXME("iface %p, metadata_writer %p stub.\n", iface
, metadata_writer
);
2330 static HRESULT WINAPI
GifEncoderFrame_Block_SetWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
,
2331 IWICMetadataWriter
*metadata_writer
)
2333 FIXME("iface %p, index %u, metadata_writer %p stub.\n", iface
, index
, metadata_writer
);
2338 static HRESULT WINAPI
GifEncoderFrame_Block_RemoveWriterByIndex(IWICMetadataBlockWriter
*iface
, UINT index
)
2340 FIXME("iface %p, index %u stub.\n", iface
, index
);
2345 static const IWICMetadataBlockWriterVtbl GifFrameEncode_BlockVtbl
= {
2346 GifEncoderFrame_Block_QueryInterface
,
2347 GifEncoderFrame_Block_AddRef
,
2348 GifEncoderFrame_Block_Release
,
2349 GifEncoderFrame_Block_GetContainerFormat
,
2350 GifEncoderFrame_Block_GetCount
,
2351 GifEncoderFrame_Block_GetReaderByIndex
,
2352 GifEncoderFrame_Block_GetEnumerator
,
2353 GifEncoderFrame_Block_InitializeFromBlockReader
,
2354 GifEncoderFrame_Block_GetWriterByIndex
,
2355 GifEncoderFrame_Block_AddWriter
,
2356 GifEncoderFrame_Block_SetWriterByIndex
,
2357 GifEncoderFrame_Block_RemoveWriterByIndex
,
2360 static HRESULT WINAPI
GifEncoder_CreateNewFrame(IWICBitmapEncoder
*iface
, IWICBitmapFrameEncode
**frame
, IPropertyBag2
**options
)
2362 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2365 TRACE("%p,%p,%p\n", iface
, frame
, options
);
2367 if (!frame
) return E_INVALIDARG
;
2369 EnterCriticalSection(&This
->lock
);
2371 if (This
->initialized
&& !This
->committed
)
2373 GifFrameEncode
*ret
= malloc(sizeof(*ret
));
2378 ret
->IWICBitmapFrameEncode_iface
.lpVtbl
= &GifFrameEncode_Vtbl
;
2379 ret
->IWICMetadataBlockWriter_iface
.lpVtbl
= &GifFrameEncode_BlockVtbl
;
2382 ret
->encoder
= This
;
2383 ret
->initialized
= FALSE
;
2384 ret
->interlace
= FALSE
; /* FIXME: read from the properties */
2385 ret
->committed
= FALSE
;
2392 ret
->image_data
= NULL
;
2393 IWICBitmapEncoder_AddRef(iface
);
2394 *frame
= &ret
->IWICBitmapFrameEncode_iface
;
2400 hr
= CreatePropertyBag2(NULL
, 0, options
);
2403 IWICBitmapFrameEncode_Release(*frame
);
2412 hr
= WINCODEC_ERR_WRONGSTATE
;
2414 LeaveCriticalSection(&This
->lock
);
2420 static HRESULT WINAPI
GifEncoder_Commit(IWICBitmapEncoder
*iface
)
2422 GifEncoder
*This
= impl_from_IWICBitmapEncoder(iface
);
2425 TRACE("%p\n", iface
);
2427 EnterCriticalSection(&This
->lock
);
2429 if (This
->initialized
&& !This
->committed
)
2431 char gif_trailer
= 0x3b;
2433 /* FIXME: write text, comment GIF extensions */
2435 hr
= IStream_Write(This
->stream
, &gif_trailer
, sizeof(gif_trailer
), NULL
);
2437 This
->committed
= TRUE
;
2440 hr
= WINCODEC_ERR_WRONGSTATE
;
2442 LeaveCriticalSection(&This
->lock
);
2446 static HRESULT WINAPI
GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder
*iface
, IWICMetadataQueryWriter
**writer
)
2448 FIXME("%p,%p: stub\n", iface
, writer
);
2452 static const IWICBitmapEncoderVtbl GifEncoder_Vtbl
=
2454 GifEncoder_QueryInterface
,
2457 GifEncoder_Initialize
,
2458 GifEncoder_GetContainerFormat
,
2459 GifEncoder_GetEncoderInfo
,
2460 GifEncoder_SetColorContexts
,
2461 GifEncoder_SetPalette
,
2462 GifEncoder_SetThumbnail
,
2463 GifEncoder_SetPreview
,
2464 GifEncoder_CreateNewFrame
,
2466 GifEncoder_GetMetadataQueryWriter
2469 HRESULT
GifEncoder_CreateInstance(REFIID iid
, void **ppv
)
2474 TRACE("%s,%p\n", debugstr_guid(iid
), ppv
);
2478 This
= malloc(sizeof(*This
));
2479 if (!This
) return E_OUTOFMEMORY
;
2481 This
->IWICBitmapEncoder_iface
.lpVtbl
= &GifEncoder_Vtbl
;
2483 This
->stream
= NULL
;
2484 InitializeCriticalSection(&This
->lock
);
2485 This
->lock
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": GifEncoder.lock");
2486 This
->initialized
= FALSE
;
2487 This
->info_written
= FALSE
;
2488 This
->committed
= FALSE
;
2492 ret
= IWICBitmapEncoder_QueryInterface(&This
->IWICBitmapEncoder_iface
, iid
, ppv
);
2493 IWICBitmapEncoder_Release(&This
->IWICBitmapEncoder_iface
);