From 9fdfcff1b4faf4aaebdcd4f65ae97fa3b7acb7c2 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Wed, 22 Jul 2015 00:45:26 +0000 Subject: [PATCH] [WINDOWSCODECS] Sync with Wine Staging 1.7.47. CORE-9924 svn path=/trunk/; revision=68543 --- reactos/dll/win32/windowscodecs/clsfactory.c | 14 +- reactos/dll/win32/windowscodecs/gifformat.c | 46 ++-- reactos/dll/win32/windowscodecs/icnsformat.c | 12 +- reactos/dll/win32/windowscodecs/imgfactory.c | 2 +- reactos/dll/win32/windowscodecs/info.c | 33 ++- .../dll/win32/windowscodecs/metadatahandler.c | 4 +- reactos/dll/win32/windowscodecs/pngformat.c | 205 +++++++++++++++++- reactos/dll/win32/windowscodecs/regsvr.c | 25 +++ reactos/dll/win32/windowscodecs/stream.c | 2 +- reactos/dll/win32/windowscodecs/tiffformat.c | 59 ++++- reactos/dll/win32/windowscodecs/ungif.c | 2 +- .../win32/windowscodecs/wincodecs_private.h | 4 + .../windowscodecs/windowscodecs_wincodec.idl | 7 + .../windowscodecs/windowscodecs_wincodec.rgs | 6 +- reactos/media/doc/README.WINE | 2 +- 15 files changed, 354 insertions(+), 69 deletions(-) diff --git a/reactos/dll/win32/windowscodecs/clsfactory.c b/reactos/dll/win32/windowscodecs/clsfactory.c index 9fb72726fc1..f114d2d51f5 100644 --- a/reactos/dll/win32/windowscodecs/clsfactory.c +++ b/reactos/dll/win32/windowscodecs/clsfactory.c @@ -22,7 +22,7 @@ extern HRESULT WINAPI WIC_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC typedef struct { REFCLSID classid; - HRESULT (*constructor)(REFIID,void**); + class_constructor constructor; } classinfo; static const classinfo wic_classes[] = { @@ -42,6 +42,7 @@ static const classinfo wic_classes[] = { {&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance}, {&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance}, {&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance}, + {&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance}, {&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance}, {&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance}, {&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance}, @@ -183,3 +184,14 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) TRACE("<-- %08X\n", ret); return ret; } + +HRESULT create_instance(CLSID *clsid, const IID *iid, void **ppv) +{ + int i; + + for (i=0; wic_classes[i].classid; i++) + if (IsEqualCLSID(wic_classes[i].classid, clsid)) + return wic_classes[i].constructor(iid, ppv); + + return CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, iid, ppv); +} diff --git a/reactos/dll/win32/windowscodecs/gifformat.c b/reactos/dll/win32/windowscodecs/gifformat.c index 20222d13c4b..1076813bd75 100644 --- a/reactos/dll/win32/windowscodecs/gifformat.c +++ b/reactos/dll/win32/windowscodecs/gifformat.c @@ -60,7 +60,7 @@ static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD opti hr = IStream_Read(stream, &lsd_data, sizeof(lsd_data), &bytesread); if (FAILED(hr) || bytesread != sizeof(lsd_data)) return S_OK; - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 9); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 9); if (!result) return E_OUTOFMEMORY; for (i = 0; i < 9; i++) @@ -165,7 +165,7 @@ static HRESULT load_IMD_metadata(IStream *stream, const GUID *vendor, DWORD opti hr = IStream_Read(stream, &imd_data, sizeof(imd_data), &bytesread); if (FAILED(hr) || bytesread != sizeof(imd_data)) return S_OK; - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 8); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 8); if (!result) return E_OUTOFMEMORY; for (i = 0; i < 8; i++) @@ -258,7 +258,7 @@ static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD opti hr = IStream_Read(stream, &gce_data, sizeof(gce_data), &bytesread); if (FAILED(hr) || bytesread != sizeof(gce_data)) return S_OK; - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 5); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 5); if (!result) return E_OUTOFMEMORY; for (i = 0; i < 5; i++) @@ -373,7 +373,7 @@ static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD opti data_size += subblock_size + 1; } - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 2); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem) * 2); if (!result) { HeapFree(GetProcessHeap(), 0, data); @@ -478,7 +478,7 @@ static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWO data[data_size] = 0; - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem)); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); if (!result) { HeapFree(GetProcessHeap(), 0, data); @@ -530,7 +530,8 @@ static IStream *create_stream(const void *data, int data_size) } static HRESULT create_metadata_reader(const void *data, int data_size, - const CLSID *clsid, IWICMetadataReader **reader) + class_constructor constructor, + IWICMetadataReader **reader) { HRESULT hr; IWICMetadataReader *metadata_reader; @@ -539,8 +540,7 @@ static HRESULT create_metadata_reader(const void *data, int data_size, /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ - hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICMetadataReader, (void **)&metadata_reader); + hr = constructor(&IID_IWICMetadataReader, (void**)&metadata_reader); if (FAILED(hr)) return hr; hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); @@ -563,6 +563,7 @@ static HRESULT create_metadata_reader(const void *data, int data_size, typedef struct { IWICBitmapDecoder IWICBitmapDecoder_iface; IWICMetadataBlockReader IWICMetadataBlockReader_iface; + IStream *stream; BYTE LSD_data[13]; /* Logical Screen Descriptor */ LONG ref; BOOL initialized; @@ -885,8 +886,7 @@ static HRESULT create_IMD_metadata_reader(GifFrameDecode *This, IWICMetadataRead /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ - hr = CoCreateInstance(&CLSID_WICIMDMetadataReader, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICMetadataReader, (void **)&metadata_reader); + hr = IMDReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); if (FAILED(hr)) return hr; hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); @@ -942,7 +942,7 @@ static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockRea for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++) { - const CLSID *clsid; + class_constructor constructor; const void *data; int data_size; @@ -956,24 +956,24 @@ static HRESULT WINAPI GifFrameDecode_Block_GetReaderByIndex(IWICMetadataBlockRea } else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) { - clsid = &CLSID_WICGifCommentMetadataReader; + constructor = GifCommentReader_CreateInstance; data = This->frame->Extensions.ExtensionBlocks[i].Bytes; data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; } else { - clsid = &CLSID_WICUnknownMetadataReader; + constructor = UnknownMetadataReader_CreateInstance; data = This->frame->Extensions.ExtensionBlocks[i].Bytes; data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount; } - return create_metadata_reader(data, data_size, clsid, reader); + return create_metadata_reader(data, data_size, constructor, reader); } if (gce_index == -1) return E_INVALIDARG; return create_metadata_reader(This->frame->Extensions.ExtensionBlocks[gce_index].Bytes + 3, This->frame->Extensions.ExtensionBlocks[gce_index].ByteCount - 4, - &CLSID_WICGCEMetadataReader, reader); + GCEReader_CreateInstance, reader); } static HRESULT WINAPI GifFrameDecode_Block_GetEnumerator(IWICMetadataBlockReader *iface, @@ -1040,6 +1040,7 @@ static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface) if (ref == 0) { + IStream_Release(This->stream); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); DGifCloseFile(This->gif); @@ -1127,6 +1128,9 @@ static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); IStream_Read(pIStream, This->LSD_data, sizeof(This->LSD_data), NULL); + This->stream = pIStream; + IStream_AddRef(This->stream); + This->initialized = TRUE; LeaveCriticalSection(&This->lock); @@ -1361,24 +1365,24 @@ static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader if (index == 0) return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data), - &CLSID_WICLSDMetadataReader, reader); + LSDReader_CreateInstance, reader); for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++) { - const CLSID *clsid; + class_constructor constructor; if (index != i + 1) continue; if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE) - clsid = &CLSID_WICAPEMetadataReader; + constructor = APEReader_CreateInstance; else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE) - clsid = &CLSID_WICGifCommentMetadataReader; + constructor = GifCommentReader_CreateInstance; else - clsid = &CLSID_WICUnknownMetadataReader; + constructor = UnknownMetadataReader_CreateInstance; return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes, This->gif->Extensions.ExtensionBlocks[i].ByteCount, - clsid, reader); + constructor, reader); } return E_INVALIDARG; diff --git a/reactos/dll/win32/windowscodecs/icnsformat.c b/reactos/dll/win32/windowscodecs/icnsformat.c index 3fdface5106..b9764e65f0b 100644 --- a/reactos/dll/win32/windowscodecs/icnsformat.c +++ b/reactos/dll/win32/windowscodecs/icnsformat.c @@ -162,7 +162,7 @@ static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface) if (This->icns_image != NULL) HeapFree(GetProcessHeap(), 0, This->icns_image); - IUnknown_Release((IUnknown*)This->encoder); + IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface); HeapFree(GetProcessHeap(), 0, This); } @@ -380,7 +380,7 @@ static HRESULT WINAPI IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, if (!This->initialized) return WINCODEC_ERR_WRONGSTATE; - hr = configure_write_source(iface, pIBitmapSource, &prc, + hr = configure_write_source(iface, pIBitmapSource, prc, &GUID_WICPixelFormat32bppBGRA, This->size, This->size, 1.0, 1.0); @@ -472,7 +472,7 @@ static HRESULT WINAPI IcnsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFII if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapEncoder, iid)) { - *ppv = This; + *ppv = &This->IWICBitmapEncoder_iface; } else { @@ -622,7 +622,7 @@ static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface, frameEncode->committed = FALSE; *ppIFrameEncode = &frameEncode->IWICBitmapFrameEncode_iface; This->outstanding_commits++; - IUnknown_AddRef((IUnknown*)This); + IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface); end: LeaveCriticalSection(&This->lock); @@ -708,8 +708,8 @@ HRESULT IcnsEncoder_CreateInstance(REFIID iid, void** ppv) InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcnsEncoder.lock"); - ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv); - IUnknown_Release((IUnknown*)This); + ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); + IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); return ret; } diff --git a/reactos/dll/win32/windowscodecs/imgfactory.c b/reactos/dll/win32/windowscodecs/imgfactory.c index d90db02e5e7..1b36d29eecf 100644 --- a/reactos/dll/win32/windowscodecs/imgfactory.c +++ b/reactos/dll/win32/windowscodecs/imgfactory.c @@ -694,7 +694,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFact return E_INVALIDARG; } - hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, &format, option, bitmap); + hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, &format, WICBitmapCacheOnLoad, bitmap); if (hr != S_OK) return hr; hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); diff --git a/reactos/dll/win32/windowscodecs/info.c b/reactos/dll/win32/windowscodecs/info.c index a24b7283d6a..ca1c1960e02 100644 --- a/reactos/dll/win32/windowscodecs/info.c +++ b/reactos/dll/win32/windowscodecs/info.c @@ -213,7 +213,7 @@ static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *if IsEqualIID(&IID_IWICBitmapCodecInfo, iid) || IsEqualIID(&IID_IWICBitmapDecoderInfo ,iid)) { - *ppv = This; + *ppv = &This->IWICBitmapDecoderInfo_iface; } else { @@ -606,8 +606,7 @@ static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *if TRACE("(%p,%p)\n", iface, ppIBitmapDecoder); - return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder); + return create_instance(&This->clsid, &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder); } static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = { @@ -655,7 +654,7 @@ static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWIC This->classkey = classkey; memcpy(&This->clsid, clsid, sizeof(CLSID)); - *ppIInfo = (IWICComponentInfo*)This; + *ppIInfo = (IWICComponentInfo *)&This->IWICBitmapDecoderInfo_iface; return S_OK; } @@ -684,7 +683,7 @@ static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *if IsEqualIID(&IID_IWICBitmapCodecInfo, iid) || IsEqualIID(&IID_IWICBitmapEncoderInfo ,iid)) { - *ppv = This; + *ppv = &This->IWICBitmapEncoderInfo_iface; } else { @@ -900,8 +899,7 @@ static HRESULT WINAPI BitmapEncoderInfo_CreateInstance(IWICBitmapEncoderInfo *if TRACE("(%p,%p)\n", iface, ppIBitmapEncoder); - return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder); + return create_instance(&This->clsid, &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder); } static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = { @@ -947,7 +945,7 @@ static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWIC This->classkey = classkey; memcpy(&This->clsid, clsid, sizeof(CLSID)); - *ppIInfo = (IWICComponentInfo*)This; + *ppIInfo = (IWICComponentInfo *)&This->IWICBitmapEncoderInfo_iface; return S_OK; } @@ -975,7 +973,7 @@ static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo IsEqualIID(&IID_IWICComponentInfo, iid) || IsEqualIID(&IID_IWICFormatConverterInfo ,iid)) { - *ppv = This; + *ppv = &This->IWICFormatConverterInfo_iface; } else { @@ -1108,8 +1106,8 @@ static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo TRACE("(%p,%p)\n", iface, ppIFormatConverter); - return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICFormatConverter, (void**)ppIFormatConverter); + return create_instance(&This->clsid, &IID_IWICFormatConverter, + (void**)ppIFormatConverter); } static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid) @@ -1164,7 +1162,7 @@ static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IW This->classkey = classkey; memcpy(&This->clsid, clsid, sizeof(CLSID)); - *ppIInfo = (IWICComponentInfo*)This; + *ppIInfo = (IWICComponentInfo *)&This->IWICFormatConverterInfo_iface; return S_OK; } @@ -1193,7 +1191,7 @@ static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface IsEqualIID(&IID_IWICPixelFormatInfo, iid) || IsEqualIID(&IID_IWICPixelFormatInfo2 ,iid)) { - *ppv = This; + *ppv = &This->IWICPixelFormatInfo2_iface; } else { @@ -1458,7 +1456,7 @@ static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICCo This->classkey = classkey; memcpy(&This->clsid, clsid, sizeof(CLSID)); - *ppIInfo = (IWICComponentInfo*)This; + *ppIInfo = (IWICComponentInfo *)&This->IWICPixelFormatInfo2_iface; return S_OK; } @@ -1489,7 +1487,7 @@ static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo * IsEqualIID(&IID_IWICMetadataHandlerInfo, riid) || IsEqualIID(&IID_IWICMetadataReaderInfo, riid)) { - *ppv = This; + *ppv = &This->IWICMetadataReaderInfo_iface; } else { @@ -1854,8 +1852,7 @@ static HRESULT WINAPI MetadataReaderInfo_CreateInstance(IWICMetadataReaderInfo * TRACE("(%p,%p)\n", iface, reader); - return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICMetadataReader, (void **)reader); + return create_instance(&This->clsid, &IID_IWICMetadataReader, (void **)reader); } static const IWICMetadataReaderInfoVtbl MetadataReaderInfo_Vtbl = { @@ -1898,7 +1895,7 @@ static HRESULT MetadataReaderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWI This->classkey = classkey; This->clsid = *clsid; - *info = (IWICComponentInfo *)This; + *info = (IWICComponentInfo *)&This->IWICMetadataReaderInfo_iface; return S_OK; } diff --git a/reactos/dll/win32/windowscodecs/metadatahandler.c b/reactos/dll/win32/windowscodecs/metadatahandler.c index f7239e4ac29..7adcba08e1c 100644 --- a/reactos/dll/win32/windowscodecs/metadatahandler.c +++ b/reactos/dll/win32/windowscodecs/metadatahandler.c @@ -680,7 +680,7 @@ static HRESULT LoadUnknownMetadata(IStream *input, const GUID *preferred_vendor, return hr; } - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem)); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); if (!result) { HeapFree(GetProcessHeap(), 0, data); @@ -1110,7 +1110,7 @@ static HRESULT LoadIfdMetadata(IStream *input, const GUID *preferred_vendor, return WINCODEC_ERR_BADMETADATAHEADER; } - result = HeapAlloc(GetProcessHeap(), 0, count * sizeof(*result)); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * sizeof(*result)); if (!result) { HeapFree(GetProcessHeap(), 0, entry); diff --git a/reactos/dll/win32/windowscodecs/pngformat.c b/reactos/dll/win32/windowscodecs/pngformat.c index a4ce89ea402..e9973ef1411 100644 --- a/reactos/dll/win32/windowscodecs/pngformat.c +++ b/reactos/dll/win32/windowscodecs/pngformat.c @@ -24,6 +24,11 @@ static const WCHAR wszPngInterlaceOption[] = {'I','n','t','e','r','l','a','c','e','O','p','t','i','o','n',0}; +static inline ULONG read_ulong_be(BYTE* data) +{ + return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; +} + static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *data_size) { BYTE header[8]; @@ -38,7 +43,7 @@ static HRESULT read_png_chunk(IStream *stream, BYTE *type, BYTE **data, ULONG *d return hr; } - *data_size = header[0] << 24 | header[1] << 16 | header[2] << 8 | header[3]; + *data_size = read_ulong_be(&header[0]); memcpy(type, &header[4], 4); @@ -92,7 +97,7 @@ static HRESULT LoadTextMetadata(IStream *stream, const GUID *preferred_vendor, value_len = data_size - name_len - 1; - result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem)); + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); name = HeapAlloc(GetProcessHeap(), 0, name_len + 1); value = HeapAlloc(GetProcessHeap(), 0, value_len + 1); if (!result || !name || !value) @@ -136,6 +141,68 @@ HRESULT PngTextReader_CreateInstance(REFIID iid, void** ppv) return MetadataReader_Create(&TextReader_Vtbl, iid, ppv); } +static HRESULT LoadGamaMetadata(IStream *stream, const GUID *preferred_vendor, + DWORD persist_options, MetadataItem **items, DWORD *item_count) +{ + HRESULT hr; + BYTE type[4]; + BYTE *data; + ULONG data_size; + ULONG gamma; + static const WCHAR ImageGamma[] = {'I','m','a','g','e','G','a','m','m','a',0}; + LPWSTR name; + MetadataItem *result; + + hr = read_png_chunk(stream, type, &data, &data_size); + if (FAILED(hr)) return hr; + + if (data_size < 4) + { + HeapFree(GetProcessHeap(), 0, data); + return E_FAIL; + } + + gamma = read_ulong_be(data); + + HeapFree(GetProcessHeap(), 0, data); + + result = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MetadataItem)); + name = HeapAlloc(GetProcessHeap(), 0, sizeof(ImageGamma)); + if (!result || !name) + { + HeapFree(GetProcessHeap(), 0, result); + HeapFree(GetProcessHeap(), 0, name); + return E_OUTOFMEMORY; + } + + PropVariantInit(&result[0].schema); + PropVariantInit(&result[0].id); + PropVariantInit(&result[0].value); + + memcpy(name, ImageGamma, sizeof(ImageGamma)); + + result[0].id.vt = VT_LPWSTR; + result[0].id.u.pwszVal = name; + result[0].value.vt = VT_UI4; + result[0].value.u.ulVal = gamma; + + *items = result; + *item_count = 1; + + return S_OK; +} + +static const MetadataHandlerVtbl GamaReader_Vtbl = { + 0, + &CLSID_WICPngGamaMetadataReader, + LoadGamaMetadata +}; + +HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv) +{ + return MetadataReader_Create(&GamaReader_Vtbl, iid, ppv); +} + #ifdef SONAME_LIBPNG static void *libpng_handle; @@ -272,11 +339,17 @@ static void user_warning_fn(png_structp png_ptr, png_const_charp warning_message WARN("PNG warning: %s\n", debugstr_a(warning_message)); } +typedef struct { + ULARGE_INTEGER ofs, len; + IWICMetadataReader* reader; +} metadata_block_info; + typedef struct { IWICBitmapDecoder IWICBitmapDecoder_iface; IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; IWICMetadataBlockReader IWICMetadataBlockReader_iface; LONG ref; + IStream *stream; png_structp png_ptr; png_infop info_ptr; png_infop end_info; @@ -287,6 +360,8 @@ typedef struct { const WICPixelFormatGUID *format; BYTE *image_bits; CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */ + ULONG metadata_count; + metadata_block_info* metadata_blocks; } PngDecoder; static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) @@ -342,16 +417,25 @@ static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface) { PngDecoder *This = impl_from_IWICBitmapDecoder(iface); ULONG ref = InterlockedDecrement(&This->ref); + ULONG i; TRACE("(%p) refcount=%u\n", iface, ref); if (ref == 0) { + if (This->stream) + IStream_Release(This->stream); if (This->png_ptr) ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); HeapFree(GetProcessHeap(), 0, This->image_bits); + for (i=0; imetadata_count; i++) + { + if (This->metadata_blocks[i].reader) + IWICMetadataReader_Release(This->metadata_blocks[i].reader); + } + HeapFree(GetProcessHeap(), 0, This->metadata_blocks); HeapFree(GetProcessHeap(), 0, This); } @@ -404,6 +488,10 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p png_uint_32 transparency; png_color_16p trans_values; jmp_buf jmpbuf; + BYTE chunk_type[4]; + ULONG chunk_size; + ULARGE_INTEGER chunk_start; + ULONG metadata_blocks_size = 0; TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); @@ -586,10 +674,60 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p ppng_read_end(This->png_ptr, This->end_info); + /* Find the metadata chunks in the file. */ + seek.QuadPart = 8; + hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start); + if (FAILED(hr)) goto end; + + do + { + hr = read_png_chunk(pIStream, chunk_type, NULL, &chunk_size); + if (FAILED(hr)) goto end; + + if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' && + memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4)) + { + /* This chunk is considered metadata. */ + if (This->metadata_count == metadata_blocks_size) + { + metadata_block_info* new_metadata_blocks; + ULONG new_metadata_blocks_size; + + new_metadata_blocks_size = 4 + metadata_blocks_size * 2; + new_metadata_blocks = HeapAlloc(GetProcessHeap(), 0, + new_metadata_blocks_size * sizeof(*new_metadata_blocks)); + + if (!new_metadata_blocks) + { + hr = E_OUTOFMEMORY; + goto end; + } + + memcpy(new_metadata_blocks, This->metadata_blocks, + This->metadata_count * sizeof(*new_metadata_blocks)); + + HeapFree(GetProcessHeap(), 0, This->metadata_blocks); + This->metadata_blocks = new_metadata_blocks; + metadata_blocks_size = new_metadata_blocks_size; + } + + This->metadata_blocks[This->metadata_count].ofs = chunk_start; + This->metadata_blocks[This->metadata_count].len.QuadPart = chunk_size + 12; + This->metadata_blocks[This->metadata_count].reader = NULL; + This->metadata_count++; + } + + seek.QuadPart = chunk_start.QuadPart + chunk_size + 12; /* skip data and CRC */ + hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, &chunk_start); + if (FAILED(hr)) goto end; + } while (memcmp(chunk_type, "IEND", 4)); + + This->stream = pIStream; + IStream_AddRef(This->stream); + This->initialized = TRUE; end: - LeaveCriticalSection(&This->lock); return hr; @@ -959,17 +1097,65 @@ static HRESULT WINAPI PngDecoder_Block_GetContainerFormat(IWICMetadataBlockReade static HRESULT WINAPI PngDecoder_Block_GetCount(IWICMetadataBlockReader *iface, UINT *pcCount) { - static int once; + PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); + TRACE("%p,%p\n", iface, pcCount); - if (!once++) FIXME("stub\n"); - return E_NOTIMPL; + + if (!pcCount) return E_INVALIDARG; + + *pcCount = This->metadata_count; + + return S_OK; } static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, UINT nIndex, IWICMetadataReader **ppIMetadataReader) { - FIXME("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); - return E_NOTIMPL; + PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); + HRESULT hr; + IWICComponentFactory* factory; + IWICStream* stream; + + TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); + + if (nIndex >= This->metadata_count || !ppIMetadataReader) + return E_INVALIDARG; + + if (!This->metadata_blocks[nIndex].reader) + { + hr = StreamImpl_Create(&stream); + + if (SUCCEEDED(hr)) + { + hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream, + This->metadata_blocks[nIndex].ofs, This->metadata_blocks[nIndex].len); + + if (SUCCEEDED(hr)) + hr = ComponentFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory); + + if (SUCCEEDED(hr)) + { + hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, + &GUID_ContainerFormatPng, NULL, WICMetadataCreationAllowUnknown, + (IStream*)stream, &This->metadata_blocks[nIndex].reader); + + IWICComponentFactory_Release(factory); + } + + IWICStream_Release(stream); + } + + if (FAILED(hr)) + { + *ppIMetadataReader = NULL; + return hr; + } + } + + *ppIMetadataReader = This->metadata_blocks[nIndex].reader; + IWICMetadataReader_AddRef(*ppIMetadataReader); + + return S_OK; } static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, @@ -1014,10 +1200,13 @@ HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) This->png_ptr = NULL; This->info_ptr = NULL; This->end_info = NULL; + This->stream = NULL; This->initialized = FALSE; This->image_bits = NULL; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": PngDecoder.lock"); + This->metadata_count = 0; + This->metadata_blocks = NULL; ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); diff --git a/reactos/dll/win32/windowscodecs/regsvr.c b/reactos/dll/win32/windowscodecs/regsvr.c index 44641c76803..18812d817a5 100644 --- a/reactos/dll/win32/windowscodecs/regsvr.c +++ b/reactos/dll/win32/windowscodecs/regsvr.c @@ -1483,6 +1483,21 @@ static const struct reader_containers pngtext_containers[] = { { NULL } /* list terminator */ }; +static const BYTE gAMA[] = "gAMA"; + +static const struct metadata_pattern pnggama_metadata_pattern[] = { + { 4, 4, gAMA, mask_all, 4 }, + { 0 } +}; + +static const struct reader_containers pnggama_containers[] = { + { + &GUID_ContainerFormatPng, + pnggama_metadata_pattern + }, + { NULL } /* list terminator */ +}; + static const struct metadata_pattern lsd_metadata_patterns[] = { { 0, 6, gif87a_magic, mask_all, 0 }, { 0, 6, gif89a_magic, mask_all, 0 }, @@ -1578,6 +1593,16 @@ static struct regsvr_metadatareader const metadatareader_list[] = { 1, 1, 0, ifd_containers }, + { &CLSID_WICPngGamaMetadataReader, + "The Wine Project", + "Chunk gAMA Reader", + "1.0.0.0", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_MetadataFormatChunkgAMA, + 0, 0, 0, + pnggama_containers + }, { &CLSID_WICPngTextMetadataReader, "The Wine Project", "Chunk tEXt Reader", diff --git a/reactos/dll/win32/windowscodecs/stream.c b/reactos/dll/win32/windowscodecs/stream.c index e0ec3f13417..f585036edef 100644 --- a/reactos/dll/win32/windowscodecs/stream.c +++ b/reactos/dll/win32/windowscodecs/stream.c @@ -748,7 +748,7 @@ static HRESULT WINAPI IWICStreamImpl_QueryInterface(IWICStream *iface, if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IStream, iid) || IsEqualIID(&IID_ISequentialStream, iid) || IsEqualIID(&IID_IWICStream, iid)) { - *ppv = This; + *ppv = &This->IWICStream_iface; IUnknown_AddRef((IUnknown*)*ppv); return S_OK; } diff --git a/reactos/dll/win32/windowscodecs/tiffformat.c b/reactos/dll/win32/windowscodecs/tiffformat.c index 253be566c4e..2aa711c0419 100644 --- a/reactos/dll/win32/windowscodecs/tiffformat.c +++ b/reactos/dll/win32/windowscodecs/tiffformat.c @@ -219,7 +219,7 @@ typedef struct { const WICPixelFormatGUID *format; int bps; int samples; - int bpp; + int bpp, source_bpp; int planar; int indexed; int reverse_bgr; @@ -318,26 +318,54 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) extra_sample = 0; extra_samples = &extra_sample; } - else - FIXME("ignoring extra alpha %u/%u bps %u\n", extra_sample_count, extra_samples[0], bps); } else if (samples != 1) { - FIXME("unhandled grayscale sample count %u\n", samples); + FIXME("unhandled %dbpp sample count %u\n", bps, samples); return E_FAIL; } - decode_info->bpp = bps; + decode_info->bpp = bps * samples; + decode_info->source_bpp = decode_info->bpp; switch (bps) { case 1: + if (samples != 1) + { + FIXME("unhandled 1bpp sample count %u\n", samples); + return E_FAIL; + } decode_info->format = &GUID_WICPixelFormatBlackWhite; break; case 4: + if (samples != 1) + { + FIXME("unhandled 4bpp grayscale sample count %u\n", samples); + return E_FAIL; + } decode_info->format = &GUID_WICPixelFormat4bppGray; break; case 8: - decode_info->format = &GUID_WICPixelFormat8bppGray; + if (samples == 1) + decode_info->format = &GUID_WICPixelFormat8bppGray; + else + { + decode_info->bpp = 32; + + switch(extra_samples[0]) + { + case 1: /* Associated (pre-multiplied) alpha data */ + decode_info->format = &GUID_WICPixelFormat32bppPBGRA; + break; + case 0: /* Unspecified data */ + case 2: /* Unassociated alpha data */ + decode_info->format = &GUID_WICPixelFormat32bppBGRA; + break; + default: + FIXME("unhandled extra sample type %u\n", extra_samples[0]); + return E_FAIL; + } + } break; default: FIXME("unhandled greyscale bit count %u\n", bps); @@ -938,6 +966,22 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT hr = E_FAIL; } + /* 8bpp grayscale with extra alpha */ + if (hr == S_OK && This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32) + { + BYTE *src; + DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height; + + src = This->cached_tile + This->decode_info.tile_width * This->decode_info.tile_height * 2 - 2; + dst = (DWORD *)(This->cached_tile + This->decode_info.tile_size - 4); + + while (count--) + { + *dst-- = src[0] | (src[0] << 8) | (src[0] << 16) | (src[1] << 24); + src -= 2; + } + } + if (hr == S_OK && This->decode_info.reverse_bgr) { if (This->decode_info.bps == 8) @@ -1218,8 +1262,7 @@ static HRESULT create_metadata_reader(TiffFrameDecode *This, IWICMetadataReader /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */ - hr = CoCreateInstance(&CLSID_WICIfdMetadataReader, NULL, CLSCTX_INPROC_SERVER, - &IID_IWICMetadataReader, (void **)&metadata_reader); + hr = IfdMetadataReader_CreateInstance(&IID_IWICMetadataReader, (void **)&metadata_reader); if (FAILED(hr)) return hr; hr = IWICMetadataReader_QueryInterface(metadata_reader, &IID_IWICPersistStream, (void **)&persist); diff --git a/reactos/dll/win32/windowscodecs/ungif.c b/reactos/dll/win32/windowscodecs/ungif.c index 40ced841e84..b3468427a46 100644 --- a/reactos/dll/win32/windowscodecs/ungif.c +++ b/reactos/dll/win32/windowscodecs/ungif.c @@ -491,7 +491,7 @@ DGifGetLine(GifFileType * GifFile, * image until empty block (size 0) detected. We use GetCodeNext. */ do if (DGifGetCodeNext(GifFile, &Dummy) == GIF_ERROR) - return GIF_ERROR; + break; while (Dummy != NULL) ; } return GIF_OK; diff --git a/reactos/dll/win32/windowscodecs/wincodecs_private.h b/reactos/dll/win32/windowscodecs/wincodecs_private.h index 7bb44c51b78..e47aca89a56 100644 --- a/reactos/dll/win32/windowscodecs/wincodecs_private.h +++ b/reactos/dll/win32/windowscodecs/wincodecs_private.h @@ -94,6 +94,9 @@ DECLARE_INTERFACE_(IMILUnknown2,IUnknown) }; #undef INTERFACE +HRESULT create_instance(CLSID *clsid, const IID *iid, void **ppv) DECLSPEC_HIDDEN; + +typedef HRESULT(*class_constructor)(REFIID,void**); extern HRESULT FormatConverter_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT ComponentFactory_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT BmpDecoder_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN; @@ -175,6 +178,7 @@ extern HRESULT MetadataReader_Create(const MetadataHandlerVtbl *vtable, REFIID i extern HRESULT UnknownMetadataReader_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT IfdMetadataReader_CreateInstance(REFIID iid, void **ppv) DECLSPEC_HIDDEN; +extern HRESULT PngGamaReader_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT PngTextReader_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv) DECLSPEC_HIDDEN; extern HRESULT IMDReader_CreateInstance(REFIID iid, void **ppv) DECLSPEC_HIDDEN; diff --git a/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.idl b/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.idl index 489d74bc5c7..089bb39dc95 100644 --- a/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.idl +++ b/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.idl @@ -139,6 +139,13 @@ coclass WICUnknownMetadataReader { interface IWICMetadataReader; } ] coclass WICIfdMetadataReader { interface IWICIfdMetadataReader; } +[ + helpstring("WIC Png gAMA Metadata Reader"), + threading(both), + uuid(3692ca39-e082-4350-9e1f-3704cb083cd5) +] +coclass WICPngGamaMetadataReader { interface IWICMetadataReader; } + [ helpstring("WIC Png tEXt Metadata Reader"), threading(both), diff --git a/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.rgs b/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.rgs index fc33de64ec8..83fce40bc85 100644 --- a/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.rgs +++ b/reactos/dll/win32/windowscodecs/windowscodecs_wincodec.rgs @@ -203,6 +203,10 @@ HKCR { InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } } + '{3692CA39-E082-4350-9E1F-3704CB083CD5}' = s 'WIC Png gAMA Metadata Reader' + { + InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } + } '{4B59AFCC-B8C3-408A-B670-89E5FAB6FDA7}' = s 'WIC Png tEXt Metadata Reader' { InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } @@ -228,4 +232,4 @@ HKCR InprocServer32 = s '%MODULE%' { val ThreadingModel = s 'Both' } } } -} \ No newline at end of file +} diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index a30964affaa..bcb5ce85e47 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -202,7 +202,7 @@ reactos/dll/win32/vbscript # Synced to WineStaging-1.7.47 reactos/dll/win32/version # Synced to WineStaging-1.7.47 reactos/dll/win32/wbemdisp # Synced to WineStaging-1.7.47 reactos/dll/win32/wbemprox # Synced to WineStaging-1.7.47 -reactos/dll/win32/windowscodecs # Synced to WineStaging-1.7.37 +reactos/dll/win32/windowscodecs # Synced to WineStaging-1.7.47 reactos/dll/win32/windowscodecsext # Synced to WineStaging-1.7.37 reactos/dll/win32/winemp3.acm # Synced to WineStaging-1.7.47 reactos/dll/win32/wing32 # Out of sync