diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c index 66c56a8e37..62bdc6f74d 100644 --- a/dlls/windowscodecs/gifformat.c +++ b/dlls/windowscodecs/gifformat.c @@ -149,25 +149,27 @@ HRESULT LSDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv) return MetadataReader_Create(&LSDReader_Vtbl, pUnkOuter, iid, ppv); } +#include "pshpack1.h" +struct image_descriptor +{ + USHORT left; + USHORT top; + USHORT width; + USHORT height; + BYTE packed; + /* local_color_table_flag : 1; + * interlace_flag : 1; + * sort_flag : 1; + * reserved : 2; + * local_color_table_size : 3; + */ +}; +#include "poppack.h" + static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD options, MetadataItem **items, DWORD *count) { -#include "pshpack1.h" - struct image_descriptor - { - USHORT left; - USHORT top; - USHORT width; - USHORT height; - BYTE packed; - /* local_color_table_flag : 1; - * interlace_flag : 1; - * sort_flag : 1; - * reserved : 2; - * local_color_table_size : 3; - */ - } imd_data; -#include "poppack.h" + struct image_descriptor imd_data; HRESULT hr; ULONG bytesread, i; MetadataItem *result; @@ -353,6 +355,7 @@ typedef struct { typedef struct { IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + IWICMetadataBlockReader IWICMetadataBlockReader_iface; LONG ref; SavedImage *frame; GifDecoder *parent; @@ -373,6 +376,11 @@ static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDec return CONTAINING_RECORD(iface, GifFrameDecode, IWICBitmapFrameDecode_iface); } +static inline GifFrameDecode *frame_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) +{ + return CONTAINING_RECORD(iface, GifFrameDecode, IWICMetadataBlockReader_iface); +} + static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, void **ppv) { @@ -387,6 +395,10 @@ static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface { *ppv = &This->IWICBitmapFrameDecode_iface; } + else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) + { + *ppv = &This->IWICMetadataBlockReader_iface; + } else { *ppv = NULL; @@ -604,6 +616,125 @@ static const IWICBitmapFrameDecodeVtbl GifFrameDecode_Vtbl = { GifFrameDecode_GetThumbnail }; +static HRESULT WINAPI GifFrameDecode_Block_QueryInterface(IWICMetadataBlockReader *iface, + REFIID iid, void **ppv) +{ + GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); +} + +static ULONG WINAPI GifFrameDecode_Block_AddRef(IWICMetadataBlockReader *iface) +{ + GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); +} + +static ULONG WINAPI GifFrameDecode_Block_Release(IWICMetadataBlockReader *iface) +{ + GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); +} + +static HRESULT WINAPI GifFrameDecode_Block_GetContainerFormat(IWICMetadataBlockReader *iface, + GUID *guid) +{ + TRACE("(%p,%p)\n", iface, guid); + + if (!guid) return E_INVALIDARG; + + *guid = GUID_ContainerFormatGif; + return S_OK; +} + +static HRESULT WINAPI GifFrameDecode_Block_GetCount(IWICMetadataBlockReader *iface, + UINT *count) +{ + TRACE("%p,%p\n", iface, count); + + if (!count) return E_INVALIDARG; + + *count = 1; + return S_OK; +} + +static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataReader **reader) +{ + HRESULT hr; + IWICMetadataReader *metadata_reader; + IWICPersistStream *persist; + IStream *stream; + struct image_descriptor IMD_data; + + /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ + + hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER, + &IID_IWICMetadataReader, (void **)&metadata_reader); + if (FAILED(hr)) return hr; + + hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); + if (FAILED(hr)) + { + IWICMetadataReader_Release(metadata_reader); + return hr; + } + + /* recreate IMD structure from GIF decoder data */ + IMD_data.left = This->frame->ImageDesc.Left; + IMD_data.top = This->frame->ImageDesc.Top; + IMD_data.width = This->frame->ImageDesc.Width; + IMD_data.height = This->frame->ImageDesc.Height; + IMD_data.packed = 0; + /* interlace_flag */ + IMD_data.packed |= This->frame->ImageDesc.Interlace ? (1 << 6) : 0; + if (This->frame->ImageDesc.ColorMap) + { + /* local_color_table_flag */ + IMD_data.packed |= 1 << 7; + /* local_color_table_size */ + IMD_data.packed |= This->frame->ImageDesc.ColorMap->BitsPerPixel; + /* FIXME: sort_flag */ + } + + stream = create_stream(&IMD_data, sizeof(IMD_data)); + IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault); + IStream_Release(stream); + + IWICPersistStream_Release(persist); + + *reader = metadata_reader; + return S_OK; +} + +static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, + UINT index, IWICMetadataReader **reader) +{ + GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface); + + TRACE("(%p,%u,%p)\n", iface, index, reader); + + if (!reader || index != 0) return E_INVALIDARG; + + return create_IMD_metadata_reader(This, reader); +} + +static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, + IEnumUnknown **enumerator) +{ + FIXME("(%p,%p): stub\n", iface, enumerator); + return E_NOTIMPL; +} + +static const IWICMetadataBlockReaderVtbl GifFrameDecode_BlockVtbl = +{ + GifFrameDecode_Block_QueryInterface, + GifFrameDecode_Block_AddRef, + GifFrameDecode_Block_Release, + GifFrameDecode_Block_GetContainerFormat, + GifFrameDecode_Block_GetCount, + GifFrameDecode_Block_GetReaderByIndex, + GifFrameDecode_Block_GetEnumerator +}; + static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, void **ppv) { @@ -824,6 +955,7 @@ static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface, if (!result) return E_OUTOFMEMORY; result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl; + result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl; result->ref = 1; result->frame = &This->gif->SavedImages[index]; IWICBitmapDecoder_AddRef(iface); diff --git a/dlls/windowscodecs/tests/metadata.c b/dlls/windowscodecs/tests/metadata.c index 6bdecee352..39c5144c03 100644 --- a/dlls/windowscodecs/tests/metadata.c +++ b/dlls/windowscodecs/tests/metadata.c @@ -1088,7 +1088,6 @@ static void test_metadata_gif(void) ok(hr == S_OK, "GetFrame error %#x\n", hr); hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader); -todo_wine ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr); if (SUCCEEDED(hr)) @@ -1190,7 +1189,6 @@ todo_wine ok(hr == S_OK, "GetFrame error %#x\n", hr); hr = IWICBitmapFrameDecode_QueryInterface(frame, &IID_IWICMetadataBlockReader, (void **)&blockreader); -todo_wine ok(hr == S_OK || broken(hr == E_NOINTERFACE) /* before Win7 */, "QueryInterface error %#x\n", hr); if (SUCCEEDED(hr)) @@ -1208,6 +1206,7 @@ todo_wine hr = IWICMetadataBlockReader_GetCount(blockreader, &count); ok(hr == S_OK, "GetCount error %#x\n", hr); +todo_wine ok(count == 2, "expected 2, got %u\n", count); hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 0, &reader); @@ -1229,6 +1228,7 @@ todo_wine } hr = IWICMetadataBlockReader_GetReaderByIndex(blockreader, 1, &reader); +todo_wine ok(hr == S_OK, "GetReaderByIndex error %#x\n", hr); if (SUCCEEDED(hr))