Signed-off-by: Esme Povirk esme@codeweavers.com --- dlls/windowscodecs/Makefile.in | 1 + dlls/windowscodecs/decoder.c | 746 +++++++++++++++++++++++ dlls/windowscodecs/pngformat.c | 810 +------------------------ dlls/windowscodecs/wincodecs_private.h | 3 + 4 files changed, 765 insertions(+), 795 deletions(-) create mode 100644 dlls/windowscodecs/decoder.c
diff --git a/dlls/windowscodecs/Makefile.in b/dlls/windowscodecs/Makefile.in index fde28aea778..2472ef57d63 100644 --- a/dlls/windowscodecs/Makefile.in +++ b/dlls/windowscodecs/Makefile.in @@ -14,6 +14,7 @@ C_SRCS = \ colortransform.c \ converter.c \ ddsformat.c \ + decoder.c \ fliprotate.c \ gifformat.c \ icnsformat.c \ diff --git a/dlls/windowscodecs/decoder.c b/dlls/windowscodecs/decoder.c new file mode 100644 index 00000000000..599b5780e8f --- /dev/null +++ b/dlls/windowscodecs/decoder.c @@ -0,0 +1,746 @@ +/* + * Copyright 2020 Esme Povirk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#include "wine/port.h" + +#include <stdarg.h> + +#define NONAMELESSUNION +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +typedef struct { + IWICBitmapDecoder IWICBitmapDecoder_iface; + LONG ref; + CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */ + IStream *stream; + struct decoder *decoder; + struct decoder_info decoder_info; + struct decoder_stat file_info; + WICDecodeOptions cache_options; +} CommonDecoder; + +static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI CommonDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, + void **ppv) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) + { + *ppv = &This->IWICBitmapDecoder_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CommonDecoder_AddRef(IWICBitmapDecoder *iface) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%u\n", iface, ref); + + return ref; +} + +static ULONG WINAPI CommonDecoder_Release(IWICBitmapDecoder *iface) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%u\n", iface, ref); + + if (ref == 0) + { + if (This->stream) + IStream_Release(This->stream); + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI CommonDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, + DWORD *capability) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr; + + TRACE("(%p,%p,%p)\n", iface, stream, capability); + + if (!stream || !capability) return E_INVALIDARG; + + hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); + if (hr != S_OK) return hr; + + *capability = (This->file_info.flags & DECODER_FLAGS_CAPABILITY_MASK); + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, + WICDecodeOptions cacheOptions) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr=S_OK; + + TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); + + EnterCriticalSection(&This->lock); + + if (This->stream) + hr = WINCODEC_ERR_WRONGSTATE; + + if (SUCCEEDED(hr)) + hr = decoder_initialize(This->decoder, pIStream, &This->file_info); + + if (SUCCEEDED(hr)) + { + This->cache_options = cacheOptions; + This->stream = pIStream; + IStream_AddRef(This->stream); + } + + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoder_GetContainerFormat(IWICBitmapDecoder *iface, + GUID *pguidContainerFormat) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + memcpy(pguidContainerFormat, &This->decoder_info.container_format, sizeof(GUID)); + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, + IWICBitmapDecoderInfo **ppIDecoderInfo) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%p)\n", iface, ppIDecoderInfo); + + return get_decoder_info(&This->decoder_info.clsid, ppIDecoderInfo); +} + +static HRESULT WINAPI CommonDecoder_CopyPalette(IWICBitmapDecoder *iface, + IWICPalette *palette) +{ + TRACE("(%p,%p)\n", iface, palette); + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + +static HRESULT WINAPI CommonDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, + IWICMetadataQueryReader **reader) +{ + TRACE("(%p,%p)\n", iface, reader); + + if (!reader) return E_INVALIDARG; + + *reader = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetPreview(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIBitmapSource) +{ + TRACE("(%p,%p)\n", iface, ppIBitmapSource); + + if (!ppIBitmapSource) return E_INVALIDARG; + + *ppIBitmapSource = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetColorContexts(IWICBitmapDecoder *iface, + UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +{ + TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetThumbnail(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIThumbnail) +{ + TRACE("(%p,%p)\n", iface, ppIThumbnail); + + if (!ppIThumbnail) return E_INVALIDARG; + + *ppIThumbnail = NULL; + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static HRESULT WINAPI CommonDecoder_GetFrameCount(IWICBitmapDecoder *iface, + UINT *pCount) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + if (!pCount) return E_INVALIDARG; + + if (!This->stream) return WINCODEC_ERR_WRONGSTATE; + + *pCount = This->file_info.frame_count; + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, + UINT index, IWICBitmapFrameDecode **ppIBitmapFrame); + +static const IWICBitmapDecoderVtbl CommonDecoder_Vtbl = { + CommonDecoder_QueryInterface, + CommonDecoder_AddRef, + CommonDecoder_Release, + CommonDecoder_QueryCapability, + CommonDecoder_Initialize, + CommonDecoder_GetContainerFormat, + CommonDecoder_GetDecoderInfo, + CommonDecoder_CopyPalette, + CommonDecoder_GetMetadataQueryReader, + CommonDecoder_GetPreview, + CommonDecoder_GetColorContexts, + CommonDecoder_GetThumbnail, + CommonDecoder_GetFrameCount, + CommonDecoder_GetFrame +}; + +typedef struct { + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + IWICMetadataBlockReader IWICMetadataBlockReader_iface; + LONG ref; + CommonDecoder *parent; + DWORD frame; + struct decoder_frame decoder_frame; + BOOL metadata_initialized; + ULONG metadata_count; + struct decoder_block* metadata_blocks; +} CommonDecoderFrame; + +static inline CommonDecoderFrame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICBitmapFrameDecode_iface); +} + +static inline CommonDecoderFrame *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICMetadataBlockReader_iface); +} + +static HRESULT WINAPI CommonDecoderFrame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, + void **ppv) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid) || + IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) + { + *ppv = &This->IWICBitmapFrameDecode_iface; + } + else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid) && + (This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata)) + { + *ppv = &This->IWICMetadataBlockReader_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CommonDecoderFrame_AddRef(IWICBitmapFrameDecode *iface) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%u\n", iface, ref); + + return ref; +} + +static ULONG WINAPI CommonDecoderFrame_Release(IWICBitmapFrameDecode *iface) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%u\n", iface, ref); + + if (ref == 0) + { + IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); + HeapFree(GetProcessHeap(), 0, This->metadata_blocks); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI CommonDecoderFrame_GetSize(IWICBitmapFrameDecode *iface, + UINT *puiWidth, UINT *puiHeight) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p,%p)\n", This, puiWidth, puiHeight); + + if (!puiWidth || !puiHeight) + return E_POINTER; + + *puiWidth = This->decoder_frame.width; + *puiHeight = This->decoder_frame.height; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_GetPixelFormat(IWICBitmapFrameDecode *iface, + WICPixelFormatGUID *pPixelFormat) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p)\n", This, pPixelFormat); + + if (!pPixelFormat) + return E_POINTER; + + *pPixelFormat = This->decoder_frame.pixel_format; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_GetResolution(IWICBitmapFrameDecode *iface, + double *pDpiX, double *pDpiY) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p,%p)\n", This, pDpiX, pDpiY); + + if (!pDpiX || !pDpiY) + return E_POINTER; + + *pDpiX = This->decoder_frame.dpix; + *pDpiY = This->decoder_frame.dpiy; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_CopyPalette(IWICBitmapFrameDecode *iface, + IWICPalette *pIPalette) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr=S_OK; + + TRACE("(%p,%p)\n", iface, pIPalette); + + if (This->decoder_frame.num_colors) + { + hr = IWICPalette_InitializeCustom(pIPalette, This->decoder_frame.palette, This->decoder_frame.num_colors); + } + else + { + hr = WINCODEC_ERR_PALETTEUNAVAILABLE; + } + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_CopyPixels(IWICBitmapFrameDecode *iface, + const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr; + UINT bytesperrow; + WICRect rect; + + TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); + + if (!pbBuffer) + return E_POINTER; + + if (!prc) + { + rect.X = 0; + rect.Y = 0; + rect.Width = This->decoder_frame.width; + rect.Height = This->decoder_frame.height; + prc = ▭ + } + else + { + if (prc->X < 0 || prc->Y < 0 || + prc->X+prc->Width > This->decoder_frame.width || + prc->Y+prc->Height > This->decoder_frame.height) + return E_INVALIDARG; + } + + bytesperrow = ((This->decoder_frame.bpp * prc->Width)+7)/8; + + if (cbStride < bytesperrow) + return E_INVALIDARG; + + if ((cbStride * (prc->Height-1)) + bytesperrow > cbBufferSize) + return E_INVALIDARG; + + EnterCriticalSection(&This->parent->lock); + + hr = decoder_copy_pixels(This->parent->decoder, This->frame, + prc, cbStride, cbBufferSize, pbBuffer); + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, + IWICMetadataQueryReader **ppIMetadataQueryReader) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); + + if (!ppIMetadataQueryReader) + return E_INVALIDARG; + + if (!(This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata)) + return WINCODEC_ERR_UNSUPPORTEDOPERATION; + + return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); +} + +static HRESULT WINAPI CommonDecoderFrame_GetColorContexts(IWICBitmapFrameDecode *iface, + UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr=S_OK; + UINT i; + BYTE *profile; + DWORD profile_len; + + TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); + + if (!pcActualCount) return E_INVALIDARG; + + *pcActualCount = This->decoder_frame.num_color_contexts; + + if (This->decoder_frame.num_color_contexts && cCount && ppIColorContexts) + { + if (cCount >= This->decoder_frame.num_color_contexts) + { + EnterCriticalSection(&This->parent->lock); + + for (i=0; i<This->decoder_frame.num_color_contexts; i++) + { + hr = decoder_get_color_context(This->parent->decoder, This->frame, i, + &profile, &profile_len); + if (SUCCEEDED(hr)) + { + hr = IWICColorContext_InitializeFromMemory(ppIColorContexts[i], profile, profile_len); + + HeapFree(GetProcessHeap(), 0, profile); + } + + if (FAILED(hr)) + break; + } + + LeaveCriticalSection(&This->parent->lock); + } + else + { + hr = E_INVALIDARG; + } + } + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_GetThumbnail(IWICBitmapFrameDecode *iface, + IWICBitmapSource **ppIThumbnail) +{ + TRACE("(%p,%p)\n", iface, ppIThumbnail); + + if (!ppIThumbnail) return E_INVALIDARG; + + *ppIThumbnail = NULL; + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static const IWICBitmapFrameDecodeVtbl CommonDecoderFrameVtbl = { + CommonDecoderFrame_QueryInterface, + CommonDecoderFrame_AddRef, + CommonDecoderFrame_Release, + CommonDecoderFrame_GetSize, + CommonDecoderFrame_GetPixelFormat, + CommonDecoderFrame_GetResolution, + CommonDecoderFrame_CopyPalette, + CommonDecoderFrame_CopyPixels, + CommonDecoderFrame_GetMetadataQueryReader, + CommonDecoderFrame_GetColorContexts, + CommonDecoderFrame_GetThumbnail +}; + +static HRESULT WINAPI CommonDecoderFrame_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, + void **ppv) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); +} + +static ULONG WINAPI CommonDecoderFrame_Block_AddRef(IWICMetadataBlockReader *iface) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); +} + +static ULONG WINAPI CommonDecoderFrame_Block_Release(IWICMetadataBlockReader *iface) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetContainerFormat(IWICMetadataBlockReader *iface, + GUID *pguidContainerFormat) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + if (!pguidContainerFormat) return E_INVALIDARG; + *pguidContainerFormat = This->parent->decoder_info.block_format; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_InitializeMetadata(CommonDecoderFrame *This) +{ + HRESULT hr=S_OK; + + if (This->metadata_initialized) + return S_OK; + + EnterCriticalSection(&This->parent->lock); + + if (!This->metadata_initialized) + { + hr = decoder_get_metadata_blocks(This->parent->decoder, This->frame, &This->metadata_count, &This->metadata_blocks); + if (SUCCEEDED(hr)) + This->metadata_initialized = TRUE; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetCount(IWICMetadataBlockReader *iface, + UINT *pcCount) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + HRESULT hr; + + TRACE("%p,%p\n", iface, pcCount); + + if (!pcCount) return E_INVALIDARG; + + hr = CommonDecoderFrame_InitializeMetadata(This); + if (SUCCEEDED(hr)) + *pcCount = This->metadata_count; + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, + UINT nIndex, IWICMetadataReader **ppIMetadataReader) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + HRESULT hr; + IWICComponentFactory* factory; + IWICStream* stream; + + TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); + + if (!ppIMetadataReader) + return E_INVALIDARG; + + hr = CommonDecoderFrame_InitializeMetadata(This); + + if (SUCCEEDED(hr) && nIndex >= This->metadata_count) + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) + hr = StreamImpl_Create(&stream); + + if (SUCCEEDED(hr)) + { + ULARGE_INTEGER offset, length; + + offset.QuadPart = This->metadata_blocks[nIndex].offset; + length.QuadPart = This->metadata_blocks[nIndex].length; + hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream, + offset, length); + + if (SUCCEEDED(hr)) + hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory); + + if (SUCCEEDED(hr)) + { + hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, + &This->parent->decoder_info.block_format, NULL, This->metadata_blocks[nIndex].options, + (IStream*)stream, ppIMetadataReader); + + IWICComponentFactory_Release(factory); + } + + IWICStream_Release(stream); + } + + if (FAILED(hr)) + *ppIMetadataReader = NULL; + + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader *iface, + IEnumUnknown **ppIEnumMetadata) +{ + FIXME("%p,%p\n", iface, ppIEnumMetadata); + return E_NOTIMPL; +} + +static const IWICMetadataBlockReaderVtbl CommonDecoderFrame_BlockVtbl = { + CommonDecoderFrame_Block_QueryInterface, + CommonDecoderFrame_Block_AddRef, + CommonDecoderFrame_Block_Release, + CommonDecoderFrame_Block_GetContainerFormat, + CommonDecoderFrame_Block_GetCount, + CommonDecoderFrame_Block_GetReaderByIndex, + CommonDecoderFrame_Block_GetEnumerator, +}; + +static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, + UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr=S_OK; + CommonDecoderFrame *result; + + TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); + + if (!ppIBitmapFrame) + return E_POINTER; + + EnterCriticalSection(&This->lock); + + if (!This->stream || index >= This->file_info.frame_count) + hr = WINCODEC_ERR_FRAMEMISSING; + + if (SUCCEEDED(hr)) + { + result = HeapAlloc(GetProcessHeap(), 0, sizeof(*result)); + if (!result) + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + result->IWICBitmapFrameDecode_iface.lpVtbl = &CommonDecoderFrameVtbl; + result->IWICMetadataBlockReader_iface.lpVtbl = &CommonDecoderFrame_BlockVtbl; + result->ref = 1; + result->parent = This; + result->frame = index; + result->metadata_initialized = FALSE; + result->metadata_count = 0; + result->metadata_blocks = NULL; + + hr = decoder_get_frame_info(This->decoder, index, &result->decoder_frame); + + if (SUCCEEDED(hr) && This->cache_options == WICDecodeMetadataCacheOnLoad) + hr = CommonDecoderFrame_InitializeMetadata(result); + + if (FAILED(hr)) + HeapFree(GetProcessHeap(), 0, result); + } + + LeaveCriticalSection(&This->lock); + + if (SUCCEEDED(hr)) + { + TRACE("-> %ux%u, %u-bit pixelformat=%s res=%f,%f colors=%u contexts=%u\n", + result->decoder_frame.width, result->decoder_frame.height, + result->decoder_frame.bpp, wine_dbgstr_guid(&result->decoder_frame.pixel_format), + result->decoder_frame.dpix, result->decoder_frame.dpiy, + result->decoder_frame.num_colors, result->decoder_frame.num_color_contexts); + IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); + *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; + } + else + { + *ppIBitmapFrame = NULL; + } + + return hr; +} + +HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, + const struct decoder_info *decoder_info, REFIID iid, void** ppv) +{ + CommonDecoder *This; + HRESULT hr; + + TRACE("(%s,%s,%p)\n", debugstr_guid(&decoder_info->clsid), debugstr_guid(iid), ppv); + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + { + decoder_destroy(decoder); + return E_OUTOFMEMORY; + } + + This->IWICBitmapDecoder_iface.lpVtbl = &CommonDecoder_Vtbl; + This->ref = 1; + This->stream = NULL; + This->decoder = decoder; + This->decoder_info = *decoder_info; + InitializeCriticalSection(&This->lock); + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonDecoder.lock"); + + hr = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); + IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); + + return hr; +} + diff --git a/dlls/windowscodecs/pngformat.c b/dlls/windowscodecs/pngformat.c index efd5f6ab2c1..b36512447b2 100644 --- a/dlls/windowscodecs/pngformat.c +++ b/dlls/windowscodecs/pngformat.c @@ -392,795 +392,6 @@ 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; - struct decoder *png_decoder; - struct decoder_info decoder_info; - struct decoder_stat file_info; - struct decoder_frame decoder_frame; - png_structp png_ptr; - png_infop info_ptr; - png_infop end_info; - BOOL initialized; - int bpp; - int width, height; - UINT stride; - const WICPixelFormatGUID *format; - BYTE *image_bits; - CRITICAL_SECTION lock; /* must be held when png structures are accessed or initialized is set */ - ULONG metadata_count; - struct decoder_block* metadata_blocks; -} PngDecoder; - -static inline PngDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) -{ - return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapDecoder_iface); -} - -static inline PngDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) -{ - return CONTAINING_RECORD(iface, PngDecoder, IWICBitmapFrameDecode_iface); -} - -static inline PngDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) -{ - return CONTAINING_RECORD(iface, PngDecoder, IWICMetadataBlockReader_iface); -} - -static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl; - -static HRESULT WINAPI PngDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, - void **ppv) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); - - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) - { - *ppv = &This->IWICBitmapDecoder_iface; - } - else - { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI PngDecoder_AddRef(IWICBitmapDecoder *iface) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - ULONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) refcount=%u\n", iface, ref); - - return ref; -} - -static ULONG WINAPI PngDecoder_Release(IWICBitmapDecoder *iface) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - 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); - if (This->png_decoder) - decoder_destroy(This->png_decoder); - This->lock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&This->lock); - HeapFree(GetProcessHeap(), 0, This->image_bits); - HeapFree(GetProcessHeap(), 0, This->metadata_blocks); - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} - -static HRESULT WINAPI PngDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, - DWORD *capability) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - HRESULT hr; - - TRACE("(%p,%p,%p)\n", iface, stream, capability); - - if (!stream || !capability) return E_INVALIDARG; - - hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); - if (hr != S_OK) return hr; - - *capability = (This->file_info.flags & DECODER_FLAGS_CAPABILITY_MASK); - return S_OK; -} - -static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - IStream *stream = ppng_get_io_ptr(png_ptr); - HRESULT hr; - ULONG bytesread; - - hr = IStream_Read(stream, data, length, &bytesread); - if (FAILED(hr) || bytesread != length) - { - ppng_error(png_ptr, "failed reading data"); - } -} - -static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, - WICDecodeOptions cacheOptions) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - LARGE_INTEGER seek; - HRESULT hr=S_OK; - png_bytep *row_pointers=NULL; - UINT image_size; - UINT i; - int color_type, bit_depth; - png_bytep trans; - int num_trans; - png_uint_32 transparency; - png_color_16p trans_values; - jmp_buf jmpbuf; - - TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); - - EnterCriticalSection(&This->lock); - - if (This->initialized) - { - hr = WINCODEC_ERR_WRONGSTATE; - goto end; - } - - hr = decoder_initialize(This->png_decoder, pIStream, &This->file_info); - if (FAILED(hr)) - goto end; - - /* this function cannot fail in PNG decoder */ - decoder_get_frame_info(This->png_decoder, 0, &This->decoder_frame); - - /* initialize libpng */ - This->png_ptr = ppng_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!This->png_ptr) - { - hr = E_FAIL; - goto end; - } - - This->info_ptr = ppng_create_info_struct(This->png_ptr); - if (!This->info_ptr) - { - ppng_destroy_read_struct(&This->png_ptr, NULL, NULL); - This->png_ptr = NULL; - hr = E_FAIL; - goto end; - } - - This->end_info = ppng_create_info_struct(This->png_ptr); - if (!This->end_info) - { - ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, NULL); - This->png_ptr = NULL; - hr = E_FAIL; - goto end; - } - - /* set up setjmp/longjmp error handling */ - if (setjmp(jmpbuf)) - { - ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); - This->png_ptr = NULL; - hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT; - goto end; - } - ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); - ppng_set_crc_action(This->png_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - - /* seek to the start of the stream */ - seek.QuadPart = 0; - hr = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); - if (FAILED(hr)) goto end; - - /* set up custom i/o handling */ - ppng_set_read_fn(This->png_ptr, pIStream, user_read_data); - - /* read the header */ - ppng_read_info(This->png_ptr, This->info_ptr); - - /* choose a pixel format */ - color_type = ppng_get_color_type(This->png_ptr, This->info_ptr); - bit_depth = ppng_get_bit_depth(This->png_ptr, This->info_ptr); - - /* PNGs with bit-depth greater than 8 are network byte order. Windows does not expect this. */ - if (bit_depth > 8) - ppng_set_swap(This->png_ptr); - - /* check for color-keyed alpha */ - transparency = ppng_get_tRNS(This->png_ptr, This->info_ptr, &trans, &num_trans, &trans_values); - - if (transparency && (color_type == PNG_COLOR_TYPE_RGB || - (color_type == PNG_COLOR_TYPE_GRAY && bit_depth == 16))) - { - /* expand to RGBA */ - if (color_type == PNG_COLOR_TYPE_GRAY) - ppng_set_gray_to_rgb(This->png_ptr); - ppng_set_tRNS_to_alpha(This->png_ptr); - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - } - - switch (color_type) - { - case PNG_COLOR_TYPE_GRAY_ALPHA: - /* WIC does not support grayscale alpha formats so use RGBA */ - ppng_set_gray_to_rgb(This->png_ptr); - /* fall through */ - case PNG_COLOR_TYPE_RGB_ALPHA: - This->bpp = bit_depth * 4; - switch (bit_depth) - { - case 8: - ppng_set_bgr(This->png_ptr); - This->format = &GUID_WICPixelFormat32bppBGRA; - break; - case 16: This->format = &GUID_WICPixelFormat64bppRGBA; break; - default: - ERR("invalid RGBA bit depth: %i\n", bit_depth); - hr = E_FAIL; - goto end; - } - break; - case PNG_COLOR_TYPE_GRAY: - This->bpp = bit_depth; - if (!transparency) - { - switch (bit_depth) - { - case 1: This->format = &GUID_WICPixelFormatBlackWhite; break; - case 2: This->format = &GUID_WICPixelFormat2bppGray; break; - case 4: This->format = &GUID_WICPixelFormat4bppGray; break; - case 8: This->format = &GUID_WICPixelFormat8bppGray; break; - case 16: This->format = &GUID_WICPixelFormat16bppGray; break; - default: - ERR("invalid grayscale bit depth: %i\n", bit_depth); - hr = E_FAIL; - goto end; - } - break; - } - /* else fall through */ - case PNG_COLOR_TYPE_PALETTE: - This->bpp = bit_depth; - switch (bit_depth) - { - case 1: This->format = &GUID_WICPixelFormat1bppIndexed; break; - case 2: This->format = &GUID_WICPixelFormat2bppIndexed; break; - case 4: This->format = &GUID_WICPixelFormat4bppIndexed; break; - case 8: This->format = &GUID_WICPixelFormat8bppIndexed; break; - default: - ERR("invalid indexed color bit depth: %i\n", bit_depth); - hr = E_FAIL; - goto end; - } - break; - case PNG_COLOR_TYPE_RGB: - This->bpp = bit_depth * 3; - switch (bit_depth) - { - case 8: - ppng_set_bgr(This->png_ptr); - This->format = &GUID_WICPixelFormat24bppBGR; - break; - case 16: This->format = &GUID_WICPixelFormat48bppRGB; break; - default: - ERR("invalid RGB color bit depth: %i\n", bit_depth); - hr = E_FAIL; - goto end; - } - break; - default: - ERR("invalid color type %i\n", color_type); - hr = E_FAIL; - goto end; - } - - /* read the image data */ - This->width = ppng_get_image_width(This->png_ptr, This->info_ptr); - This->height = ppng_get_image_height(This->png_ptr, This->info_ptr); - This->stride = (This->width * This->bpp + 7) / 8; - image_size = This->stride * This->height; - - This->image_bits = HeapAlloc(GetProcessHeap(), 0, image_size); - if (!This->image_bits) - { - hr = E_OUTOFMEMORY; - goto end; - } - - row_pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(png_bytep)*This->height); - if (!row_pointers) - { - hr = E_OUTOFMEMORY; - goto end; - } - - for (i=0; i<This->height; i++) - row_pointers[i] = This->image_bits + i * This->stride; - - ppng_read_image(This->png_ptr, row_pointers); - - HeapFree(GetProcessHeap(), 0, row_pointers); - row_pointers = NULL; - - ppng_read_end(This->png_ptr, This->end_info); - - decoder_get_metadata_blocks(This->png_decoder, 0, &This->metadata_count, &This->metadata_blocks); - - This->stream = pIStream; - IStream_AddRef(This->stream); - - This->initialized = TRUE; - -end: - LeaveCriticalSection(&This->lock); - - HeapFree(GetProcessHeap(), 0, row_pointers); - - return hr; -} - -static HRESULT WINAPI PngDecoder_GetContainerFormat(IWICBitmapDecoder *iface, - GUID *pguidContainerFormat) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - memcpy(pguidContainerFormat, &This->decoder_info.container_format, sizeof(GUID)); - return S_OK; -} - -static HRESULT WINAPI PngDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, - IWICBitmapDecoderInfo **ppIDecoderInfo) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - TRACE("(%p,%p)\n", iface, ppIDecoderInfo); - - return get_decoder_info(&This->decoder_info.clsid, ppIDecoderInfo); -} - -static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface, - IWICPalette *palette) -{ - TRACE("(%p,%p)\n", iface, palette); - return WINCODEC_ERR_PALETTEUNAVAILABLE; -} - -static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, - IWICMetadataQueryReader **reader) -{ - TRACE("(%p,%p)\n", iface, reader); - - if (!reader) return E_INVALIDARG; - - *reader = NULL; - return WINCODEC_ERR_UNSUPPORTEDOPERATION; -} - -static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface, - IWICBitmapSource **ppIBitmapSource) -{ - TRACE("(%p,%p)\n", iface, ppIBitmapSource); - - if (!ppIBitmapSource) return E_INVALIDARG; - - *ppIBitmapSource = NULL; - return WINCODEC_ERR_UNSUPPORTEDOPERATION; -} - -static HRESULT WINAPI PngDecoder_GetColorContexts(IWICBitmapDecoder *iface, - UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) -{ - TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); - return WINCODEC_ERR_UNSUPPORTEDOPERATION; -} - -static HRESULT WINAPI PngDecoder_GetThumbnail(IWICBitmapDecoder *iface, - IWICBitmapSource **ppIThumbnail) -{ - TRACE("(%p,%p)\n", iface, ppIThumbnail); - - if (!ppIThumbnail) return E_INVALIDARG; - - *ppIThumbnail = NULL; - return WINCODEC_ERR_CODECNOTHUMBNAIL; -} - -static HRESULT WINAPI PngDecoder_GetFrameCount(IWICBitmapDecoder *iface, - UINT *pCount) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - if (!pCount) return E_INVALIDARG; - - if (!This->initialized) return WINCODEC_ERR_WRONGSTATE; - - *pCount = This->file_info.frame_count; - return S_OK; -} - -static HRESULT WINAPI PngDecoder_GetFrame(IWICBitmapDecoder *iface, - UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) -{ - PngDecoder *This = impl_from_IWICBitmapDecoder(iface); - TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); - - if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING; - - if (index != 0) return E_INVALIDARG; - - IWICBitmapDecoder_AddRef(iface); - - *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface; - - return S_OK; -} - -static const IWICBitmapDecoderVtbl PngDecoder_Vtbl = { - PngDecoder_QueryInterface, - PngDecoder_AddRef, - PngDecoder_Release, - PngDecoder_QueryCapability, - PngDecoder_Initialize, - PngDecoder_GetContainerFormat, - PngDecoder_GetDecoderInfo, - PngDecoder_CopyPalette, - PngDecoder_GetMetadataQueryReader, - PngDecoder_GetPreview, - PngDecoder_GetColorContexts, - PngDecoder_GetThumbnail, - PngDecoder_GetFrameCount, - PngDecoder_GetFrame -}; - -static HRESULT WINAPI PngDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, - void **ppv) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid) || - IsEqualIID(&IID_IWICBitmapSource, iid) || - IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) - { - *ppv = &This->IWICBitmapFrameDecode_iface; - } - else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid)) - { - *ppv = &This->IWICMetadataBlockReader_iface; - } - else - { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI PngDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); -} - -static ULONG WINAPI PngDecoder_Frame_Release(IWICBitmapFrameDecode *iface) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); -} - -static HRESULT WINAPI PngDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface, - UINT *puiWidth, UINT *puiHeight) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - *puiWidth = This->decoder_frame.width; - *puiHeight = This->decoder_frame.height; - TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight); - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface, - WICPixelFormatGUID *pPixelFormat) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - TRACE("(%p,%p)\n", iface, pPixelFormat); - - memcpy(pPixelFormat, &This->decoder_frame.pixel_format, sizeof(GUID)); - - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface, - double *pDpiX, double *pDpiY) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - - *pDpiX = This->decoder_frame.dpix; - *pDpiY = This->decoder_frame.dpiy; - - TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY); - - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface, - IWICPalette *pIPalette) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - HRESULT hr=S_OK; - - TRACE("(%p,%p)\n", iface, pIPalette); - - if (This->decoder_frame.num_colors) - { - hr = IWICPalette_InitializeCustom(pIPalette, This->decoder_frame.palette, This->decoder_frame.num_colors); - } - else - { - hr = WINCODEC_ERR_PALETTEUNAVAILABLE; - } - - return hr; -} - -static HRESULT WINAPI PngDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, - const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); - - return decoder_copy_pixels(This->png_decoder, 0, - prc, cbStride, cbBufferSize, pbBuffer); -} - -static HRESULT WINAPI PngDecoder_Frame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, - IWICMetadataQueryReader **ppIMetadataQueryReader) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - - TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); - - if (!ppIMetadataQueryReader) - return E_INVALIDARG; - - return MetadataQueryReader_CreateInstance(&This->IWICMetadataBlockReader_iface, NULL, ppIMetadataQueryReader); -} - -static HRESULT WINAPI PngDecoder_Frame_GetColorContexts(IWICBitmapFrameDecode *iface, - UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) -{ - PngDecoder *This = impl_from_IWICBitmapFrameDecode(iface); - HRESULT hr=S_OK; - BYTE *profile; - DWORD profile_len; - - TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); - - if (!pcActualCount) return E_INVALIDARG; - - *pcActualCount = This->decoder_frame.num_color_contexts; - - if (This->decoder_frame.num_color_contexts && cCount && ppIColorContexts) - { - EnterCriticalSection(&This->lock); - - hr = decoder_get_color_context(This->png_decoder, 0, 0, - &profile, &profile_len); - - LeaveCriticalSection(&This->lock); - - if (SUCCEEDED(hr)) - { - hr = IWICColorContext_InitializeFromMemory(*ppIColorContexts, profile, profile_len); - - HeapFree(GetProcessHeap(), 0, profile); - } - } - - return hr; -} - -static HRESULT WINAPI PngDecoder_Frame_GetThumbnail(IWICBitmapFrameDecode *iface, - IWICBitmapSource **ppIThumbnail) -{ - TRACE("(%p,%p)\n", iface, ppIThumbnail); - - if (!ppIThumbnail) return E_INVALIDARG; - - *ppIThumbnail = NULL; - return WINCODEC_ERR_CODECNOTHUMBNAIL; -} - -static const IWICBitmapFrameDecodeVtbl PngDecoder_FrameVtbl = { - PngDecoder_Frame_QueryInterface, - PngDecoder_Frame_AddRef, - PngDecoder_Frame_Release, - PngDecoder_Frame_GetSize, - PngDecoder_Frame_GetPixelFormat, - PngDecoder_Frame_GetResolution, - PngDecoder_Frame_CopyPalette, - PngDecoder_Frame_CopyPixels, - PngDecoder_Frame_GetMetadataQueryReader, - PngDecoder_Frame_GetColorContexts, - PngDecoder_Frame_GetThumbnail -}; - -static HRESULT WINAPI PngDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, - void **ppv) -{ - PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); -} - -static ULONG WINAPI PngDecoder_Block_AddRef(IWICMetadataBlockReader *iface) -{ - PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); -} - -static ULONG WINAPI PngDecoder_Block_Release(IWICMetadataBlockReader *iface) -{ - PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); - return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); -} - -static HRESULT WINAPI PngDecoder_Block_GetContainerFormat(IWICMetadataBlockReader *iface, - GUID *pguidContainerFormat) -{ - PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); - if (!pguidContainerFormat) return E_INVALIDARG; - memcpy(pguidContainerFormat, &This->decoder_info.block_format, sizeof(GUID)); - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Block_GetCount(IWICMetadataBlockReader *iface, - UINT *pcCount) -{ - PngDecoder *This = impl_from_IWICMetadataBlockReader(iface); - - TRACE("%p,%p\n", iface, pcCount); - - if (!pcCount) return E_INVALIDARG; - - *pcCount = This->metadata_count; - - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, - UINT nIndex, IWICMetadataReader **ppIMetadataReader) -{ - 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; - - hr = StreamImpl_Create(&stream); - - if (SUCCEEDED(hr)) - { - ULARGE_INTEGER offset, length; - - offset.QuadPart = This->metadata_blocks[nIndex].offset; - length.QuadPart = This->metadata_blocks[nIndex].length; - hr = IWICStream_InitializeFromIStreamRegion(stream, This->stream, - offset, length); - - if (SUCCEEDED(hr)) - hr = ImagingFactory_CreateInstance(&IID_IWICComponentFactory, (void**)&factory); - - if (SUCCEEDED(hr)) - { - hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, - &GUID_ContainerFormatPng, NULL, This->metadata_blocks[nIndex].options, - (IStream*)stream, ppIMetadataReader); - - IWICComponentFactory_Release(factory); - } - - IWICStream_Release(stream); - } - - if (FAILED(hr)) - *ppIMetadataReader = NULL; - - return S_OK; -} - -static HRESULT WINAPI PngDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface, - IEnumUnknown **ppIEnumMetadata) -{ - FIXME("%p,%p\n", iface, ppIEnumMetadata); - return E_NOTIMPL; -} - -static const IWICMetadataBlockReaderVtbl PngDecoder_BlockVtbl = { - PngDecoder_Block_QueryInterface, - PngDecoder_Block_AddRef, - PngDecoder_Block_Release, - PngDecoder_Block_GetContainerFormat, - PngDecoder_Block_GetCount, - PngDecoder_Block_GetReaderByIndex, - PngDecoder_Block_GetEnumerator, -}; - -HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) -{ - PngDecoder *This; - HRESULT ret; - - TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); - - *ppv = NULL; - - if (!load_libpng()) - { - ERR("Failed reading PNG because unable to find %s\n",SONAME_LIBPNG); - return E_FAIL; - } - - This = HeapAlloc(GetProcessHeap(), 0, sizeof(PngDecoder)); - if (!This) return E_OUTOFMEMORY; - - ret = get_unix_decoder(&CLSID_WICPngDecoder, &This->decoder_info, &This->png_decoder); - if (FAILED(ret)) - { - HeapFree(GetProcessHeap(), 0, This); - return ret; - } - - This->IWICBitmapDecoder_iface.lpVtbl = &PngDecoder_Vtbl; - This->IWICBitmapFrameDecode_iface.lpVtbl = &PngDecoder_FrameVtbl; - This->IWICMetadataBlockReader_iface.lpVtbl = &PngDecoder_BlockVtbl; - This->ref = 1; - 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); - - return ret; -} - struct png_pixelformat { const WICPixelFormatGUID *guid; UINT bpp; @@ -2034,12 +1245,6 @@ HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv)
#else /* !SONAME_LIBPNG */
-HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) -{ - ERR("Trying to load PNG picture, but PNG support is not compiled in.\n"); - return E_FAIL; -} - HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) { ERR("Trying to save PNG picture, but PNG support is not compiled in.\n"); @@ -2047,3 +1252,18 @@ HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) }
#endif + +HRESULT PngDecoder_CreateInstance(REFIID iid, void** ppv) +{ + HRESULT hr; + struct decoder *decoder; + struct decoder_info decoder_info; + + hr = get_unix_decoder(&CLSID_WICPngDecoder, &decoder_info, &decoder); + + if (SUCCEEDED(hr)) + hr = CommonDecoder_CreateInstance(decoder, &decoder_info, iid, ppv); + + return hr; +} + diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index e5294b8cf1a..2cdd1066eb7 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -343,4 +343,7 @@ struct unix_funcs
HRESULT get_unix_decoder(const CLSID *decoder_clsid, struct decoder_info *info, struct decoder **result);
+extern HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, + const struct decoder_info *decoder_info, REFIID iid, void** ppv) DECLSPEC_HIDDEN; + #endif /* WINCODECS_PRIVATE_H */