[WINDOWSCODECS]
authorAmine Khaldi <amine.khaldi@reactos.org>
Tue, 11 Dec 2012 21:17:47 +0000 (21:17 +0000)
committerAmine Khaldi <amine.khaldi@reactos.org>
Tue, 11 Dec 2012 21:17:47 +0000 (21:17 +0000)
* Sync with Wine 1.5.19.
[PSDK]
* Update some headers.
* Import wincodecsdk.idl from Wine.

svn path=/trunk/; revision=57881

38 files changed:
reactos/dll/win32/windowscodecs/CMakeLists.txt
reactos/dll/win32/windowscodecs/bitmap.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/bmpdecode.c
reactos/dll/win32/windowscodecs/bmpencode.c
reactos/dll/win32/windowscodecs/clsfactory.c
reactos/dll/win32/windowscodecs/colorcontext.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/converter.c
reactos/dll/win32/windowscodecs/fliprotate.c
reactos/dll/win32/windowscodecs/gifformat.c
reactos/dll/win32/windowscodecs/icnsformat.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/icoformat.c
reactos/dll/win32/windowscodecs/imgfactory.c
reactos/dll/win32/windowscodecs/info.c
reactos/dll/win32/windowscodecs/jpegformat.c
reactos/dll/win32/windowscodecs/main.c
reactos/dll/win32/windowscodecs/metadatahandler.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/palette.c
reactos/dll/win32/windowscodecs/pngformat.c
reactos/dll/win32/windowscodecs/propertybag.c
reactos/dll/win32/windowscodecs/proxy.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/regsvr.c
reactos/dll/win32/windowscodecs/scaler.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/stream.c
reactos/dll/win32/windowscodecs/tgaformat.c [new file with mode: 0644]
reactos/dll/win32/windowscodecs/tiffformat.c
reactos/dll/win32/windowscodecs/typeof.h
reactos/dll/win32/windowscodecs/ungif.c
reactos/dll/win32/windowscodecs/ungif.h
reactos/dll/win32/windowscodecs/version.rc
reactos/dll/win32/windowscodecs/wincodecs_private.h
reactos/dll/win32/windowscodecs/windowscodecs.spec
reactos/dll/win32/windowscodecs/windowscodecs_wincodec.idl [new file with mode: 0644]
reactos/dll/win32/windowscodecs/windowscodecs_wincodec.rgs [new file with mode: 0644]
reactos/include/psdk/CMakeLists.txt
reactos/include/psdk/wincodec.idl
reactos/include/psdk/wincodecsdk.idl [new file with mode: 0644]
reactos/include/psdk/winternl.h
reactos/media/doc/README.WINE

index 75f3e9a..ee60b10 100644 (file)
@@ -1,5 +1,9 @@
 
-add_definitions(-D__WINESRC__)
+add_definitions(
+    -D__WINESRC__
+    -DENTRY_PREFIX=WIC_
+    -DPROXY_DELEGATION
+    -DWINE_REGISTER_DLL)
 
 remove_definitions(-D_WIN32_WINNT=0x502)
 add_definitions(-D_WIN32_WINNT=0x600)
@@ -17,32 +21,47 @@ endif()
 
 spec2def(windowscodecs.dll windowscodecs.spec ADD_IMPORTLIB)
 
+add_rpcproxy_files(windowscodecs_wincodec.idl)
+
 list(APPEND SOURCE
+    bitmap.c
     bmpdecode.c
     bmpencode.c
     clsfactory.c
+    colorcontext.c
     converter.c
     fliprotate.c
     gifformat.c
+    icnsformat.c
     icoformat.c
     imgfactory.c
     info.c
     jpegformat.c
     main.c
+    metadatahandler.c
     palette.c
     pngformat.c
     propertybag.c
+    proxy.c
     regsvr.c
+    scaler.c
     stream.c
+    tgaformat.c
     tiffformat.c
     ungif.c
-    version.rc
+    ${CMAKE_CURRENT_BINARY_DIR}/proxy.dlldata.c
     ${CMAKE_CURRENT_BINARY_DIR}/windowscodecs_stubs.c
-    ${CMAKE_CURRENT_BINARY_DIR}/windowscodecs.def)
+    ${CMAKE_CURRENT_BINARY_DIR}/windowscodecs.def
+    ${CMAKE_CURRENT_BINARY_DIR}/windowscodecs_wincodec_p.c)
 
-add_library(windowscodecs SHARED ${SOURCE})
-set_module_type(windowscodecs win32dll)
-target_link_libraries(windowscodecs wine uuid)
-add_importlibs(windowscodecs ole32 shlwapi advapi32 msvcrt kernel32 ntdll)
+if(NOT MSVC)
+    # FIXME: http://www.cmake.org/Bug/view.php?id=12998
+    #allow_warnings(windowscodecs)
+    set_source_files_properties(${SOURCE} PROPERTIES COMPILE_FLAGS "-Wno-error")
+endif()
 
+add_library(windowscodecs SHARED ${SOURCE} version.rc)
+set_module_type(windowscodecs win32dll)
+target_link_libraries(windowscodecs wine uuid ${PSEH_LIB})
+add_importlibs(windowscodecs ole32 oleaut32 shlwapi advapi32 rpcrt4 msvcrt kernel32 ntdll)
 add_cd_file(TARGET windowscodecs DESTINATION reactos/system32 FOR all)
diff --git a/reactos/dll/win32/windowscodecs/bitmap.c b/reactos/dll/win32/windowscodecs/bitmap.c
new file mode 100644 (file)
index 0000000..520fdef
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * Copyright 2012 Vincent Povirk for CodeWeavers
+ *
+ * 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 <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct BitmapImpl {
+    IWICBitmap IWICBitmap_iface;
+    LONG ref;
+    IWICPalette *palette;
+    int palette_set;
+    LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */
+    BYTE *data;
+    UINT width, height;
+    UINT stride;
+    UINT bpp;
+    WICPixelFormatGUID pixelformat;
+    double dpix, dpiy;
+    CRITICAL_SECTION cs;
+} BitmapImpl;
+
+typedef struct BitmapLockImpl {
+    IWICBitmapLock IWICBitmapLock_iface;
+    LONG ref;
+    BitmapImpl *parent;
+    UINT width, height;
+    BYTE *data;
+} BitmapLockImpl;
+
+static inline BitmapImpl *impl_from_IWICBitmap(IWICBitmap *iface)
+{
+    return CONTAINING_RECORD(iface, BitmapImpl, IWICBitmap_iface);
+}
+
+static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface)
+{
+    return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface);
+}
+
+static BOOL BitmapImpl_AcquireLock(BitmapImpl *This, int write)
+{
+    if (write)
+    {
+        return 0 == InterlockedCompareExchange(&This->lock, -1, 0);
+    }
+    else
+    {
+        while (1)
+        {
+            LONG prev_val = This->lock;
+            if (prev_val == -1)
+                return FALSE;
+            if (prev_val == InterlockedCompareExchange(&This->lock, prev_val+1, prev_val))
+                return TRUE;
+        }
+    }
+}
+
+static void BitmapImpl_ReleaseLock(BitmapImpl *This)
+{
+    while (1)
+    {
+        LONG prev_val = This->lock, new_val;
+        if (prev_val == -1)
+            new_val = 0;
+        else
+            new_val = prev_val - 1;
+        if (prev_val == InterlockedCompareExchange(&This->lock, new_val, prev_val))
+            break;
+    }
+}
+
+
+static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFIID iid,
+    void **ppv)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapLock, iid))
+    {
+        *ppv = &This->IWICBitmapLock_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        BitmapImpl_ReleaseLock(This->parent);
+        IWICBitmap_Release(&This->parent->IWICBitmap_iface);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BitmapLockImpl_GetSize(IWICBitmapLock *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
+
+    if (!puiWidth || !puiHeight)
+        return E_INVALIDARG;
+
+    *puiWidth = This->width;
+    *puiHeight = This->height;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapLockImpl_GetStride(IWICBitmapLock *iface,
+    UINT *pcbStride)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    TRACE("(%p,%p)\n", iface, pcbStride);
+
+    if (!pcbStride)
+        return E_INVALIDARG;
+
+    *pcbStride = This->parent->stride;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapLockImpl_GetDataPointer(IWICBitmapLock *iface,
+    UINT *pcbBufferSize, BYTE **ppbData)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    TRACE("(%p,%p,%p)\n", iface, pcbBufferSize, ppbData);
+
+    if (!pcbBufferSize || !ppbData)
+        return E_INVALIDARG;
+
+    *pcbBufferSize = This->parent->stride * (This->height - 1) +
+        ((This->parent->bpp * This->width) + 7)/8;
+    *ppbData = This->data;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapLockImpl_GetPixelFormat(IWICBitmapLock *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    BitmapLockImpl *This = impl_from_IWICBitmapLock(iface);
+    TRACE("(%p,%p)\n", iface, pPixelFormat);
+
+    return IWICBitmap_GetPixelFormat(&This->parent->IWICBitmap_iface, pPixelFormat);
+}
+
+static const IWICBitmapLockVtbl BitmapLockImpl_Vtbl = {
+    BitmapLockImpl_QueryInterface,
+    BitmapLockImpl_AddRef,
+    BitmapLockImpl_Release,
+    BitmapLockImpl_GetSize,
+    BitmapLockImpl_GetStride,
+    BitmapLockImpl_GetDataPointer,
+    BitmapLockImpl_GetPixelFormat
+};
+
+static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid,
+    void **ppv)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapSource, iid) ||
+        IsEqualIID(&IID_IWICBitmap, iid))
+    {
+        *ppv = &This->IWICBitmap_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (This->palette) IWICPalette_Release(This->palette);
+        This->cs.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&This->cs);
+        HeapFree(GetProcessHeap(), 0, This->data);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BitmapImpl_GetSize(IWICBitmap *iface,
+    UINT *puiWidth, UINT *puiHeight)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
+
+    if (!puiWidth || !puiHeight)
+        return E_INVALIDARG;
+
+    *puiWidth = This->width;
+    *puiHeight = This->height;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapImpl_GetPixelFormat(IWICBitmap *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%p)\n", iface, pPixelFormat);
+
+    if (!pPixelFormat)
+        return E_INVALIDARG;
+
+    memcpy(pPixelFormat, &This->pixelformat, sizeof(GUID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapImpl_GetResolution(IWICBitmap *iface,
+    double *pDpiX, double *pDpiY)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
+
+    if (!pDpiX || !pDpiY)
+        return E_INVALIDARG;
+
+    EnterCriticalSection(&This->cs);
+    *pDpiX = This->dpix;
+    *pDpiY = This->dpiy;
+    LeaveCriticalSection(&This->cs);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapImpl_CopyPalette(IWICBitmap *iface,
+    IWICPalette *pIPalette)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    if (!This->palette_set)
+        return WINCODEC_ERR_PALETTEUNAVAILABLE;
+
+    return IWICPalette_InitializeFromPalette(pIPalette, This->palette);
+}
+
+static HRESULT WINAPI BitmapImpl_CopyPixels(IWICBitmap *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    return copy_pixels(This->bpp, This->data, This->width, This->height,
+        This->stride, prc, cbStride, cbBufferSize, pbBuffer);
+}
+
+static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock,
+    DWORD flags, IWICBitmapLock **ppILock)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    BitmapLockImpl *result;
+    WICRect rc;
+
+    TRACE("(%p,%p,%x,%p)\n", iface, prcLock, flags, ppILock);
+
+    if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock)
+        return E_INVALIDARG;
+
+    if (!prcLock)
+    {
+        rc.X = rc.Y = 0;
+        rc.Width = This->width;
+        rc.Height = This->height;
+        prcLock = &rc;
+    }
+    else if (prcLock->X >= This->width || prcLock->Y >= This->height ||
+             prcLock->X + prcLock->Width > This->width ||
+             prcLock->Y + prcLock->Height > This->height ||
+             prcLock->Width <= 0 || prcLock->Height <= 0)
+        return E_INVALIDARG;
+    else if (((prcLock->X * This->bpp) % 8) != 0)
+    {
+        FIXME("Cannot lock at an X coordinate not at a full byte\n");
+        return E_FAIL;
+    }
+
+    result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl));
+    if (!result)
+        return E_OUTOFMEMORY;
+
+    if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite))
+    {
+        HeapFree(GetProcessHeap(), 0, result);
+        return WINCODEC_ERR_ALREADYLOCKED;
+    }
+
+    result->IWICBitmapLock_iface.lpVtbl = &BitmapLockImpl_Vtbl;
+    result->ref = 1;
+    result->parent = This;
+    result->width = prcLock->Width;
+    result->height = prcLock->Height;
+    result->data = This->data + This->stride * prcLock->Y +
+        (This->bpp * prcLock->X)/8;
+
+    IWICBitmap_AddRef(&This->IWICBitmap_iface);
+    *ppILock = &result->IWICBitmapLock_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapImpl_SetPalette(IWICBitmap *iface, IWICPalette *pIPalette)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    HRESULT hr;
+
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    if (!This->palette)
+    {
+        IWICPalette *new_palette;
+        hr = PaletteImpl_Create(&new_palette);
+
+        if (FAILED(hr)) return hr;
+
+        if (InterlockedCompareExchangePointer((void**)&This->palette, new_palette, NULL))
+        {
+            /* someone beat us to it */
+            IWICPalette_Release(new_palette);
+        }
+    }
+
+    hr = IWICPalette_InitializeFromPalette(This->palette, pIPalette);
+
+    if (SUCCEEDED(hr))
+        This->palette_set = 1;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapImpl_SetResolution(IWICBitmap *iface,
+    double dpiX, double dpiY)
+{
+    BitmapImpl *This = impl_from_IWICBitmap(iface);
+    TRACE("(%p,%f,%f)\n", iface, dpiX, dpiY);
+
+    EnterCriticalSection(&This->cs);
+    This->dpix = dpiX;
+    This->dpiy = dpiY;
+    LeaveCriticalSection(&This->cs);
+
+    return S_OK;
+}
+
+static const IWICBitmapVtbl BitmapImpl_Vtbl = {
+    BitmapImpl_QueryInterface,
+    BitmapImpl_AddRef,
+    BitmapImpl_Release,
+    BitmapImpl_GetSize,
+    BitmapImpl_GetPixelFormat,
+    BitmapImpl_GetResolution,
+    BitmapImpl_CopyPalette,
+    BitmapImpl_CopyPixels,
+    BitmapImpl_Lock,
+    BitmapImpl_SetPalette,
+    BitmapImpl_SetResolution
+};
+
+HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight,
+    REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option,
+    IWICBitmap **ppIBitmap)
+{
+    HRESULT hr;
+    BitmapImpl *This;
+    UINT bpp, stride, datasize;
+    BYTE *data;
+
+    hr = get_pixelformat_bpp(pixelFormat, &bpp);
+    if (FAILED(hr)) return hr;
+
+    stride = (((bpp*uiWidth)+31)/32)*4;
+    datasize = stride * uiHeight;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl));
+    data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize);
+    if (!This || !data)
+    {
+        HeapFree(GetProcessHeap(), 0, This);
+        HeapFree(GetProcessHeap(), 0, data);
+        return E_OUTOFMEMORY;
+    }
+
+    This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl;
+    This->ref = 1;
+    This->palette = NULL;
+    This->palette_set = 0;
+    This->lock = 0;
+    This->data = data;
+    This->width = uiWidth;
+    This->height = uiHeight;
+    This->stride = stride;
+    This->bpp = bpp;
+    memcpy(&This->pixelformat, pixelFormat, sizeof(GUID));
+    This->dpix = This->dpiy = 0.0;
+    InitializeCriticalSection(&This->cs);
+    This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock");
+
+    *ppIBitmap = &This->IWICBitmap_iface;
+
+    return S_OK;
+}
index 9cdc8e5..e029369 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <stdarg.h>
 
 #define COBJMACROS
@@ -58,16 +59,16 @@ typedef struct {
     DWORD bc2AppData;
 } BITMAPCOREHEADER2;
 
-struct BmpDecoder;
-typedef HRESULT (*ReadDataFunc)(struct BmpDecoder* This);
+typedef HRESULT (*ReadDataFunc)(BmpDecoder* This);
 
-typedef struct BmpDecoder {
-    const IWICBitmapDecoderVtbl *lpVtbl;
-    const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
+struct BmpDecoder {
+    IWICBitmapDecoder IWICBitmapDecoder_iface;
+    IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
     LONG ref;
     BOOL initialized;
     IStream *stream;
-    BITMAPFILEHEADER bfh;
+    ULONG palette_offset;
+    ULONG image_offset;
     BITMAPV5HEADER bih;
     const WICPixelFormatGUID *pixelformat;
     int bitsperpixel;
@@ -76,16 +77,25 @@ typedef struct BmpDecoder {
     BYTE *imagedata;
     BYTE *imagedatastart;
     CRITICAL_SECTION lock; /* must be held when initialized/imagedata is set or stream is accessed */
-} BmpDecoder;
+    int packed; /* If TRUE, don't look for a file header and assume a packed DIB. */
+    int icoframe; /* If TRUE, this is a frame of a .ico file. */
+};
+
+static inline BmpDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
+{
+    return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapDecoder_iface);
+}
 
-static inline BmpDecoder *impl_from_frame(IWICBitmapFrameDecode *iface)
+static inline BmpDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
 {
-    return CONTAINING_RECORD(iface, BmpDecoder, lpFrameVtbl);
+    return CONTAINING_RECORD(iface, BmpDecoder, IWICBitmapFrameDecode_iface);
 }
 
 static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
     void **ppv)
 {
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
+
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -94,7 +104,7 @@ static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
     {
-        *ppv = iface;
+        *ppv = &This->IWICBitmapFrameDecode_iface;
     }
     else
     {
@@ -108,22 +118,22 @@ static HRESULT WINAPI BmpFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
 
 static ULONG WINAPI BmpFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
 
-    return IUnknown_AddRef((IUnknown*)This);
+    return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
 }
 
 static ULONG WINAPI BmpFrameDecode_Release(IWICBitmapFrameDecode *iface)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
 
-    return IUnknown_Release((IUnknown*)This);
+    return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 }
 
 static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
 
     if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
@@ -143,7 +153,7 @@ static HRESULT WINAPI BmpFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
 static HRESULT WINAPI BmpFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface,
     WICPixelFormatGUID *pPixelFormat)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p)\n", iface, pPixelFormat);
 
     memcpy(pPixelFormat, This->pixelformat, sizeof(GUID));
@@ -174,7 +184,7 @@ static HRESULT BmpHeader_GetResolution(BITMAPV5HEADER *bih, double *pDpiX, doubl
 static HRESULT WINAPI BmpFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
     double *pDpiX, double *pDpiY)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
 
     return BmpHeader_GetResolution(&This->bih, pDpiX, pDpiY);
@@ -184,7 +194,7 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
     IWICPalette *pIPalette)
 {
     HRESULT hr;
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     int count;
     WICColor *wiccolors=NULL;
     RGBTRIPLE *bgrcolors=NULL;
@@ -213,7 +223,7 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
                 goto end;
             }
 
-            offset.QuadPart = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPCOREHEADER);
+            offset.QuadPart = This->palette_offset;
             hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
             if (FAILED(hr)) goto end;
 
@@ -259,7 +269,7 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
                 goto end;
             }
 
-            offset.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+            offset.QuadPart = This->palette_offset;
             hr = IStream_Seek(This->stream, offset, STREAM_SEEK_SET, NULL);
             if (FAILED(hr)) goto end;
 
@@ -296,7 +306,7 @@ end:
 static HRESULT WINAPI BmpFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    BmpDecoder *This = impl_from_frame(iface);
+    BmpDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     HRESULT hr=S_OK;
     UINT width, height;
     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
@@ -369,7 +379,7 @@ static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This)
     This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize);
     if (!This->imagedata) return E_OUTOFMEMORY;
 
-    offbits.QuadPart = This->bfh.bfOffBits;
+    offbits.QuadPart = This->image_offset;
     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) goto fail;
 
@@ -395,6 +405,27 @@ fail:
     return hr;
 }
 
+static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This)
+{
+    HRESULT hr;
+    UINT width, height;
+
+    hr = IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = BmpFrameDecode_ReadUncompressed(This);
+    }
+
+    if (SUCCEEDED(hr))
+    {
+        reverse_bgr8(This->bitsperpixel/8, This->imagedatastart,
+            width, height, This->stride);
+    }
+
+    return hr;
+}
+
 static HRESULT ReadByte(IStream *stream, BYTE *buffer, ULONG buffer_size,
     ULONG *cursor, ULONG *bytesread, BYTE *result)
 {
@@ -447,7 +478,7 @@ static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
     }
 
     /* read palette */
-    offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+    offbits.QuadPart = This->palette_offset;
     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) goto fail;
 
@@ -455,7 +486,7 @@ static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This)
     if (FAILED(hr) || bytesread != palettesize) goto fail;
 
     /* read RLE data */
-    offbits.QuadPart = This->bfh.bfOffBits;
+    offbits.QuadPart = This->image_offset;
     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) goto fail;
 
@@ -571,7 +602,7 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
     }
 
     /* read palette */
-    offbits.QuadPart = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+    offbits.QuadPart = This->palette_offset;
     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) goto fail;
 
@@ -579,7 +610,7 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This)
     if (FAILED(hr) || bytesread != palettesize) goto fail;
 
     /* read RLE data */
-    offbits.QuadPart = This->bfh.bfOffBits;
+    offbits.QuadPart = This->image_offset;
     hr = IStream_Seek(This->stream, offbits, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) goto fail;
 
@@ -701,6 +732,7 @@ static const struct bitfields_format bitfields_formats[] = {
     {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed},
     {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed},
     {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed},
+    {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8},
     {0}
 };
 
@@ -730,10 +762,15 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
     hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
     if (FAILED(hr)) return hr;
 
-    hr = IStream_Read(stream, &This->bfh, sizeof(BITMAPFILEHEADER), &bytesread);
-    if (FAILED(hr)) return hr;
-    if (bytesread != sizeof(BITMAPFILEHEADER) ||
-        This->bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
+    if (!This->packed)
+    {
+        BITMAPFILEHEADER bfh;
+        hr = IStream_Read(stream, &bfh, sizeof(BITMAPFILEHEADER), &bytesread);
+        if (FAILED(hr)) return hr;
+        if (bytesread != sizeof(BITMAPFILEHEADER) ||
+            bfh.bfType != 0x4d42 /* "BM" */) return E_FAIL;
+        This->image_offset = bfh.bfOffBits;
+    }
 
     hr = IStream_Read(stream, &This->bih.bV5Size, sizeof(DWORD), &bytesread);
     if (FAILED(hr)) return hr;
@@ -749,6 +786,24 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
     if (FAILED(hr)) return hr;
     if (bytestoread != bytesread) return E_FAIL;
 
+    if (This->packed)
+        This->palette_offset = This->bih.bV5Size;
+    else
+        This->palette_offset = sizeof(BITMAPFILEHEADER) + This->bih.bV5Size;
+
+    if (This->icoframe)
+    {
+        if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+        {
+            BITMAPCOREHEADER *bch = (BITMAPCOREHEADER*)&This->bih;
+            bch->bcHeight /= 2;
+        }
+        else
+        {
+            This->bih.bV5Height /= 2;
+        }
+    }
+
     /* if this is a BITMAPINFOHEADER with BI_BITFIELDS compression, we need to
         read the extra fields */
     if (This->bih.bV5Size == sizeof(BITMAPINFOHEADER) &&
@@ -758,6 +813,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
         if (FAILED(hr)) return hr;
         if (bytesread != 12) return E_FAIL;
         This->bih.bV5AlphaMask = 0;
+        This->palette_offset += 12;
     }
 
     /* decide what kind of bitmap this is and how/if we can read it */
@@ -880,6 +936,23 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
         }
     }
 
+    if (This->packed)
+    {
+        /* In a packed DIB, the image follows the palette. */
+        ULONG palette_count, palette_size;
+        if (This->bih.bV5ClrUsed)
+            palette_count = This->bih.bV5ClrUsed;
+        else if (This->bih.bV5BitCount <= 8)
+            palette_count = 1 << This->bih.bV5BitCount;
+        else
+            palette_count = 0;
+        if (This->bih.bV5Size == sizeof(BITMAPCOREHEADER))
+            palette_size = sizeof(RGBTRIPLE) * palette_count;
+        else
+            palette_size = sizeof(RGBQUAD) * palette_count;
+        This->image_offset = This->palette_offset + palette_size;
+    }
+
     This->initialized = TRUE;
 
     return S_OK;
@@ -888,14 +961,15 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream)
 static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
     void **ppv)
 {
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *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))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapDecoder, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapDecoder_iface;
     }
     else
     {
@@ -909,7 +983,7 @@ static HRESULT WINAPI BmpDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID
 
 static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
 {
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -919,7 +993,7 @@ static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface)
 
 static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
 {
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -936,22 +1010,20 @@ static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface)
     return ref;
 }
 
-static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
-    DWORD *pdwCapability)
+static HRESULT WINAPI BmpDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
+    DWORD *capability)
 {
     HRESULT hr;
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
 
-    EnterCriticalSection(&This->lock);
-    hr = BmpDecoder_ReadHeaders(This, pIStream);
-    LeaveCriticalSection(&This->lock);
-    if (FAILED(hr)) return hr;
+    TRACE("(%p,%p,%p)\n", iface, stream, capability);
 
-    if (This->read_data_func == BmpFrameDecode_ReadUnsupported)
-        *pdwCapability = 0;
-    else
-        *pdwCapability = WICBitmapDecoderCapabilityCanDecodeAllImages;
+    if (!stream || !capability) return E_INVALIDARG;
 
+    hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand);
+    if (hr != S_OK) return hr;
+
+    *capability = This->read_data_func == BmpFrameDecode_ReadUnsupported ? 0 : WICBitmapDecoderCapabilityCanDecodeAllImages;
     return S_OK;
 }
 
@@ -959,7 +1031,7 @@ static HRESULT WINAPI BmpDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p
     WICDecodeOptions cacheOptions)
 {
     HRESULT hr;
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
 
     EnterCriticalSection(&This->lock);
     hr = BmpDecoder_ReadHeaders(This, pIStream);
@@ -1039,6 +1111,8 @@ static HRESULT WINAPI BmpDecoder_GetThumbnail(IWICBitmapDecoder *iface,
 static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
     UINT *pCount)
 {
+    if (!pCount) return E_INVALIDARG;
+
     *pCount = 1;
     return S_OK;
 }
@@ -1046,13 +1120,13 @@ static HRESULT WINAPI BmpDecoder_GetFrameCount(IWICBitmapDecoder *iface,
 static HRESULT WINAPI BmpDecoder_GetFrame(IWICBitmapDecoder *iface,
     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
 {
-    BmpDecoder *This = (BmpDecoder*)iface;
+    BmpDecoder *This = impl_from_IWICBitmapDecoder(iface);
 
     if (index != 0) return E_INVALIDARG;
 
-    if (!This->stream) return WINCODEC_ERR_WRONGSTATE;
+    if (!This->stream) return WINCODEC_ERR_FRAMEMISSING;
 
-    *ppIBitmapFrame = (IWICBitmapFrameDecode*)&This->lpFrameVtbl;
+    *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
     IWICBitmapDecoder_AddRef(iface);
 
     return S_OK;
@@ -1075,31 +1149,85 @@ static const IWICBitmapDecoderVtbl BmpDecoder_Vtbl = {
     BmpDecoder_GetFrame
 };
 
-HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecoder)
 {
     BmpDecoder *This;
-    HRESULT ret;
-
-    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
-
-    *ppv = NULL;
-
-    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
 
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &BmpDecoder_Vtbl;
-    This->lpFrameVtbl = &BmpDecoder_FrameVtbl;
+    This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl;
+    This->IWICBitmapFrameDecode_iface.lpVtbl = &BmpDecoder_FrameVtbl;
     This->ref = 1;
     This->initialized = FALSE;
     This->stream = NULL;
     This->imagedata = NULL;
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock");
+    This->packed = packed;
+    This->icoframe = icoframe;
+
+    *ppDecoder = This;
+
+    return S_OK;
+}
+
+static HRESULT BmpDecoder_Construct(int packed, int icoframe, IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    BmpDecoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    ret = BmpDecoder_Create(packed, icoframe, &This);
+    if (FAILED(ret)) return ret;
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+    IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 
     return ret;
 }
+
+HRESULT BmpDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    return BmpDecoder_Construct(FALSE, FALSE, pUnkOuter, iid, ppv);
+}
+
+HRESULT DibDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    return BmpDecoder_Construct(TRUE, FALSE, pUnkOuter, iid, ppv);
+}
+
+HRESULT IcoDibDecoder_CreateInstance(BmpDecoder **ppDecoder)
+{
+    return BmpDecoder_Create(TRUE, TRUE, ppDecoder);
+}
+
+void BmpDecoder_GetWICDecoder(BmpDecoder *This, IWICBitmapDecoder **ppDecoder)
+{
+    *ppDecoder = &This->IWICBitmapDecoder_iface;
+}
+
+/* Return the offset where the mask of an icon might be, or 0 for failure. */
+void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown)
+{
+    assert(This->stream != NULL);
+
+    if (This->read_data_func == BmpFrameDecode_ReadUncompressed)
+    {
+        /* RGB or BITFIELDS data */
+        ULONG width, height, bytesperrow, datasize;
+        IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height);
+        bytesperrow = (((width * This->bitsperpixel)+31)/32)*4;
+        datasize = bytesperrow * height;
+        *mask_offset = This->image_offset + datasize;
+    }
+    else
+        *mask_offset = 0;
+
+    *topdown = This->stride > 0;
+}
index b79a19b..27922e7 100644 (file)
@@ -58,7 +58,7 @@ static const struct bmp_pixelformat formats[] = {
 };
 
 typedef struct BmpFrameEncode {
-    const IWICBitmapFrameEncodeVtbl *lpVtbl;
+    IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
     LONG ref;
     IStream *stream;
     BOOL initialized;
@@ -71,10 +71,15 @@ typedef struct BmpFrameEncode {
     BOOL committed;
 } BmpFrameEncode;
 
+static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
+{
+    return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface);
+}
+
 static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
     void **ppv)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -82,7 +87,7 @@ static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface
     if (IsEqualIID(&IID_IUnknown, iid) ||
         IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapFrameEncode_iface;
     }
     else
     {
@@ -96,7 +101,7 @@ static HRESULT WINAPI BmpFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface
 
 static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -106,7 +111,7 @@ static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
 
 static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -124,7 +129,7 @@ static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface)
 static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
     IPropertyBag2 *pIEncoderOptions)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     TRACE("(%p,%p)\n", iface, pIEncoderOptions);
 
     if (This->initialized) return WINCODEC_ERR_WRONGSTATE;
@@ -137,7 +142,7 @@ static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
 static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
     UINT uiWidth, UINT uiHeight)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
 
     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
@@ -151,7 +156,7 @@ static HRESULT WINAPI BmpFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
 static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
     double dpiX, double dpiY)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
 
     if (!This->initialized || This->bits) return WINCODEC_ERR_WRONGSTATE;
@@ -165,7 +170,7 @@ static HRESULT WINAPI BmpFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
 static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
     WICPixelFormatGUID *pPixelFormat)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     int i;
     TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
 
@@ -224,7 +229,7 @@ static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This)
 static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
     UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     HRESULT hr;
     WICRect rc;
     TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
@@ -253,7 +258,7 @@ static HRESULT WINAPI BmpFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
 static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
     IWICBitmapSource *pIBitmapSource, WICRect *prc)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     HRESULT hr;
     WICRect rc;
     WICPixelFormatGUID guid;
@@ -309,14 +314,14 @@ static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
         This->stride*(This->height-This->lineswritten),
         This->bits + This->stride*This->lineswritten);
 
-    This->lineswritten += rc.Height;
+    This->lineswritten += prc->Height;
 
     return S_OK;
 }
 
 static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface)
 {
-    BmpFrameEncode *This = (BmpFrameEncode*)iface;
+    BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
     BITMAPFILEHEADER bfh;
     BITMAPV5HEADER bih;
     UINT info_size;
@@ -407,16 +412,21 @@ static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = {
 };
 
 typedef struct BmpEncoder {
-    const IWICBitmapEncoderVtbl *lpVtbl;
+    IWICBitmapEncoder IWICBitmapEncoder_iface;
     LONG ref;
     IStream *stream;
-    IWICBitmapFrameEncode *frame;
+    BmpFrameEncode *frame;
 } BmpEncoder;
 
+static inline BmpEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
+{
+    return CONTAINING_RECORD(iface, BmpEncoder, IWICBitmapEncoder_iface);
+}
+
 static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
     void **ppv)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -424,7 +434,7 @@ static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID
     if (IsEqualIID(&IID_IUnknown, iid) ||
         IsEqualIID(&IID_IWICBitmapEncoder, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapEncoder_iface;
     }
     else
     {
@@ -438,7 +448,7 @@ static HRESULT WINAPI BmpEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID
 
 static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -448,7 +458,7 @@ static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface)
 
 static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -456,7 +466,7 @@ static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
     if (ref == 0)
     {
         if (This->stream) IStream_Release(This->stream);
-        if (This->frame) IWICBitmapFrameEncode_Release(This->frame);
+        if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -466,7 +476,7 @@ static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface)
 static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
     IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
 
     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
 
@@ -479,8 +489,8 @@ static HRESULT WINAPI BmpEncoder_Initialize(IWICBitmapEncoder *iface,
 static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
     GUID *pguidContainerFormat)
 {
-    FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
-    return E_NOTIMPL;
+    memcpy(pguidContainerFormat, &GUID_ContainerFormatBmp, sizeof(GUID));
+    return S_OK;
 }
 
 static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
@@ -518,7 +528,7 @@ static HRESULT WINAPI BmpEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmap
 static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
     IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
     BmpFrameEncode *encode;
     HRESULT hr;
 
@@ -538,7 +548,7 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
         *ppIEncoderOptions = NULL;
         return E_OUTOFMEMORY;
     }
-    encode->lpVtbl = &BmpFrameEncode_Vtbl;
+    encode->IWICBitmapFrameEncode_iface.lpVtbl = &BmpFrameEncode_Vtbl;
     encode->ref = 2;
     IStream_AddRef(This->stream);
     encode->stream = This->stream;
@@ -552,19 +562,18 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
     encode->lineswritten = 0;
     encode->committed = FALSE;
 
-    *ppIFrameEncode = (IWICBitmapFrameEncode*)encode;
-    This->frame = (IWICBitmapFrameEncode*)encode;
+    *ppIFrameEncode = &encode->IWICBitmapFrameEncode_iface;
+    This->frame = encode;
 
     return S_OK;
 }
 
 static HRESULT WINAPI BmpEncoder_Commit(IWICBitmapEncoder *iface)
 {
-    BmpEncoder *This = (BmpEncoder*)iface;
-    BmpFrameEncode *frame = (BmpFrameEncode*)This->frame;
+    BmpEncoder *This = impl_from_IWICBitmapEncoder(iface);
     TRACE("(%p)\n", iface);
 
-    if (!frame || !frame->committed) return WINCODEC_ERR_WRONGSTATE;
+    if (!This->frame || !This->frame->committed) return WINCODEC_ERR_WRONGSTATE;
 
     return S_OK;
 }
@@ -606,13 +615,13 @@ HRESULT BmpEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &BmpEncoder_Vtbl;
+    This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl;
     This->ref = 1;
     This->stream = NULL;
     This->frame = NULL;
 
-    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;
 }
index 68e0530..a57d673 100644 (file)
@@ -29,6 +29,7 @@
 #include "ocidl.h"
 #include "initguid.h"
 #include "wincodec.h"
+#include "wincodecsdk.h"
 
 #include "wincodecs_private.h"
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
+extern HRESULT WINAPI WIC_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN;
+
 typedef struct {
     REFCLSID classid;
     HRESULT (*constructor)(IUnknown*,REFIID,void**);
 } classinfo;
 
-static classinfo wic_classes[] = {
-    {&CLSID_WICImagingFactory, ImagingFactory_CreateInstance},
+static const classinfo wic_classes[] = {
+    {&CLSID_WICImagingFactory, ComponentFactory_CreateInstance},
     {&CLSID_WICBmpDecoder, BmpDecoder_CreateInstance},
     {&CLSID_WICPngDecoder, PngDecoder_CreateInstance},
     {&CLSID_WICPngEncoder, PngEncoder_CreateInstance},
@@ -50,27 +53,45 @@ static classinfo wic_classes[] = {
     {&CLSID_WICGifDecoder, GifDecoder_CreateInstance},
     {&CLSID_WICIcoDecoder, IcoDecoder_CreateInstance},
     {&CLSID_WICJpegDecoder, JpegDecoder_CreateInstance},
+    {&CLSID_WICJpegEncoder, JpegEncoder_CreateInstance},
     {&CLSID_WICTiffDecoder, TiffDecoder_CreateInstance},
+    {&CLSID_WICTiffEncoder, TiffEncoder_CreateInstance},
+    {&CLSID_WICIcnsEncoder, IcnsEncoder_CreateInstance},
     {&CLSID_WICDefaultFormatConverter, FormatConverter_CreateInstance},
+    {&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance},
+    {&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance},
+    {&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance},
+    {&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance},
+    {&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance},
+    {&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance},
+    {&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance},
+    {&CLSID_WICAPEMetadataReader, APEReader_CreateInstance},
+    {&CLSID_WICGifCommentMetadataReader, GifCommentReader_CreateInstance},
     {0}};
 
 typedef struct {
-    const IClassFactoryVtbl *lpIClassFactoryVtbl;
+    IClassFactory           IClassFactory_iface;
     LONG                    ref;
-    classinfo               *info;
+    const classinfo         *info;
 } ClassFactoryImpl;
 
+static inline ClassFactoryImpl *impl_from_IClassFactory(IClassFactory *iface)
+{
+    return CONTAINING_RECORD(iface, ClassFactoryImpl, IClassFactory_iface);
+}
+
 static HRESULT WINAPI ClassFactoryImpl_QueryInterface(IClassFactory *iface,
     REFIID iid, void **ppv)
 {
-    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ClassFactoryImpl *This = impl_from_IClassFactory(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
 
-    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IClassFactory, iid))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IClassFactory, iid))
     {
-        *ppv = This;
+        *ppv = &This->IClassFactory_iface;
     }
     else
     {
@@ -84,7 +105,7 @@ static HRESULT WINAPI ClassFactoryImpl_QueryInterface(IClassFactory *iface,
 
 static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface)
 {
-    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ClassFactoryImpl *This = impl_from_IClassFactory(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -94,7 +115,7 @@ static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface)
 
 static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface)
 {
-    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ClassFactoryImpl *This = impl_from_IClassFactory(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -108,7 +129,7 @@ static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface)
 static HRESULT WINAPI ClassFactoryImpl_CreateInstance(IClassFactory *iface,
     IUnknown *pUnkOuter, REFIID riid, void **ppv)
 {
-    ClassFactoryImpl *This = (ClassFactoryImpl*)iface;
+    ClassFactoryImpl *This = impl_from_IClassFactory(iface);
 
     return This->info->constructor(pUnkOuter, riid, ppv);
 }
@@ -127,7 +148,7 @@ static const IClassFactoryVtbl ClassFactoryImpl_Vtbl = {
     ClassFactoryImpl_LockServer
 };
 
-static HRESULT ClassFactoryImpl_Constructor(classinfo *info, REFIID riid, LPVOID *ppv)
+static HRESULT ClassFactoryImpl_Constructor(const classinfo *info, REFIID riid, LPVOID *ppv)
 {
     ClassFactoryImpl *This;
     HRESULT ret;
@@ -137,12 +158,12 @@ static HRESULT ClassFactoryImpl_Constructor(classinfo *info, REFIID riid, LPVOID
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(ClassFactoryImpl));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpIClassFactoryVtbl = &ClassFactoryImpl_Vtbl;
+    This->IClassFactory_iface.lpVtbl = &ClassFactoryImpl_Vtbl;
     This->ref = 1;
     This->info = info;
 
-    ret = IClassFactory_QueryInterface((IClassFactory*)This, riid, ppv);
-    IClassFactory_Release((IClassFactory*)This);
+    ret = IClassFactory_QueryInterface(&This->IClassFactory_iface, riid, ppv);
+    IClassFactory_Release(&This->IClassFactory_iface);
 
     return ret;
 }
@@ -150,7 +171,7 @@ static HRESULT ClassFactoryImpl_Constructor(classinfo *info, REFIID riid, LPVOID
 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
 {
     HRESULT ret;
-    classinfo *info=NULL;
+    const classinfo *info=NULL;
     int i;
 
     TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(iid), ppv);
@@ -172,7 +193,7 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
     if (info)
         ret = ClassFactoryImpl_Constructor(info, iid, ppv);
     else
-        ret = CLASS_E_CLASSNOTAVAILABLE;
+        ret = WIC_DllGetClassObject(rclsid, iid, ppv);
 
     TRACE("<-- %08X\n", ret);
     return ret;
diff --git a/reactos/dll/win32/windowscodecs/colorcontext.c b/reactos/dll/win32/windowscodecs/colorcontext.c
new file mode 100644 (file)
index 0000000..457b4db
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012 Hans Leidekker for CodeWeavers
+ *
+ * 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 <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct ColorContext {
+    IWICColorContext IWICColorContext_iface;
+    LONG ref;
+    WICColorContextType type;
+    BYTE *profile;
+    UINT profile_len;
+    UINT exif_color_space;
+} ColorContext;
+
+static inline ColorContext *impl_from_IWICColorContext(IWICColorContext *iface)
+{
+    return CONTAINING_RECORD(iface, ColorContext, IWICColorContext_iface);
+}
+
+static HRESULT WINAPI ColorContext_QueryInterface(IWICColorContext *iface, REFIID iid,
+    void **ppv)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICColorContext, iid))
+    {
+        *ppv = &This->IWICColorContext_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI ColorContext_AddRef(IWICColorContext *iface)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI ColorContext_Release(IWICColorContext *iface)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        HeapFree(GetProcessHeap(), 0, This->profile);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI ColorContext_InitializeFromFilename(IWICColorContext *iface,
+    LPCWSTR wzFilename)
+{
+    FIXME("(%p,%s)\n", iface, debugstr_w(wzFilename));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ColorContext_InitializeFromMemory(IWICColorContext *iface,
+    const BYTE *pbBuffer, UINT cbBufferSize)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%p,%u)\n", iface, pbBuffer, cbBufferSize);
+
+    if (This->type != WICColorContextUninitialized)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    HeapFree(GetProcessHeap(), 0, This->profile);
+    if (!(This->profile = HeapAlloc(GetProcessHeap(), 0, cbBufferSize)))
+        return E_OUTOFMEMORY;
+
+    memcpy(This->profile, pbBuffer, cbBufferSize);
+    This->profile_len = cbBufferSize;
+    This->type = WICColorContextProfile;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ColorContext_InitializeFromExifColorSpace(IWICColorContext *iface,
+    UINT value)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%u)\n", iface, value);
+
+    if (This->type != WICColorContextUninitialized && This->type != WICColorContextExifColorSpace)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    This->exif_color_space = value;
+    This->type = WICColorContextExifColorSpace;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ColorContext_GetType(IWICColorContext *iface,
+    WICColorContextType *pType)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%p)\n", iface, pType);
+
+    if (!pType) return E_INVALIDARG;
+
+    *pType = This->type;
+    return S_OK;
+}
+
+static HRESULT WINAPI ColorContext_GetProfileBytes(IWICColorContext *iface,
+    UINT cbBuffer, BYTE *pbBuffer, UINT *pcbActual)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%u,%p,%p)\n", iface, cbBuffer, pbBuffer, pcbActual);
+
+    if (This->type != WICColorContextProfile)
+        return WINCODEC_ERR_NOTINITIALIZED;
+
+    if (!pcbActual) return E_INVALIDARG;
+
+    if (cbBuffer >= This->profile_len && pbBuffer)
+        memcpy(pbBuffer, This->profile, This->profile_len);
+
+    *pcbActual = This->profile_len;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI ColorContext_GetExifColorSpace(IWICColorContext *iface,
+    UINT *pValue)
+{
+    ColorContext *This = impl_from_IWICColorContext(iface);
+    TRACE("(%p,%p)\n", iface, pValue);
+
+    if (!pValue) return E_INVALIDARG;
+
+    *pValue = This->exif_color_space;
+    return S_OK;
+}
+
+static const IWICColorContextVtbl ColorContext_Vtbl = {
+    ColorContext_QueryInterface,
+    ColorContext_AddRef,
+    ColorContext_Release,
+    ColorContext_InitializeFromFilename,
+    ColorContext_InitializeFromMemory,
+    ColorContext_InitializeFromExifColorSpace,
+    ColorContext_GetType,
+    ColorContext_GetProfileBytes,
+    ColorContext_GetExifColorSpace
+};
+
+HRESULT ColorContext_Create(IWICColorContext **colorcontext)
+{
+    ColorContext *This;
+
+    if (!colorcontext) return E_INVALIDARG;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ColorContext));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IWICColorContext_iface.lpVtbl = &ColorContext_Vtbl;
+    This->ref = 1;
+    This->type = 0;
+    This->profile = NULL;
+    This->profile_len = 0;
+    This->exif_color_space = ~0u;
+
+    *colorcontext = &This->IWICColorContext_iface;
+
+    return S_OK;
+}
index b1c0952..8611560 100644 (file)
@@ -47,11 +47,14 @@ enum pixelformat {
     format_16bppGray,
     format_16bppBGR555,
     format_16bppBGR565,
+    format_16bppBGRA5551,
     format_24bppBGR,
     format_32bppBGR,
     format_32bppBGRA,
+    format_32bppPBGRA,
     format_48bppRGB,
     format_64bppRGBA,
+    format_32bppCMYK,
 };
 
 typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc,
@@ -64,7 +67,7 @@ struct pixelformatinfo {
 };
 
 typedef struct FormatConverter {
-    const IWICFormatConverterVtbl *lpVtbl;
+    IWICFormatConverter IWICFormatConverter_iface;
     LONG ref;
     IWICBitmapSource *source;
     const struct pixelformatinfo *dst_format, *src_format;
@@ -74,14 +77,9 @@ typedef struct FormatConverter {
     CRITICAL_SECTION lock; /* must be held when initialized */
 } FormatConverter;
 
-static void make_grayscale_palette(WICColor *colors, UINT num_colors)
+static inline FormatConverter *impl_from_IWICFormatConverter(IWICFormatConverter *iface)
 {
-    int i, v;
-    for (i=0; i<num_colors; i++)
-    {
-        v = i * 255 / (num_colors-1);
-        colors[i] = 0xff000000 | v<<16 | v<<8 | v;
-    }
+    return CONTAINING_RECORD(iface, FormatConverter, IWICFormatConverter_iface);
 }
 
 static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRect *prc,
@@ -105,24 +103,19 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
             IWICPalette *palette;
             UINT actualcolors;
 
-            if (source_format == format_1bppIndexed)
-            {
-                res = PaletteImpl_Create(&palette);
-                if (FAILED(res)) return res;
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
 
+            if (source_format == format_1bppIndexed)
                 res = IWICBitmapSource_CopyPalette(This->source, palette);
-                if (SUCCEEDED(res))
-                    res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
+            else
+                res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedBW, FALSE);
 
-                IWICPalette_Release(palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 2, colors, &actualcolors);
 
-                if (FAILED(res)) return res;
-            }
-            else
-            {
-                colors[0] = 0xff000000;
-                colors[1] = 0xffffffff;
-            }
+            IWICPalette_Release(palette);
+            if (FAILED(res)) return res;
 
             srcstride = (prc->Width+7)/8;
             srcdatasize = srcstride * prc->Height;
@@ -137,7 +130,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x+=8) {
                         BYTE srcval;
@@ -177,21 +170,19 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
             IWICPalette *palette;
             UINT actualcolors;
 
-            if (source_format == format_2bppIndexed)
-            {
-                res = PaletteImpl_Create(&palette);
-                if (FAILED(res)) return res;
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
 
+            if (source_format == format_2bppIndexed)
                 res = IWICBitmapSource_CopyPalette(This->source, palette);
-                if (SUCCEEDED(res))
-                    res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
+            else
+                res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray4, FALSE);
 
-                IWICPalette_Release(palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 4, colors, &actualcolors);
 
-                if (FAILED(res)) return res;
-            }
-            else
-                make_grayscale_palette(colors, 4);
+            IWICPalette_Release(palette);
+            if (FAILED(res)) return res;
 
             srcstride = (prc->Width+3)/4;
             srcdatasize = srcstride * prc->Height;
@@ -206,7 +197,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x+=4) {
                         BYTE srcval;
@@ -242,21 +233,19 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
             IWICPalette *palette;
             UINT actualcolors;
 
-            if (source_format == format_4bppIndexed)
-            {
-                res = PaletteImpl_Create(&palette);
-                if (FAILED(res)) return res;
+            res = PaletteImpl_Create(&palette);
+            if (FAILED(res)) return res;
 
+            if (source_format == format_4bppIndexed)
                 res = IWICBitmapSource_CopyPalette(This->source, palette);
-                if (SUCCEEDED(res))
-                    res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
+            else
+                res = IWICPalette_InitializePredefined(palette, WICBitmapPaletteTypeFixedGray16, FALSE);
 
-                IWICPalette_Release(palette);
+            if (SUCCEEDED(res))
+                res = IWICPalette_GetColors(palette, 16, colors, &actualcolors);
 
-                if (FAILED(res)) return res;
-            }
-            else
-                make_grayscale_palette(colors, 16);
+            IWICPalette_Release(palette);
+            if (FAILED(res)) return res;
 
             srcstride = (prc->Width+1)/2;
             srcdatasize = srcstride * prc->Height;
@@ -271,7 +260,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x+=2) {
                         BYTE srcval;
@@ -314,7 +303,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x++)
                     {
@@ -370,7 +359,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x++)
                         *dstpixel++ = colors[*srcbyte++];
@@ -409,7 +398,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
                 srcrow = srcdata;
                 dstrow = pbBuffer;
                 for (y=0; y<prc->Height; y++) {
-                    srcbyte=(const BYTE*)srcrow;
+                    srcbyte = srcrow;
                     dstpixel=(DWORD*)dstrow;
                     for (x=0; x<prc->Width; x++)
                     {
@@ -522,6 +511,54 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
             return res;
         }
         return S_OK;
+    case format_16bppBGRA5551:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+            BYTE *srcdata;
+            UINT srcstride, srcdatasize;
+            const BYTE *srcrow;
+            const WORD *srcpixel;
+            BYTE *dstrow;
+            DWORD *dstpixel;
+
+            srcstride = 2 * prc->Width;
+            srcdatasize = srcstride * prc->Height;
+
+            srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize);
+            if (!srcdata) return E_OUTOFMEMORY;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata);
+
+            if (SUCCEEDED(res))
+            {
+                srcrow = srcdata;
+                dstrow = pbBuffer;
+                for (y=0; y<prc->Height; y++) {
+                    srcpixel=(const WORD*)srcrow;
+                    dstpixel=(DWORD*)dstrow;
+                    for (x=0; x<prc->Width; x++) {
+                        WORD srcval;
+                        srcval=*srcpixel++;
+                        *dstpixel++=((srcval & 0x8000) ? 0xff000000 : 0) | /* alpha */
+                                    ((srcval << 9) & 0xf80000) | /* r */
+                                    ((srcval << 4) & 0x070000) | /* r - 3 bits */
+                                    ((srcval << 6) & 0x00f800) | /* g */
+                                    ((srcval << 1) & 0x000700) | /* g - 3 bits */
+                                    ((srcval << 3) & 0x0000f8) | /* b */
+                                    ((srcval >> 2) & 0x000007);  /* b - 3 bits */
+                    }
+                    srcrow += srcstride;
+                    dstrow += cbStride;
+                }
+            }
+
+            HeapFree(GetProcessHeap(), 0, srcdata);
+
+            return res;
+        }
+        return S_OK;
     case format_24bppBGR:
         if (prc)
         {
@@ -584,6 +621,28 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
         if (prc)
             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
         return S_OK;
+    case format_32bppPBGRA:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+            if (FAILED(res)) return res;
+
+            for (y=0; y<prc->Height; y++)
+                for (x=0; x<prc->Width; x++)
+                {
+                    BYTE alpha = pbBuffer[cbStride*y+4*x+3];
+                    if (alpha != 0 && alpha != 255)
+                    {
+                        pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * 255 / alpha;
+                        pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * 255 / alpha;
+                        pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * 255 / alpha;
+                    }
+                }
+        }
+        return S_OK;
     case format_48bppRGB:
         if (prc)
         {
@@ -673,6 +732,27 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe
             return res;
         }
         return S_OK;
+    case format_32bppCMYK:
+        if (prc)
+        {
+            HRESULT res;
+            UINT x, y;
+
+            res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+            if (FAILED(res)) return res;
+
+            for (y=0; y<prc->Height; y++)
+                for (x=0; x<prc->Width; x++)
+                {
+                    BYTE *pixel = pbBuffer+cbStride*y+4*x;
+                    BYTE c=pixel[0], m=pixel[1], y=pixel[2], k=pixel[3];
+                    pixel[0] = (255-y)*(255-k)/255; /* blue */
+                    pixel[1] = (255-m)*(255-k)/255; /* green */
+                    pixel[2] = (255-c)*(255-k)/255; /* red */
+                    pixel[3] = 255; /* alpha */
+                }
+        }
+        return S_OK;
     default:
         return WINCODEC_ERR_UNSUPPORTEDOPERATION;
     }
@@ -685,6 +765,7 @@ static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRec
     {
     case format_32bppBGR:
     case format_32bppBGRA:
+    case format_32bppPBGRA:
         if (prc)
             return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
         return S_OK;
@@ -693,6 +774,39 @@ static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRec
     }
 }
 
+static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc,
+    UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format)
+{
+    HRESULT hr;
+
+    switch (source_format)
+    {
+    case format_32bppPBGRA:
+        if (prc)
+            return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer);
+        return S_OK;
+    default:
+        hr = copypixels_to_32bppBGRA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format);
+        if (SUCCEEDED(hr) && prc)
+        {
+            UINT x, y;
+
+            for (y=0; y<prc->Height; y++)
+                for (x=0; x<prc->Width; x++)
+                {
+                    BYTE alpha = pbBuffer[cbStride*y+4*x+3];
+                    if (alpha != 255)
+                    {
+                        pbBuffer[cbStride*y+4*x] = pbBuffer[cbStride*y+4*x] * alpha / 255;
+                        pbBuffer[cbStride*y+4*x+1] = pbBuffer[cbStride*y+4*x+1] * alpha / 255;
+                        pbBuffer[cbStride*y+4*x+2] = pbBuffer[cbStride*y+4*x+2] * alpha / 255;
+                    }
+                }
+        }
+        return hr;
+    }
+}
+
 static const struct pixelformatinfo supported_formats[] = {
     {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL},
     {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL},
@@ -705,11 +819,14 @@ static const struct pixelformatinfo supported_formats[] = {
     {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL},
     {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL},
     {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL},
+    {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL},
     {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, NULL},
     {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR},
     {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA},
+    {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA},
     {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL},
     {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL},
+    {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL},
     {0}
 };
 
@@ -726,7 +843,7 @@ static const struct pixelformatinfo *get_formatinfo(const WICPixelFormatGUID *fo
 static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface, REFIID iid,
     void **ppv)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -735,7 +852,7 @@ static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface,
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICFormatConverter, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICFormatConverter_iface;
     }
     else
     {
@@ -749,7 +866,7 @@ static HRESULT WINAPI FormatConverter_QueryInterface(IWICFormatConverter *iface,
 
 static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -759,7 +876,7 @@ static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface)
 
 static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -778,7 +895,7 @@ static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface)
 static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
 
     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
 
@@ -791,7 +908,7 @@ static HRESULT WINAPI FormatConverter_GetSize(IWICFormatConverter *iface,
 static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
     WICPixelFormatGUID *pPixelFormat)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
 
     TRACE("(%p,%p): stub\n", iface, pPixelFormat);
 
@@ -806,7 +923,7 @@ static HRESULT WINAPI FormatConverter_GetPixelFormat(IWICFormatConverter *iface,
 static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface,
     double *pDpiX, double *pDpiY)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
 
     TRACE("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
 
@@ -826,12 +943,28 @@ static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
 static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
+    WICRect rc;
+    HRESULT hr;
     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
 
     if (This->source)
+    {
+        if (!prc)
+        {
+            UINT width, height;
+            hr = IWICBitmapSource_GetSize(This->source, &width, &height);
+            if (FAILED(hr)) return hr;
+            rc.X = 0;
+            rc.Y = 0;
+            rc.Width = width;
+            rc.Height = height;
+            prc = &rc;
+        }
+
         return This->dst_format->copy_function(This, prc, cbStride, cbBufferSize,
             pbBuffer, This->src_format->format);
+    }
     else
         return WINCODEC_ERR_NOTINITIALIZED;
 }
@@ -840,7 +973,7 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
     IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither,
     IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
     const struct pixelformatinfo *srcinfo, *dstinfo;
     static INT fixme=0;
     GUID srcFormat;
@@ -866,6 +999,7 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
     if (!srcinfo)
     {
         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+        FIXME("Unsupported source format %s\n", debugstr_guid(&srcFormat));
         goto end;
     }
 
@@ -873,6 +1007,7 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
     if (!dstinfo)
     {
         res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+        FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat));
         goto end;
     }
 
@@ -887,7 +1022,10 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface,
         This->source = pISource;
     }
     else
+    {
+        FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(&srcFormat), debugstr_guid(dstFormat));
         res = WINCODEC_ERR_UNSUPPORTEDOPERATION;
+    }
 
 end:
 
@@ -900,23 +1038,34 @@ static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface,
     REFWICPixelFormatGUID srcPixelFormat, REFWICPixelFormatGUID dstPixelFormat,
     BOOL *pfCanConvert)
 {
-    FormatConverter *This = (FormatConverter*)iface;
+    FormatConverter *This = impl_from_IWICFormatConverter(iface);
     const struct pixelformatinfo *srcinfo, *dstinfo;
 
     TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(srcPixelFormat),
         debugstr_guid(dstPixelFormat), pfCanConvert);
 
     srcinfo = get_formatinfo(srcPixelFormat);
-    if (!srcinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+    if (!srcinfo)
+    {
+        FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat));
+        return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+    }
 
     dstinfo = get_formatinfo(dstPixelFormat);
-    if (!dstinfo) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+    if (!dstinfo)
+    {
+        FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat));
+        return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT;
+    }
 
     if (dstinfo->copy_function &&
         SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format)))
         *pfCanConvert = TRUE;
     else
+    {
+        FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat));
         *pfCanConvert = FALSE;
+    }
 
     return S_OK;
 }
@@ -948,14 +1097,14 @@ HRESULT FormatConverter_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** p
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &FormatConverter_Vtbl;
+    This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl;
     This->ref = 1;
     This->source = NULL;
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv);
+    IWICFormatConverter_Release(&This->IWICFormatConverter_iface);
 
     return ret;
 }
index 7dac252..81e01cc 100644 (file)
@@ -34,7 +34,7 @@
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
 typedef struct FlipRotator {
-    const IWICBitmapFlipRotatorVtbl *lpVtbl;
+    IWICBitmapFlipRotator IWICBitmapFlipRotator_iface;
     LONG ref;
     IWICBitmapSource *source;
     int flip_x;
@@ -43,10 +43,15 @@ typedef struct FlipRotator {
     CRITICAL_SECTION lock; /* must be held when initialized */
 } FlipRotator;
 
+static inline FlipRotator *impl_from_IWICBitmapFlipRotator(IWICBitmapFlipRotator *iface)
+{
+    return CONTAINING_RECORD(iface, FlipRotator, IWICBitmapFlipRotator_iface);
+}
+
 static HRESULT WINAPI FlipRotator_QueryInterface(IWICBitmapFlipRotator *iface, REFIID iid,
     void **ppv)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -55,7 +60,7 @@ static HRESULT WINAPI FlipRotator_QueryInterface(IWICBitmapFlipRotator *iface, R
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICBitmapFlipRotator, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapFlipRotator_iface;
     }
     else
     {
@@ -69,7 +74,7 @@ static HRESULT WINAPI FlipRotator_QueryInterface(IWICBitmapFlipRotator *iface, R
 
 static ULONG WINAPI FlipRotator_AddRef(IWICBitmapFlipRotator *iface)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -79,7 +84,7 @@ static ULONG WINAPI FlipRotator_AddRef(IWICBitmapFlipRotator *iface)
 
 static ULONG WINAPI FlipRotator_Release(IWICBitmapFlipRotator *iface)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -98,7 +103,7 @@ static ULONG WINAPI FlipRotator_Release(IWICBitmapFlipRotator *iface)
 static HRESULT WINAPI FlipRotator_GetSize(IWICBitmapFlipRotator *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
 
     if (!This->source)
@@ -112,34 +117,50 @@ static HRESULT WINAPI FlipRotator_GetSize(IWICBitmapFlipRotator *iface,
 static HRESULT WINAPI FlipRotator_GetPixelFormat(IWICBitmapFlipRotator *iface,
     WICPixelFormatGUID *pPixelFormat)
 {
-    FIXME("(%p,%p): stub\n", iface, pPixelFormat);
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
+    TRACE("(%p,%p)\n", iface, pPixelFormat);
 
-    return E_NOTIMPL;
+    if (!This->source)
+        return WINCODEC_ERR_WRONGSTATE;
+    else
+        return IWICBitmapSource_GetPixelFormat(This->source, pPixelFormat);
 }
 
 static HRESULT WINAPI FlipRotator_GetResolution(IWICBitmapFlipRotator *iface,
     double *pDpiX, double *pDpiY)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
+    TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
 
-    return E_NOTIMPL;
+    if (!This->source)
+        return WINCODEC_ERR_WRONGSTATE;
+    else if (This->swap_xy)
+        return IWICBitmapSource_GetResolution(This->source, pDpiY, pDpiX);
+    else
+        return IWICBitmapSource_GetResolution(This->source, pDpiX, pDpiY);
 }
 
 static HRESULT WINAPI FlipRotator_CopyPalette(IWICBitmapFlipRotator *iface,
     IWICPalette *pIPalette)
 {
-    FIXME("(%p,%p): stub\n", iface, pIPalette);
-    return E_NOTIMPL;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
+    TRACE("(%p,%p)\n", iface, pIPalette);
+
+    if (!This->source)
+        return WINCODEC_ERR_WRONGSTATE;
+    else
+        return IWICBitmapSource_CopyPalette(This->source, pIPalette);
 }
 
 static HRESULT WINAPI FlipRotator_CopyPixels(IWICBitmapFlipRotator *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     HRESULT hr;
     UINT y;
     UINT srcy, srcwidth, srcheight;
     WICRect rc;
+    WICRect rect;
 
     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
 
@@ -155,6 +176,18 @@ static HRESULT WINAPI FlipRotator_CopyPixels(IWICBitmapFlipRotator *iface,
     hr = IWICBitmapSource_GetSize(This->source, &srcwidth, &srcheight);
     if (FAILED(hr)) return hr;
 
+    if (!prc)
+    {
+        UINT width, height;
+        hr = IWICBitmapFlipRotator_GetSize(iface, &width, &height);
+        if (FAILED(hr)) return hr;
+        rect.X = 0;
+        rect.Y = 0;
+        rect.Width = width;
+        rect.Height = height;
+        prc = &rect;
+    }
+
     for (y=prc->Y; y - prc->Y < prc->Height; y++)
     {
         if (This->flip_y)
@@ -181,7 +214,7 @@ static HRESULT WINAPI FlipRotator_CopyPixels(IWICBitmapFlipRotator *iface,
 static HRESULT WINAPI FlipRotator_Initialize(IWICBitmapFlipRotator *iface,
     IWICBitmapSource *pISource, WICBitmapTransformOptions options)
 {
-    FlipRotator *This = (FlipRotator*)iface;
+    FlipRotator *This = impl_from_IWICBitmapFlipRotator(iface);
     HRESULT hr=S_OK;
 
     TRACE("(%p,%p,%u)\n", iface, pISource, options);
@@ -240,7 +273,7 @@ HRESULT FlipRotator_Create(IWICBitmapFlipRotator **fliprotator)
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(FlipRotator));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &FlipRotator_Vtbl;
+    This->IWICBitmapFlipRotator_iface.lpVtbl = &FlipRotator_Vtbl;
     This->ref = 1;
     This->source = NULL;
     This->flip_x = 0;
@@ -249,7 +282,7 @@ HRESULT FlipRotator_Create(IWICBitmapFlipRotator **fliprotator)
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FlipRotator.lock");
 
-    *fliprotator = (IWICBitmapFlipRotator*)This;
+    *fliprotator = &This->IWICBitmapFlipRotator_iface;
 
     return S_OK;
 }
index 3443b2c..84838e2 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Vincent Povirk for CodeWeavers
+ * Copyright 2012 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdarg.h>
 
 #define COBJMACROS
+#define NONAMELESSUNION
 
 #include "windef.h"
 #include "winbase.h"
 #include "objbase.h"
 #include "wincodec.h"
+#include "wincodecsdk.h"
 
 #include "ungif.h"
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
+static LPWSTR strdupAtoW(const char *src)
+{
+    int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0);
+    LPWSTR dst = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (dst) MultiByteToWideChar(CP_ACP, 0, src, -1, dst, len);
+    return dst;
+}
+
+static HRESULT load_LSD_metadata(IStream *stream, const GUID *vendor, DWORD options,
+                                 MetadataItem **items, DWORD *count)
+{
+#include "pshpack1.h"
+    struct logical_screen_descriptor
+    {
+        char signature[6];
+        USHORT width;
+        USHORT height;
+        BYTE packed;
+        /* global_color_table_flag : 1;
+         * color_resolution : 3;
+         * sort_flag : 1;
+         * global_color_table_size : 3;
+         */
+        BYTE background_color_index;
+        BYTE pixel_aspect_ratio;
+    } lsd_data;
+#include "poppack.h"
+    HRESULT hr;
+    ULONG bytesread, i;
+    MetadataItem *result;
+
+    *items = NULL;
+    *count = 0;
+
+    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);
+    if (!result) return E_OUTOFMEMORY;
+
+    for (i = 0; i < 9; i++)
+    {
+        PropVariantInit(&result[i].schema);
+        PropVariantInit(&result[i].id);
+        PropVariantInit(&result[i].value);
+    }
+
+    result[0].id.vt = VT_LPWSTR;
+    result[0].id.u.pwszVal = strdupAtoW("Signature");
+    result[0].value.vt = VT_UI1|VT_VECTOR;
+    result[0].value.u.caub.cElems = sizeof(lsd_data.signature);
+    result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(lsd_data.signature));
+    memcpy(result[0].value.u.caub.pElems, lsd_data.signature, sizeof(lsd_data.signature));
+
+    result[1].id.vt = VT_LPWSTR;
+    result[1].id.u.pwszVal = strdupAtoW("Width");
+    result[1].value.vt = VT_UI2;
+    result[1].value.u.uiVal = lsd_data.width;
+
+    result[2].id.vt = VT_LPWSTR;
+    result[2].id.u.pwszVal = strdupAtoW("Height");
+    result[2].value.vt = VT_UI2;
+    result[2].value.u.uiVal = lsd_data.height;
+
+    result[3].id.vt = VT_LPWSTR;
+    result[3].id.u.pwszVal = strdupAtoW("GlobalColorTableFlag");
+    result[3].value.vt = VT_BOOL;
+    result[3].value.u.boolVal = (lsd_data.packed >> 7) & 1;
+
+    result[4].id.vt = VT_LPWSTR;
+    result[4].id.u.pwszVal = strdupAtoW("ColorResolution");
+    result[4].value.vt = VT_UI1;
+    result[4].value.u.bVal = (lsd_data.packed >> 4) & 7;
+
+    result[5].id.vt = VT_LPWSTR;
+    result[5].id.u.pwszVal = strdupAtoW("SortFlag");
+    result[5].value.vt = VT_BOOL;
+    result[5].value.u.boolVal = (lsd_data.packed >> 3) & 1;
+
+    result[6].id.vt = VT_LPWSTR;
+    result[6].id.u.pwszVal = strdupAtoW("GlobalColorTableSize");
+    result[6].value.vt = VT_UI1;
+    result[6].value.u.bVal = lsd_data.packed & 7;
+
+    result[7].id.vt = VT_LPWSTR;
+    result[7].id.u.pwszVal = strdupAtoW("BackgroundColorIndex");
+    result[7].value.vt = VT_UI1;
+    result[7].value.u.bVal = lsd_data.background_color_index;
+
+    result[8].id.vt = VT_LPWSTR;
+    result[8].id.u.pwszVal = strdupAtoW("PixelAspectRatio");
+    result[8].value.vt = VT_UI1;
+    result[8].value.u.bVal = lsd_data.pixel_aspect_ratio;
+
+    *items = result;
+    *count = 9;
+
+    return S_OK;
+}
+
+static const MetadataHandlerVtbl LSDReader_Vtbl = {
+    0,
+    &CLSID_WICLSDMetadataReader,
+    load_LSD_metadata
+};
+
+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)
+{
+    struct image_descriptor imd_data;
+    HRESULT hr;
+    ULONG bytesread, i;
+    MetadataItem *result;
+
+    *items = NULL;
+    *count = 0;
+
+    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);
+    if (!result) return E_OUTOFMEMORY;
+
+    for (i = 0; i < 8; i++)
+    {
+        PropVariantInit(&result[i].schema);
+        PropVariantInit(&result[i].id);
+        PropVariantInit(&result[i].value);
+    }
+
+    result[0].id.vt = VT_LPWSTR;
+    result[0].id.u.pwszVal = strdupAtoW("Left");
+    result[0].value.vt = VT_UI2;
+    result[0].value.u.uiVal = imd_data.left;
+
+    result[1].id.vt = VT_LPWSTR;
+    result[1].id.u.pwszVal = strdupAtoW("Top");
+    result[1].value.vt = VT_UI2;
+    result[1].value.u.uiVal = imd_data.top;
+
+    result[2].id.vt = VT_LPWSTR;
+    result[2].id.u.pwszVal = strdupAtoW("Width");
+    result[2].value.vt = VT_UI2;
+    result[2].value.u.uiVal = imd_data.width;
+
+    result[3].id.vt = VT_LPWSTR;
+    result[3].id.u.pwszVal = strdupAtoW("Height");
+    result[3].value.vt = VT_UI2;
+    result[3].value.u.uiVal = imd_data.height;
+
+    result[4].id.vt = VT_LPWSTR;
+    result[4].id.u.pwszVal = strdupAtoW("LocalColorTableFlag");
+    result[4].value.vt = VT_BOOL;
+    result[4].value.u.boolVal = (imd_data.packed >> 7) & 1;
+
+    result[5].id.vt = VT_LPWSTR;
+    result[5].id.u.pwszVal = strdupAtoW("InterlaceFlag");
+    result[5].value.vt = VT_BOOL;
+    result[5].value.u.boolVal = (imd_data.packed >> 6) & 1;
+
+    result[6].id.vt = VT_LPWSTR;
+    result[6].id.u.pwszVal = strdupAtoW("SortFlag");
+    result[6].value.vt = VT_BOOL;
+    result[6].value.u.boolVal = (imd_data.packed >> 5) & 1;
+
+    result[7].id.vt = VT_LPWSTR;
+    result[7].id.u.pwszVal = strdupAtoW("LocalColorTableSize");
+    result[7].value.vt = VT_UI1;
+    result[7].value.u.bVal = imd_data.packed & 7;
+
+    *items = result;
+    *count = 8;
+
+    return S_OK;
+}
+
+static const MetadataHandlerVtbl IMDReader_Vtbl = {
+    0,
+    &CLSID_WICIMDMetadataReader,
+    load_IMD_metadata
+};
+
+HRESULT IMDReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
+{
+    return MetadataReader_Create(&IMDReader_Vtbl, pUnkOuter, iid, ppv);
+}
+
+static HRESULT load_GCE_metadata(IStream *stream, const GUID *vendor, DWORD options,
+                                 MetadataItem **items, DWORD *count)
+{
+#include "pshpack1.h"
+    struct graphic_control_extenstion
+    {
+        BYTE packed;
+        /* reservred: 3;
+         * disposal : 3;
+         * user_input_flag : 1;
+         * transparency_flag : 1;
+         */
+         USHORT delay;
+         BYTE transparent_color_index;
+    } gce_data;
+#include "poppack.h"
+    HRESULT hr;
+    ULONG bytesread, i;
+    MetadataItem *result;
+
+    *items = NULL;
+    *count = 0;
+
+    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);
+    if (!result) return E_OUTOFMEMORY;
+
+    for (i = 0; i < 5; i++)
+    {
+        PropVariantInit(&result[i].schema);
+        PropVariantInit(&result[i].id);
+        PropVariantInit(&result[i].value);
+    }
+
+    result[0].id.vt = VT_LPWSTR;
+    result[0].id.u.pwszVal = strdupAtoW("Disposal");
+    result[0].value.vt = VT_UI1;
+    result[0].value.u.bVal = (gce_data.packed >> 2) & 7;
+
+    result[1].id.vt = VT_LPWSTR;
+    result[1].id.u.pwszVal = strdupAtoW("UserInputFlag");
+    result[1].value.vt = VT_BOOL;
+    result[1].value.u.boolVal = (gce_data.packed >> 1) & 1;
+
+    result[2].id.vt = VT_LPWSTR;
+    result[2].id.u.pwszVal = strdupAtoW("TransparencyFlag");
+    result[2].value.vt = VT_BOOL;
+    result[2].value.u.boolVal = gce_data.packed & 1;
+
+    result[3].id.vt = VT_LPWSTR;
+    result[3].id.u.pwszVal = strdupAtoW("Delay");
+    result[3].value.vt = VT_UI2;
+    result[3].value.u.uiVal = gce_data.delay;
+
+    result[4].id.vt = VT_LPWSTR;
+    result[4].id.u.pwszVal = strdupAtoW("TransparentColorIndex");
+    result[4].value.vt = VT_UI1;
+    result[4].value.u.bVal = gce_data.transparent_color_index;
+
+    *items = result;
+    *count = 5;
+
+    return S_OK;
+}
+
+static const MetadataHandlerVtbl GCEReader_Vtbl = {
+    0,
+    &CLSID_WICGCEMetadataReader,
+    load_GCE_metadata
+};
+
+HRESULT GCEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
+{
+    return MetadataReader_Create(&GCEReader_Vtbl, pUnkOuter, iid, ppv);
+}
+
+static HRESULT load_APE_metadata(IStream *stream, const GUID *vendor, DWORD options,
+                                 MetadataItem **items, DWORD *count)
+{
+#include "pshpack1.h"
+    struct application_extenstion
+    {
+        BYTE extension_introducer;
+        BYTE extension_label;
+        BYTE block_size;
+        BYTE application[11];
+    } ape_data;
+#include "poppack.h"
+    HRESULT hr;
+    ULONG bytesread, data_size, i;
+    MetadataItem *result;
+    BYTE subblock_size;
+    BYTE *data;
+
+    *items = NULL;
+    *count = 0;
+
+    hr = IStream_Read(stream, &ape_data, sizeof(ape_data), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(ape_data)) return S_OK;
+    if (ape_data.extension_introducer != 0x21 ||
+        ape_data.extension_label != APPLICATION_EXT_FUNC_CODE ||
+        ape_data.block_size != 11)
+        return S_OK;
+
+    data = NULL;
+    data_size = 0;
+
+    for (;;)
+    {
+        hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
+        if (FAILED(hr) || bytesread != sizeof(subblock_size))
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            return S_OK;
+        }
+        if (!subblock_size) break;
+
+        if (!data)
+            data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
+        else
+        {
+            BYTE *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
+            if (!new_data)
+            {
+                HeapFree(GetProcessHeap(), 0, data);
+                return S_OK;
+            }
+            data = new_data;
+        }
+        data[data_size] = subblock_size;
+        hr = IStream_Read(stream, data + data_size + 1, subblock_size, &bytesread);
+        if (FAILED(hr) || bytesread != subblock_size)
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            return S_OK;
+        }
+        data_size += subblock_size + 1;
+    }
+
+    result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem) * 2);
+    if (!result)
+    {
+        HeapFree(GetProcessHeap(), 0, data);
+        return E_OUTOFMEMORY;
+    }
+
+    for (i = 0; i < 2; i++)
+    {
+        PropVariantInit(&result[i].schema);
+        PropVariantInit(&result[i].id);
+        PropVariantInit(&result[i].value);
+    }
+
+    result[0].id.vt = VT_LPWSTR;
+    result[0].id.u.pwszVal = strdupAtoW("Application");
+    result[0].value.vt = VT_UI1|VT_VECTOR;
+    result[0].value.u.caub.cElems = sizeof(ape_data.application);
+    result[0].value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, sizeof(ape_data.application));
+    memcpy(result[0].value.u.caub.pElems, ape_data.application, sizeof(ape_data.application));
+
+    result[1].id.vt = VT_LPWSTR;
+    result[1].id.u.pwszVal = strdupAtoW("Data");
+    result[1].value.vt = VT_UI1|VT_VECTOR;
+    result[1].value.u.caub.cElems = data_size;
+    result[1].value.u.caub.pElems = data;
+
+    *items = result;
+    *count = 2;
+
+    return S_OK;
+}
+
+static const MetadataHandlerVtbl APEReader_Vtbl = {
+    0,
+    &CLSID_WICAPEMetadataReader,
+    load_APE_metadata
+};
+
+HRESULT APEReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
+{
+    return MetadataReader_Create(&APEReader_Vtbl, pUnkOuter, iid, ppv);
+}
+
+static HRESULT load_GifComment_metadata(IStream *stream, const GUID *vendor, DWORD options,
+                                        MetadataItem **items, DWORD *count)
+{
+#include "pshpack1.h"
+    struct gif_extenstion
+    {
+        BYTE extension_introducer;
+        BYTE extension_label;
+    } ext_data;
+#include "poppack.h"
+    HRESULT hr;
+    ULONG bytesread, data_size;
+    MetadataItem *result;
+    BYTE subblock_size;
+    char *data;
+
+    *items = NULL;
+    *count = 0;
+
+    hr = IStream_Read(stream, &ext_data, sizeof(ext_data), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(ext_data)) return S_OK;
+    if (ext_data.extension_introducer != 0x21 ||
+        ext_data.extension_label != COMMENT_EXT_FUNC_CODE)
+        return S_OK;
+
+    data = NULL;
+    data_size = 0;
+
+    for (;;)
+    {
+        hr = IStream_Read(stream, &subblock_size, sizeof(subblock_size), &bytesread);
+        if (FAILED(hr) || bytesread != sizeof(subblock_size))
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            return S_OK;
+        }
+        if (!subblock_size) break;
+
+        if (!data)
+            data = HeapAlloc(GetProcessHeap(), 0, subblock_size + 1);
+        else
+        {
+            char *new_data = HeapReAlloc(GetProcessHeap(), 0, data, data_size + subblock_size + 1);
+            if (!new_data)
+            {
+                HeapFree(GetProcessHeap(), 0, data);
+                return S_OK;
+            }
+            data = new_data;
+        }
+        hr = IStream_Read(stream, data + data_size, subblock_size, &bytesread);
+        if (FAILED(hr) || bytesread != subblock_size)
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            return S_OK;
+        }
+        data_size += subblock_size;
+    }
+
+    data[data_size] = 0;
+
+    result = HeapAlloc(GetProcessHeap(), 0, sizeof(MetadataItem));
+    if (!result)
+    {
+        HeapFree(GetProcessHeap(), 0, data);
+        return E_OUTOFMEMORY;
+    }
+
+    PropVariantInit(&result->schema);
+    PropVariantInit(&result->id);
+    PropVariantInit(&result->value);
+
+    result->id.vt = VT_LPWSTR;
+    result->id.u.pwszVal = strdupAtoW("TextEntry");
+    result->value.vt = VT_LPSTR;
+    result->value.u.pszVal = data;
+
+    *items = result;
+    *count = 1;
+
+    return S_OK;
+}
+
+static const MetadataHandlerVtbl GifCommentReader_Vtbl = {
+    0,
+    &CLSID_WICGifCommentMetadataReader,
+    load_GifComment_metadata
+};
+
+HRESULT GifCommentReader_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void **ppv)
+{
+    return MetadataReader_Create(&GifCommentReader_Vtbl, pUnkOuter, iid, ppv);
+}
+
+static IStream *create_stream(const void *data, int data_size)
+{
+    HRESULT hr;
+    IStream *stream;
+    HGLOBAL hdata;
+    void *locked_data;
+
+    hdata = GlobalAlloc(GMEM_MOVEABLE, data_size);
+    if (!hdata) return NULL;
+
+    locked_data = GlobalLock(hdata);
+    memcpy(locked_data, data, data_size);
+    GlobalUnlock(hdata);
+
+    hr = CreateStreamOnHGlobal(hdata, TRUE, &stream);
+    return FAILED(hr) ? NULL : stream;
+}
+
+static HRESULT create_metadata_reader(const void *data, int data_size,
+                                      const CLSID *clsid, IWICMetadataReader **reader)
+{
+    HRESULT hr;
+    IWICMetadataReader *metadata_reader;
+    IWICPersistStream *persist;
+    IStream *stream;
+
+    /* FIXME: Use IWICComponentFactory_CreateMetadataReader once it's implemented */
+
+    hr = CoCreateInstance(clsid, 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;
+    }
+
+    stream = create_stream(data, data_size);
+    IWICPersistStream_LoadEx(persist, stream, NULL, WICPersistOptionsDefault);
+    IStream_Release(stream);
+
+    IWICPersistStream_Release(persist);
+
+    *reader = metadata_reader;
+    return S_OK;
+}
+
 typedef struct {
-    const IWICBitmapDecoderVtbl *lpVtbl;
+    IWICBitmapDecoder IWICBitmapDecoder_iface;
+    IWICMetadataBlockReader IWICMetadataBlockReader_iface;
+    BYTE LSD_data[13]; /* Logical Screen Descriptor */
     LONG ref;
     BOOL initialized;
     GifFileType *gif;
+    UINT current_frame;
     CRITICAL_SECTION lock;
 } GifDecoder;
 
 typedef struct {
-    const IWICBitmapFrameDecodeVtbl *lpVtbl;
+    IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
+    IWICMetadataBlockReader IWICMetadataBlockReader_iface;
     LONG ref;
     SavedImage *frame;
     GifDecoder *parent;
 } GifFrameDecode;
 
+static inline GifDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
+{
+    return CONTAINING_RECORD(iface, GifDecoder, IWICBitmapDecoder_iface);
+}
+
+static inline GifDecoder *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface)
+{
+    return CONTAINING_RECORD(iface, GifDecoder, IWICMetadataBlockReader_iface);
+}
+
+static inline GifFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
+{
+    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)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -62,7 +626,11 @@ static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapFrameDecode_iface;
+    }
+    else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
+    {
+        *ppv = &This->IWICMetadataBlockReader_iface;
     }
     else
     {
@@ -76,7 +644,7 @@ static HRESULT WINAPI GifFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
 
 static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -86,14 +654,14 @@ static ULONG WINAPI GifFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
 
 static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
     if (ref == 0)
     {
-        IUnknown_Release((IUnknown*)This->parent);
+        IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface);
         HeapFree(GetProcessHeap(), 0, This);
     }
 
@@ -103,7 +671,7 @@ static ULONG WINAPI GifFrameDecode_Release(IWICBitmapFrameDecode *iface)
 static HRESULT WINAPI GifFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p,%p)\n", iface, puiWidth, puiHeight);
 
     *puiWidth = This->frame->ImageDesc.Width;
@@ -123,14 +691,21 @@ static HRESULT WINAPI GifFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface
 static HRESULT WINAPI GifFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
     double *pDpiX, double *pDpiY)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
-    return E_NOTIMPL;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
+    const GifWord aspect_word = This->parent->gif->SAspectRatio;
+    const double aspect = (aspect_word > 0) ? ((aspect_word + 15.0) / 64.0) : 1.0;
+    TRACE("(%p,%p,%p)\n", iface, pDpiX, pDpiY);
+
+    *pDpiX = 96.0 / aspect;
+    *pDpiY = 96.0;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
     IWICPalette *pIPalette)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     WICColor colors[256];
     ColorMapObject *cm = This->frame->ImageDesc.ColorMap;
     int i, trans;
@@ -153,20 +728,18 @@ static HRESULT WINAPI GifFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
     }
 
     /* look for the transparent color extension */
-    for (i = 0; i < This->frame->ExtensionBlockCount; ++i) {
-       eb = This->frame->ExtensionBlocks + i;
-       if (eb->Function == 0xF9 && eb->ByteCount == 4) {
-           if ((eb->Bytes[0] & 1) == 1) {
-               trans = (unsigned char)eb->Bytes[3];
+    for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; ++i) {
+       eb = This->frame->Extensions.ExtensionBlocks + i;
+       if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8) {
+           if (eb->Bytes[3] & 1) {
+               trans = (unsigned char)eb->Bytes[6];
                colors[trans] &= 0xffffff; /* set alpha to 0 */
                break;
            }
        }
     }
 
-    IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
-
-    return S_OK;
+    return IWICPalette_InitializeCustom(pIPalette, colors, cm->ColorCount);
 }
 
 static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
@@ -177,9 +750,21 @@ static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
     const BYTE *src;
     BYTE *dst;
     UINT y;
+    WICRect rect;
 
-    if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
-        return E_INVALIDARG;
+    if (!rc)
+    {
+        rect.X = 0;
+        rect.Y = 0;
+        rect.Width = srcwidth;
+        rect.Height = srcheight;
+        rc = &rect;
+    }
+    else
+    {
+        if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
+            return E_INVALIDARG;
+    }
 
     if (dststride < rc->Width)
         return E_INVALIDARG;
@@ -210,7 +795,7 @@ static HRESULT copy_interlaced_pixels(const BYTE *srcbuffer,
 static HRESULT WINAPI GifFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    GifFrameDecode *This = (GifFrameDecode*)iface;
+    GifFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
 
     if (This->frame->ImageDesc.Interlace)
@@ -262,17 +847,184 @@ 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)
+{
+    GifFrameDecode *This = frame_from_IWICMetadataBlockReader(iface);
+
+    TRACE("%p,%p\n", iface, count);
+
+    if (!count) return E_INVALIDARG;
+
+    *count = This->frame->Extensions.ExtensionBlockCount + 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 - 1;
+        /* sort_flag */
+        IMD_data.packed |= This->frame->ImageDesc.ColorMap->SortFlag ? 0x20 : 0;
+    }
+
+    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);
+    int i, gce_index = -1, gce_skipped = 0;
+
+    TRACE("(%p,%u,%p)\n", iface, index, reader);
+
+    if (!reader) return E_INVALIDARG;
+
+    if (index == 0)
+        return create_IMD_metadata_reader(This, reader);
+
+    if (index >= This->frame->Extensions.ExtensionBlockCount + 1)
+        return E_INVALIDARG;
+
+    for (i = 0; i < This->frame->Extensions.ExtensionBlockCount; i++)
+    {
+        const CLSID *clsid;
+        const void *data;
+        int data_size;
+
+        if (index != i + 1 - gce_skipped) continue;
+
+        if (This->frame->Extensions.ExtensionBlocks[i].Function == GRAPHICS_EXT_FUNC_CODE)
+        {
+            gce_index = i;
+            gce_skipped = 1;
+            continue;
+        }
+        else if (This->frame->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
+        {
+            clsid = &CLSID_WICGifCommentMetadataReader;
+            data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
+            data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
+        }
+        else
+        {
+            clsid = &CLSID_WICUnknownMetadataReader;
+            data = This->frame->Extensions.ExtensionBlocks[i].Bytes;
+            data_size = This->frame->Extensions.ExtensionBlocks[i].ByteCount;
+        }
+        return create_metadata_reader(data, data_size, clsid, 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);
+}
+
+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)
 {
-    GifDecoder *This = (GifDecoder*)iface;
+    GifDecoder *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))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapDecoder, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapDecoder_iface;
+    }
+    else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid))
+    {
+        *ppv = &This->IWICMetadataBlockReader_iface;
     }
     else
     {
@@ -286,7 +1038,7 @@ static HRESULT WINAPI GifDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID
 
 static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
 {
-    GifDecoder *This = (GifDecoder*)iface;
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -296,7 +1048,7 @@ static ULONG WINAPI GifDecoder_AddRef(IWICBitmapDecoder *iface)
 
 static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
 {
-    GifDecoder *This = (GifDecoder*)iface;
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -312,11 +1064,22 @@ static ULONG WINAPI GifDecoder_Release(IWICBitmapDecoder *iface)
     return ref;
 }
 
-static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
-    DWORD *pdwCapability)
+static HRESULT WINAPI GifDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
+    DWORD *capability)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
-    return E_NOTIMPL;
+    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 = WICBitmapDecoderCapabilityCanDecodeAllImages |
+                  WICBitmapDecoderCapabilityCanDecodeSomeImages |
+                  WICBitmapDecoderCapabilityCanEnumerateMetadata;
+    return S_OK;
 }
 
 static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
@@ -338,7 +1101,7 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
 static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
     WICDecodeOptions cacheOptions)
 {
-    GifDecoder *This = (GifDecoder*)iface;
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
     LARGE_INTEGER seek;
     int ret;
 
@@ -375,6 +1138,10 @@ static HRESULT WINAPI GifDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p
     /* make sure we don't use the stream after this method returns */
     This->gif->UserData = NULL;
 
+    seek.QuadPart = 0;
+    IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL);
+    IStream_Read(pIStream, &This->LSD_data, sizeof(This->LSD_data), NULL);
+
     This->initialized = TRUE;
 
     LeaveCriticalSection(&This->lock);
@@ -408,11 +1175,49 @@ static HRESULT WINAPI GifDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     return hr;
 }
 
-static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface,
-    IWICPalette *pIPalette)
+static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalette *palette)
 {
-    TRACE("(%p,%p)\n", iface, pIPalette);
-    return WINCODEC_ERR_PALETTEUNAVAILABLE;
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
+    WICColor colors[256];
+    ColorMapObject *cm;
+    int i, trans;
+    ExtensionBlock *eb;
+
+    TRACE("(%p,%p)\n", iface, palette);
+
+    cm = This->gif->SColorMap;
+    if (!cm) return WINCODEC_ERR_FRAMEMISSING;
+
+    if (cm->ColorCount > 256)
+    {
+        ERR("GIF contains invalid number of colors: %d\n", cm->ColorCount);
+        return E_FAIL;
+    }
+
+    for (i = 0; i < cm->ColorCount; i++)
+    {
+        colors[i] = 0xff000000 | /* alpha */
+                    cm->Colors[i].Red << 16 |
+                    cm->Colors[i].Green << 8 |
+                    cm->Colors[i].Blue;
+    }
+
+    /* look for the transparent color extension */
+    for (i = 0; i < This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlockCount; i++)
+    {
+        eb = This->gif->SavedImages[This->current_frame].Extensions.ExtensionBlocks + i;
+        if (eb->Function == GRAPHICS_EXT_FUNC_CODE && eb->ByteCount == 8)
+        {
+            if (eb->Bytes[3] & 1)
+            {
+                trans = (unsigned char)eb->Bytes[6];
+                colors[trans] &= 0xffffff; /* set alpha to 0 */
+                break;
+            }
+        }
+    }
+
+    return IWICPalette_InitializeCustom(palette, colors, cm->ColorCount);
 }
 
 static HRESULT WINAPI GifDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface,
@@ -446,14 +1251,15 @@ static HRESULT WINAPI GifDecoder_GetThumbnail(IWICBitmapDecoder *iface,
 static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
     UINT *pCount)
 {
-    GifDecoder *This = (GifDecoder*)iface;
-    TRACE("(%p,%p)\n", iface, pCount);
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
 
-    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+    if (!pCount) return E_INVALIDARG;
 
-    *pCount = This->gif->ImageCount;
+    EnterCriticalSection(&This->lock);
+    *pCount = This->gif ? This->gif->ImageCount : 0;
+    LeaveCriticalSection(&This->lock);
 
-    TRACE("<- %u\n", *pCount);
+    TRACE("(%p) <-- %d\n", iface, *pCount);
 
     return S_OK;
 }
@@ -461,24 +1267,26 @@ static HRESULT WINAPI GifDecoder_GetFrameCount(IWICBitmapDecoder *iface,
 static HRESULT WINAPI GifDecoder_GetFrame(IWICBitmapDecoder *iface,
     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
 {
-    GifDecoder *This = (GifDecoder*)iface;
+    GifDecoder *This = impl_from_IWICBitmapDecoder(iface);
     GifFrameDecode *result;
     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
 
-    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+    if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
 
     if (index >= This->gif->ImageCount) return E_INVALIDARG;
 
     result = HeapAlloc(GetProcessHeap(), 0, sizeof(GifFrameDecode));
     if (!result) return E_OUTOFMEMORY;
 
-    result->lpVtbl = &GifFrameDecode_Vtbl;
+    result->IWICBitmapFrameDecode_iface.lpVtbl = &GifFrameDecode_Vtbl;
+    result->IWICMetadataBlockReader_iface.lpVtbl = &GifFrameDecode_BlockVtbl;
     result->ref = 1;
     result->frame = &This->gif->SavedImages[index];
     IWICBitmapDecoder_AddRef(iface);
     result->parent = This;
+    This->current_frame = index;
 
-    *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
+    *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
 
     return S_OK;
 }
@@ -500,6 +1308,102 @@ static const IWICBitmapDecoderVtbl GifDecoder_Vtbl = {
     GifDecoder_GetFrame
 };
 
+static HRESULT WINAPI GifDecoder_Block_QueryInterface(IWICMetadataBlockReader *iface,
+    REFIID iid, void **ppv)
+{
+    GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
+    return IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+}
+
+static ULONG WINAPI GifDecoder_Block_AddRef(IWICMetadataBlockReader *iface)
+{
+    GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
+    return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
+}
+
+static ULONG WINAPI GifDecoder_Block_Release(IWICMetadataBlockReader *iface)
+{
+    GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
+    return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
+}
+
+static HRESULT WINAPI GifDecoder_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 GifDecoder_Block_GetCount(IWICMetadataBlockReader *iface,
+    UINT *count)
+{
+    GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
+
+    TRACE("%p,%p\n", iface, count);
+
+    if (!count) return E_INVALIDARG;
+
+    *count = This->gif->Extensions.ExtensionBlockCount + 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI GifDecoder_Block_GetReaderByIndex(IWICMetadataBlockReader *iface,
+    UINT index, IWICMetadataReader **reader)
+{
+    GifDecoder *This = impl_from_IWICMetadataBlockReader(iface);
+    int i;
+
+    TRACE("(%p,%u,%p)\n", iface, index, reader);
+
+    if (!reader) return E_INVALIDARG;
+
+    if (index == 0)
+        return create_metadata_reader(This->LSD_data, sizeof(This->LSD_data),
+                                      &CLSID_WICLSDMetadataReader, reader);
+
+    for (i = 0; i < This->gif->Extensions.ExtensionBlockCount; i++)
+    {
+        const CLSID *clsid;
+
+        if (index != i + 1) continue;
+
+        if (This->gif->Extensions.ExtensionBlocks[i].Function == APPLICATION_EXT_FUNC_CODE)
+            clsid = &CLSID_WICAPEMetadataReader;
+        else if (This->gif->Extensions.ExtensionBlocks[i].Function == COMMENT_EXT_FUNC_CODE)
+            clsid = &CLSID_WICGifCommentMetadataReader;
+        else
+            clsid = &CLSID_WICUnknownMetadataReader;
+
+        return create_metadata_reader(This->gif->Extensions.ExtensionBlocks[i].Bytes,
+                                      This->gif->Extensions.ExtensionBlocks[i].ByteCount,
+                                      clsid, reader);
+    }
+
+    return E_INVALIDARG;
+}
+
+static HRESULT WINAPI GifDecoder_Block_GetEnumerator(IWICMetadataBlockReader *iface,
+    IEnumUnknown **enumerator)
+{
+    FIXME("(%p,%p): stub\n", iface, enumerator);
+    return E_NOTIMPL;
+}
+
+static const IWICMetadataBlockReaderVtbl GifDecoder_BlockVtbl =
+{
+    GifDecoder_Block_QueryInterface,
+    GifDecoder_Block_AddRef,
+    GifDecoder_Block_Release,
+    GifDecoder_Block_GetContainerFormat,
+    GifDecoder_Block_GetCount,
+    GifDecoder_Block_GetReaderByIndex,
+    GifDecoder_Block_GetEnumerator
+};
+
 HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
 {
     GifDecoder *This;
@@ -514,15 +1418,17 @@ HRESULT GifDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(GifDecoder));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &GifDecoder_Vtbl;
+    This->IWICBitmapDecoder_iface.lpVtbl = &GifDecoder_Vtbl;
+    This->IWICMetadataBlockReader_iface.lpVtbl = &GifDecoder_BlockVtbl;
     This->ref = 1;
     This->initialized = FALSE;
     This->gif = NULL;
+    This->current_frame = 0;
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifDecoder.lock");
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+    IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 
     return ret;
 }
diff --git a/reactos/dll/win32/windowscodecs/icnsformat.c b/reactos/dll/win32/windowscodecs/icnsformat.c
new file mode 100644 (file)
index 0000000..c777581
--- /dev/null
@@ -0,0 +1,789 @@
+/*
+ * Copyright 2010 Damjan Jovanovic
+ *
+ * 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>
+
+#ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H
+#define GetCurrentProcess GetCurrentProcess_Mac
+#define GetCurrentThread GetCurrentThread_Mac
+#define LoadResource LoadResource_Mac
+#define AnimatePalette AnimatePalette_Mac
+#define EqualRgn EqualRgn_Mac
+#define FillRgn FillRgn_Mac
+#define FrameRgn FrameRgn_Mac
+#define GetPixel GetPixel_Mac
+#define InvertRgn InvertRgn_Mac
+#define LineTo LineTo_Mac
+#define OffsetRgn OffsetRgn_Mac
+#define PaintRgn PaintRgn_Mac
+#define Polygon Polygon_Mac
+#define ResizePalette ResizePalette_Mac
+#define SetRectRgn SetRectRgn_Mac
+#define EqualRect EqualRect_Mac
+#define FillRect FillRect_Mac
+#define FrameRect FrameRect_Mac
+#define GetCursor GetCursor_Mac
+#define InvertRect InvertRect_Mac
+#define OffsetRect OffsetRect_Mac
+#define PtInRect PtInRect_Mac
+#define SetCursor SetCursor_Mac
+#define SetRect SetRect_Mac
+#define ShowCursor ShowCursor_Mac
+#define UnionRect UnionRect_Mac
+#include <ApplicationServices/ApplicationServices.h>
+#undef GetCurrentProcess
+#undef GetCurrentThread
+#undef LoadResource
+#undef AnimatePalette
+#undef EqualRgn
+#undef FillRgn
+#undef FrameRgn
+#undef GetPixel
+#undef InvertRgn
+#undef LineTo
+#undef OffsetRgn
+#undef PaintRgn
+#undef Polygon
+#undef ResizePalette
+#undef SetRectRgn
+#undef EqualRect
+#undef FillRect
+#undef FrameRect
+#undef GetCursor
+#undef InvertRect
+#undef OffsetRect
+#undef PtInRect
+#undef SetCursor
+#undef SetRect
+#undef ShowCursor
+#undef UnionRect
+#undef DPRINTF
+#endif
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "wincodec.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+#include "wine/library.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+#if defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) && \
+    MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
+
+typedef struct IcnsEncoder {
+    IWICBitmapEncoder IWICBitmapEncoder_iface;
+    LONG ref;
+    IStream *stream;
+    IconFamilyHandle icns_family;
+    BOOL any_frame_committed;
+    int outstanding_commits;
+    BOOL committed;
+    CRITICAL_SECTION lock;
+} IcnsEncoder;
+
+static inline IcnsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
+{
+    return CONTAINING_RECORD(iface, IcnsEncoder, IWICBitmapEncoder_iface);
+}
+
+typedef struct IcnsFrameEncode {
+    IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
+    IcnsEncoder *encoder;
+    LONG ref;
+    BOOL initialized;
+    UINT size;
+    OSType icns_type;
+    BYTE* icns_image;
+    int lines_written;
+    BOOL committed;
+} IcnsFrameEncode;
+
+static inline IcnsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
+{
+    return CONTAINING_RECORD(iface, IcnsFrameEncode, IWICBitmapFrameEncode_iface);
+}
+
+static HRESULT WINAPI IcnsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
+    void **ppv)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
+    {
+        *ppv = &This->IWICBitmapFrameEncode_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI IcnsFrameEncode_AddRef(IWICBitmapFrameEncode *iface)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IcnsFrameEncode_Release(IWICBitmapFrameEncode *iface)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        if (!This->committed)
+        {
+            EnterCriticalSection(&This->encoder->lock);
+            This->encoder->outstanding_commits--;
+            LeaveCriticalSection(&This->encoder->lock);
+        }
+        if (This->icns_image != NULL)
+            HeapFree(GetProcessHeap(), 0, This->icns_image);
+
+        IUnknown_Release((IUnknown*)This->encoder);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_Initialize(IWICBitmapFrameEncode *iface,
+    IPropertyBag2 *pIEncoderOptions)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("(%p,%p)\n", iface, pIEncoderOptions);
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (This->initialized)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+    This->initialized = TRUE;
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetSize(IWICBitmapFrameEncode *iface,
+    UINT uiWidth, UINT uiHeight)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (!This->initialized || This->icns_image)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+    if (uiWidth != uiHeight)
+    {
+        WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight);
+        hr = E_INVALIDARG;
+        goto end;
+    }
+
+    switch (uiWidth)
+    {
+        case 16:
+        case 32:
+        case 48:
+        case 128:
+        case 256:
+        case 512:
+            break;
+        default:
+            WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
+            hr = E_INVALIDARG;
+            goto end;
+    }
+
+    This->size = uiWidth;
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface,
+    double dpiX, double dpiY)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (!This->initialized || This->icns_image)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return S_OK;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (!This->initialized || This->icns_image)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+    memcpy(pPixelFormat, &GUID_WICPixelFormat32bppBGRA, sizeof(GUID));
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return S_OK;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface,
+    IWICPalette *pIPalette)
+{
+    FIXME("(%p,%p): stub\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIThumbnail)
+{
+    FIXME("(%p,%p): stub\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface,
+    UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr = S_OK;
+    UINT i;
+
+    TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (!This->initialized || !This->size)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+    if (lineCount == 0 || lineCount + This->lines_written > This->size)
+    {
+        hr = E_INVALIDARG;
+        goto end;
+    }
+
+    if (!This->icns_image)
+    {
+        switch (This->size)
+        {
+            case 16:  This->icns_type = kIconServices16PixelDataARGB;  break;
+            case 32:  This->icns_type = kIconServices32PixelDataARGB;  break;
+            case 48:  This->icns_type = kIconServices48PixelDataARGB;  break;
+            case 128: This->icns_type = kIconServices128PixelDataARGB; break;
+            case 256: This->icns_type = kIconServices256PixelDataARGB; break;
+            case 512: This->icns_type = kIconServices512PixelDataARGB; break;
+            default:
+                WARN("cannot generate ICNS icon from %dx%d image\n", This->size, This->size);
+                hr = E_INVALIDARG;
+                goto end;
+        }
+        This->icns_image = HeapAlloc(GetProcessHeap(), 0, This->size * This->size * 4);
+        if (!This->icns_image)
+        {
+            WARN("failed to allocate image buffer\n");
+            hr = E_FAIL;
+            goto end;
+        }
+    }
+
+    for (i = 0; i < lineCount; i++)
+    {
+        BYTE *src_row, *dst_row;
+        UINT j;
+        src_row = pbPixels + cbStride * i;
+        dst_row = This->icns_image + (This->lines_written + i)*(This->size*4);
+        /* swap bgr -> rgb */
+        for (j = 0; j < This->size*4; j += 4)
+        {
+            dst_row[j] = src_row[j+3];
+            dst_row[j+1] = src_row[j+2];
+            dst_row[j+2] = src_row[j+1];
+            dst_row[j+3] = src_row[j];
+        }
+    }
+    This->lines_written += lineCount;
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIBitmapSource, WICRect *prc)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr;
+    WICRect rc;
+    WICPixelFormatGUID guid;
+    UINT stride;
+    BYTE *pixeldata = NULL;
+
+    TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
+
+    if (!This->initialized || !This->size)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+    hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
+    if (FAILED(hr))
+        goto end;
+    if (!IsEqualGUID(&guid, &GUID_WICPixelFormat32bppBGRA))
+    {
+        FIXME("format %s unsupported, could use WICConvertBitmapSource to convert\n", debugstr_guid(&guid));
+        hr = E_FAIL;
+        goto end;
+    }
+
+    if (!prc)
+    {
+        UINT width, height;
+        hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
+        if (FAILED(hr))
+            goto end;
+        rc.X = 0;
+        rc.Y = 0;
+        rc.Width = width;
+        rc.Height = height;
+        prc = &rc;
+    }
+
+    if (prc->Width != This->size)
+    {
+        hr = E_INVALIDARG;
+        goto end;
+    }
+
+    stride = (32 * This->size + 7)/8;
+    pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
+    if (!pixeldata)
+    {
+        hr = E_OUTOFMEMORY;
+        goto end;
+    }
+
+    hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
+        stride*prc->Height, pixeldata);
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
+            stride*prc->Height, pixeldata);
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, pixeldata);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_Commit(IWICBitmapFrameEncode *iface)
+{
+    IcnsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface);
+    Handle handle;
+    OSErr ret;
+    HRESULT hr = S_OK;
+
+    TRACE("(%p): stub\n", iface);
+
+    EnterCriticalSection(&This->encoder->lock);
+
+    if (!This->icns_image || This->lines_written != This->size || This->committed)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+    ret = PtrToHand(This->icns_image, &handle, This->size * This->size * 4);
+    if (ret != noErr || !handle)
+    {
+        WARN("PtrToHand failed with error %d\n", ret);
+        hr = E_FAIL;
+        goto end;
+    }
+
+    ret = SetIconFamilyData(This->encoder->icns_family, This->icns_type, handle);
+    DisposeHandle(handle);
+
+    if (ret != noErr)
+       {
+        WARN("SetIconFamilyData failed for image with error %d\n", ret);
+        hr = E_FAIL;
+        goto end;
+       }
+
+    This->committed = TRUE;
+    This->encoder->any_frame_committed = TRUE;
+    This->encoder->outstanding_commits--;
+
+end:
+    LeaveCriticalSection(&This->encoder->lock);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapFrameEncodeVtbl IcnsEncoder_FrameVtbl = {
+    IcnsFrameEncode_QueryInterface,
+    IcnsFrameEncode_AddRef,
+    IcnsFrameEncode_Release,
+    IcnsFrameEncode_Initialize,
+    IcnsFrameEncode_SetSize,
+    IcnsFrameEncode_SetResolution,
+    IcnsFrameEncode_SetPixelFormat,
+    IcnsFrameEncode_SetColorContexts,
+    IcnsFrameEncode_SetPalette,
+    IcnsFrameEncode_SetThumbnail,
+    IcnsFrameEncode_WritePixels,
+    IcnsFrameEncode_WriteSource,
+    IcnsFrameEncode_Commit,
+    IcnsFrameEncode_GetMetadataQueryWriter
+};
+
+static HRESULT WINAPI IcnsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
+    void **ppv)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapEncoder, iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI IcnsEncoder_AddRef(IWICBitmapEncoder *iface)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI IcnsEncoder_Release(IWICBitmapEncoder *iface)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        This->lock.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&This->lock);
+        if (This->icns_family)
+            DisposeHandle((Handle)This->icns_family);
+        if (This->stream)
+            IStream_Release(This->stream);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI IcnsEncoder_Initialize(IWICBitmapEncoder *iface,
+    IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    HRESULT hr = S_OK;
+
+    TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->icns_family)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+    This->icns_family = (IconFamilyHandle)NewHandle(0);
+    if (!This->icns_family)
+    {
+        WARN("error creating icns family\n");
+        hr = E_FAIL;
+        goto end;
+    }
+    IStream_AddRef(pIStream);
+    This->stream = pIStream;
+
+end:
+    LeaveCriticalSection(&This->lock);
+
+    return hr;
+}
+
+static HRESULT WINAPI IcnsEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
+    GUID *pguidContainerFormat)
+{
+    FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcnsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
+    IWICBitmapEncoderInfo **ppIEncoderInfo)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcnsEncoder_SetColorContexts(IWICBitmapEncoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI IcnsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcnsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcnsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
+{
+    TRACE("(%p,%p)\n", iface, pIPreview);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
+    IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    HRESULT hr = S_OK;
+    IcnsFrameEncode *frameEncode = NULL;
+
+    TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->icns_family)
+    {
+        hr = WINCODEC_ERR_NOTINITIALIZED;
+        goto end;
+    }
+
+    hr = CreatePropertyBag2(ppIEncoderOptions);
+    if (FAILED(hr))
+        goto end;
+
+    frameEncode = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode));
+    if (frameEncode == NULL)
+    {
+        hr = E_OUTOFMEMORY;
+        goto end;
+    }
+    frameEncode->IWICBitmapFrameEncode_iface.lpVtbl = &IcnsEncoder_FrameVtbl;
+    frameEncode->encoder = This;
+    frameEncode->ref = 1;
+    frameEncode->initialized = FALSE;
+    frameEncode->size = 0;
+    frameEncode->icns_image = NULL;
+    frameEncode->lines_written = 0;
+    frameEncode->committed = FALSE;
+    *ppIFrameEncode = &frameEncode->IWICBitmapFrameEncode_iface;
+    This->outstanding_commits++;
+    IUnknown_AddRef((IUnknown*)This);
+
+end:
+    LeaveCriticalSection(&This->lock);
+
+    return hr;
+}
+
+static HRESULT WINAPI IcnsEncoder_Commit(IWICBitmapEncoder *iface)
+{
+    IcnsEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    size_t buffer_size;
+    HRESULT hr = S_OK;
+    ULONG byteswritten;
+
+    TRACE("(%p)\n", iface);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->any_frame_committed || This->outstanding_commits > 0 || This->committed)
+    {
+        hr = WINCODEC_ERR_WRONGSTATE;
+        goto end;
+    }
+
+    buffer_size = GetHandleSize((Handle)This->icns_family);
+    hr = IStream_Write(This->stream, *This->icns_family, buffer_size, &byteswritten);
+    if (FAILED(hr) || byteswritten != buffer_size)
+    {
+        WARN("writing file failed, hr = 0x%08X\n", hr);
+        hr = E_FAIL;
+        goto end;
+    }
+
+    This->committed = TRUE;
+
+end:
+    LeaveCriticalSection(&This->lock);
+    return hr;
+}
+
+static HRESULT WINAPI IcnsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapEncoderVtbl IcnsEncoder_Vtbl = {
+    IcnsEncoder_QueryInterface,
+    IcnsEncoder_AddRef,
+    IcnsEncoder_Release,
+    IcnsEncoder_Initialize,
+    IcnsEncoder_GetContainerFormat,
+    IcnsEncoder_GetEncoderInfo,
+    IcnsEncoder_SetColorContexts,
+    IcnsEncoder_SetPalette,
+    IcnsEncoder_SetThumbnail,
+    IcnsEncoder_SetPreview,
+    IcnsEncoder_CreateNewFrame,
+    IcnsEncoder_Commit,
+    IcnsEncoder_GetMetadataQueryWriter
+};
+
+HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    IcnsEncoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsEncoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IWICBitmapEncoder_iface.lpVtbl = &IcnsEncoder_Vtbl;
+    This->ref = 1;
+    This->stream = NULL;
+    This->icns_family = NULL;
+    This->any_frame_committed = FALSE;
+    This->outstanding_commits = 0;
+    This->committed = FALSE;
+    InitializeCriticalSection(&This->lock);
+    This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcnsEncoder.lock");
+
+    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
+    IUnknown_Release((IUnknown*)This);
+
+    return ret;
+}
+
+#else /* !defined(HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H) ||
+         MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4 */
+
+HRESULT IcnsEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    ERR("Trying to save ICNS picture, but ICNS support is not compiled in.\n");
+    return E_FAIL;
+}
+
+#endif
index 8012b4e..7aec245 100644 (file)
@@ -57,7 +57,7 @@ typedef struct
 #include "poppack.h"
 
 typedef struct {
-    const IWICBitmapDecoderVtbl *lpVtbl;
+    IWICBitmapDecoder IWICBitmapDecoder_iface;
     LONG ref;
     BOOL initialized;
     IStream *stream;
@@ -66,17 +66,27 @@ typedef struct {
 } IcoDecoder;
 
 typedef struct {
-    const IWICBitmapFrameDecodeVtbl *lpVtbl;
+    IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
     LONG ref;
-    ICONDIRENTRY entry;
-    IcoDecoder *parent;
+    UINT width, height;
+    double dpiX, dpiY;
     BYTE *bits;
 } IcoFrameDecode;
 
+static inline IcoDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
+{
+    return CONTAINING_RECORD(iface, IcoDecoder, IWICBitmapDecoder_iface);
+}
+
+static inline IcoFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
+{
+    return CONTAINING_RECORD(iface, IcoFrameDecode, IWICBitmapFrameDecode_iface);
+}
+
 static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
     void **ppv)
 {
-    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -85,7 +95,7 @@ static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapFrameDecode_iface;
     }
     else
     {
@@ -99,7 +109,7 @@ static HRESULT WINAPI IcoFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface
 
 static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
 {
-    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -109,14 +119,13 @@ static ULONG WINAPI IcoFrameDecode_AddRef(IWICBitmapFrameDecode *iface)
 
 static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
 {
-    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
     if (ref == 0)
     {
-        IUnknown_Release((IUnknown*)This->parent);
         HeapFree(GetProcessHeap(), 0, This->bits);
         HeapFree(GetProcessHeap(), 0, This);
     }
@@ -127,10 +136,10 @@ static ULONG WINAPI IcoFrameDecode_Release(IWICBitmapFrameDecode *iface)
 static HRESULT WINAPI IcoFrameDecode_GetSize(IWICBitmapFrameDecode *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    IcoFrameDecode *This = (IcoFrameDecode*)iface;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
 
-    *puiWidth = This->entry.bWidth ? This->entry.bWidth : 256;
-    *puiHeight = This->entry.bHeight ? This->entry.bHeight : 256;
+    *puiWidth = This->width;
+    *puiHeight = This->height;
 
     TRACE("(%p) -> (%i,%i)\n", iface, *puiWidth, *puiHeight);
 
@@ -147,8 +156,14 @@ static HRESULT WINAPI IcoFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface
 static HRESULT WINAPI IcoFrameDecode_GetResolution(IWICBitmapFrameDecode *iface,
     double *pDpiX, double *pDpiY)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
-    return E_NOTIMPL;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
+
+    *pDpiX = This->dpiX;
+    *pDpiY = This->dpiY;
+
+    TRACE("(%p) -> (%f,%f)\n", iface, *pDpiX, *pDpiY);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
@@ -158,427 +173,283 @@ static HRESULT WINAPI IcoFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface,
     return WINCODEC_ERR_PALETTEUNAVAILABLE;
 }
 
-static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
+    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    if (transparent) *pixel = 0;
-    else *pixel |= 0xff000000;
+    IcoFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface);
+    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+
+    return copy_pixels(32, This->bits, This->width, This->height, This->width * 4,
+        prc, cbStride, cbBufferSize, pbBuffer);
 }
 
-static HRESULT IcoFrameDecode_ReadPixels(IcoFrameDecode *This)
+static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
+    IWICMetadataQueryReader **ppIMetadataQueryReader)
 {
-    BITMAPINFOHEADER bih;
-    DWORD colors[256];
-    UINT colorcount=0;
-    LARGE_INTEGER seek;
-    ULONG bytesread;
-    HRESULT hr;
-    BYTE *tempdata = NULL;
-    BYTE *bits = NULL;
-    UINT bitsStride;
-    UINT bitsSize;
-    UINT width, height;
-
-    width = This->entry.bWidth ? This->entry.bWidth : 256;
-    height = This->entry.bHeight ? This->entry.bHeight : 256;
-
-    /* read the BITMAPINFOHEADER */
-    seek.QuadPart = This->entry.dwDIBOffset;
-    hr = IStream_Seek(This->parent->stream, seek, STREAM_SEEK_SET, NULL);
-    if (FAILED(hr)) goto fail;
+    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
 
-    hr = IStream_Read(This->parent->stream, &bih, sizeof(BITMAPINFOHEADER), &bytesread);
-    if (FAILED(hr) || bytesread != sizeof(BITMAPINFOHEADER)) goto fail;
+static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
+    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
+{
+    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
 
-    if (bih.biBitCount <= 8)
-    {
-        /* read the palette */
-        colorcount = bih.biClrUsed ? bih.biClrUsed : 1 << bih.biBitCount;
+static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
+    IWICBitmapSource **ppIThumbnail)
+{
+    FIXME("(%p,%p)\n", iface, ppIThumbnail);
+    return E_NOTIMPL;
+}
 
-        hr = IStream_Read(This->parent->stream, colors, sizeof(RGBQUAD)*colorcount, &bytesread);
-        if (FAILED(hr) || bytesread != sizeof(RGBQUAD)*colorcount) goto fail;
-    }
+static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
+    IcoFrameDecode_QueryInterface,
+    IcoFrameDecode_AddRef,
+    IcoFrameDecode_Release,
+    IcoFrameDecode_GetSize,
+    IcoFrameDecode_GetPixelFormat,
+    IcoFrameDecode_GetResolution,
+    IcoFrameDecode_CopyPalette,
+    IcoFrameDecode_CopyPixels,
+    IcoFrameDecode_GetMetadataQueryReader,
+    IcoFrameDecode_GetColorContexts,
+    IcoFrameDecode_GetThumbnail
+};
 
-    bitsStride = width * 4;
-    bitsSize = bitsStride * height;
+static inline void pixel_set_trans(DWORD* pixel, BOOL transparent)
+{
+    if (transparent) *pixel = 0;
+    else *pixel |= 0xff000000;
+}
 
-    /* read the XOR data */
-    switch (bih.biBitCount)
-    {
-    case 1:
+static HRESULT ReadIcoDib(IStream *stream, IcoFrameDecode *result)
+{
+    HRESULT hr;
+    BmpDecoder *bmp_decoder;
+    IWICBitmapDecoder *decoder;
+    IWICBitmapFrameDecode *framedecode;
+    WICPixelFormatGUID pixelformat;
+    IWICBitmapSource *source;
+    int has_alpha=FALSE; /* if TRUE, alpha data might be in the image data */
+    WICRect rc;
+
+    hr = IcoDibDecoder_CreateInstance(&bmp_decoder);
+    if (SUCCEEDED(hr))
     {
-        UINT xorBytesPerRow = (width+31)/32*4;
-        UINT xorBytes = xorBytesPerRow * height;
-        INT xorStride;
-        BYTE *xorRow;
-        BYTE *bitsRow;
-        UINT x, y;
-
-        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
-        if (!tempdata)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
-        }
+        BmpDecoder_GetWICDecoder(bmp_decoder, &decoder);
+        hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
 
-        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
-        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+        if (SUCCEEDED(hr))
+            hr = IWICBitmapDecoder_GetFrame(decoder, 0, &framedecode);
 
-        if (bih.biHeight > 0) /* bottom-up DIB */
-        {
-            xorStride = -xorBytesPerRow;
-            xorRow = tempdata + (height-1)*xorBytesPerRow;
-        }
-        else /* top-down DIB */
+        if (SUCCEEDED(hr))
         {
-            xorStride = xorBytesPerRow;
-            xorRow = tempdata;
-        }
+            hr = IWICBitmapFrameDecode_GetSize(framedecode, &result->width, &result->height);
 
-        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
-        /* palette-map the 1-bit data */
-        bitsRow = bits;
-        for (y=0; y<height; y++) {
-            BYTE *xorByte=xorRow;
-            DWORD *bitsPixel=(DWORD*)bitsRow;
-            for (x=0; x<width; x+=8) {
-                BYTE xorVal;
-                xorVal=*xorByte++;
-                *bitsPixel++ = colors[xorVal>>7];
-                if (x+1 < width) *bitsPixel++ = colors[xorVal>>6&1];
-                if (x+2 < width) *bitsPixel++ = colors[xorVal>>5&1];
-                if (x+3 < width) *bitsPixel++ = colors[xorVal>>4&1];
-                if (x+4 < width) *bitsPixel++ = colors[xorVal>>3&1];
-                if (x+5 < width) *bitsPixel++ = colors[xorVal>>2&1];
-                if (x+6 < width) *bitsPixel++ = colors[xorVal>>1&1];
-                if (x+7 < width) *bitsPixel++ = colors[xorVal&1];
+            if (SUCCEEDED(hr))
+            {
+                result->bits = HeapAlloc(GetProcessHeap(), 0, result->width * result->height * 4);
+                if (!result->bits) hr = E_OUTOFMEMORY;
             }
-            xorRow += xorStride;
-            bitsRow += bitsStride;
-        }
 
-        HeapFree(GetProcessHeap(), 0, tempdata);
-        break;
-    }
-    case 4:
-    {
-        UINT xorBytesPerRow = (width+7)/8*4;
-        UINT xorBytes = xorBytesPerRow * height;
-        INT xorStride;
-        BYTE *xorRow;
-        BYTE *bitsRow;
-        UINT x, y;
-
-        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
-        if (!tempdata)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
-        }
-
-        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
-        if (FAILED(hr) || bytesread != xorBytes) goto fail;
+            if (SUCCEEDED(hr))
+                hr = IWICBitmapFrameDecode_GetPixelFormat(framedecode, &pixelformat);
 
-        if (bih.biHeight > 0) /* bottom-up DIB */
-        {
-            xorStride = -xorBytesPerRow;
-            xorRow = tempdata + (height-1)*xorBytesPerRow;
-        }
-        else /* top-down DIB */
-        {
-            xorStride = xorBytesPerRow;
-            xorRow = tempdata;
-        }
-
-        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
-        /* palette-map the 4-bit data */
-        bitsRow = bits;
-        for (y=0; y<height; y++) {
-            BYTE *xorByte=xorRow;
-            DWORD *bitsPixel=(DWORD*)bitsRow;
-            for (x=0; x<width; x+=2) {
-                BYTE xorVal;
-                xorVal=*xorByte++;
-                *bitsPixel++ = colors[xorVal>>4];
-                if (x+1 < width) *bitsPixel++ = colors[xorVal&0xf];
+            if (IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGR) ||
+                IsEqualGUID(&pixelformat, &GUID_WICPixelFormat32bppBGRA))
+            {
+                source = (IWICBitmapSource*)framedecode;
+                IWICBitmapSource_AddRef(source);
+                has_alpha = TRUE;
+            }
+            else
+            {
+                hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA,
+                    (IWICBitmapSource*)framedecode, &source);
+                has_alpha = FALSE;
             }
-            xorRow += xorStride;
-            bitsRow += bitsStride;
-        }
-
-        HeapFree(GetProcessHeap(), 0, tempdata);
-        break;
-    }
-    case 8:
-    {
-        UINT xorBytesPerRow = (width+3)/4*4;
-        UINT xorBytes = xorBytesPerRow * height;
-        INT xorStride;
-        BYTE *xorRow;
-        BYTE *bitsRow;
-        UINT x, y;
-
-        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
-        if (!tempdata)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
-        }
-
-        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
-        if (FAILED(hr) || bytesread != xorBytes) goto fail;
-
-        if (bih.biHeight > 0) /* bottom-up DIB */
-        {
-            xorStride = -xorBytesPerRow;
-            xorRow = tempdata + (height-1)*xorBytesPerRow;
-        }
-        else /* top-down DIB */
-        {
-            xorStride = xorBytesPerRow;
-            xorRow = tempdata;
-        }
-
-        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
-
-        /* palette-map the 8-bit data */
-        bitsRow = bits;
-        for (y=0; y<height; y++) {
-            BYTE *xorByte=xorRow;
-            DWORD *bitsPixel=(DWORD*)bitsRow;
-            for (x=0; x<width; x++)
-                *bitsPixel++ = colors[*xorByte++];
-            xorRow += xorStride;
-            bitsRow += bitsStride;
-        }
-
-        HeapFree(GetProcessHeap(), 0, tempdata);
-        break;
-    }
-    case 24:
-    {
-        UINT xorBytesPerRow = (width*3+3)/4*4;
-        UINT xorBytes = xorBytesPerRow * height;
-        INT xorStride;
-        BYTE *xorRow;
-        BYTE *bitsRow;
-        UINT x, y;
-
-        tempdata = HeapAlloc(GetProcessHeap(), 0, xorBytes);
-        if (!tempdata)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
-        }
-
-        hr = IStream_Read(This->parent->stream, tempdata, xorBytes, &bytesread);
-        if (FAILED(hr) || bytesread != xorBytes) goto fail;
-
-        if (bih.biHeight > 0) /* bottom-up DIB */
-        {
-            xorStride = -xorBytesPerRow;
-            xorRow = tempdata + (height-1)*xorBytesPerRow;
-        }
-        else /* top-down DIB */
-        {
-            xorStride = xorBytesPerRow;
-            xorRow = tempdata;
-        }
-
-        bits = HeapAlloc(GetProcessHeap(), 0, bitsSize);
 
-        /* copy BGR->BGRA */
-        bitsRow = bits;
-        for (y=0; y<height; y++) {
-            BYTE *xorByte=xorRow;
-            BYTE *bitsByte=bitsRow;
-            for (x=0; x<width; x++)
+            if (SUCCEEDED(hr))
             {
-                *bitsByte++ = *xorByte++; /* blue */
-                *bitsByte++ = *xorByte++; /* green */
-                *bitsByte++ = *xorByte++; /* red */
-                bitsByte++; /* alpha */
+                rc.X = 0;
+                rc.Y = 0;
+                rc.Width = result->width;
+                rc.Height = result->height;
+                hr = IWICBitmapSource_CopyPixels(source, &rc, result->width * 4,
+                    result->width * result->height * 4, result->bits);
+
+                IWICBitmapSource_Release(source);
             }
-            xorRow += xorStride;
-            bitsRow += bitsStride;
-        }
 
-        HeapFree(GetProcessHeap(), 0, tempdata);
-        break;
-    }
-    case 32:
-    {
-        UINT xorBytesPerRow = width*4;
-        UINT xorBytes = xorBytesPerRow * height;
+            if (SUCCEEDED(hr))
+                hr = IWICBitmapFrameDecode_GetResolution(framedecode, &result->dpiX, &result->dpiY);
 
-        bits = HeapAlloc(GetProcessHeap(), 0, xorBytes);
-        if (!bits)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
+            IWICBitmapFrameDecode_Release(framedecode);
         }
 
-        if (bih.biHeight > 0) /* bottom-up DIB */
+        if (SUCCEEDED(hr) && has_alpha)
         {
-            /* read the rows backwards so we get a top-down DIB */
-            UINT i;
-            BYTE *xorRow = bits + xorBytesPerRow * (height-1);
+            /* If the alpha channel is fully transparent, we should ignore it. */
+            int nonzero_alpha = 0;
+            int i;
 
-            for (i=0; i<height; i++)
+            for (i=0; i<(result->height*result->width); i++)
             {
-                hr = IStream_Read(This->parent->stream, xorRow, xorBytesPerRow, &bytesread);
-                if (FAILED(hr) || bytesread != xorBytesPerRow) goto fail;
-                xorRow -= xorBytesPerRow;
+                if (result->bits[i*4+3] != 0)
+                {
+                    nonzero_alpha = 1;
+                    break;
+                }
             }
-        }
-        else /* top-down DIB */
-        {
-            hr = IStream_Read(This->parent->stream, bits, xorBytes, &bytesread);
-            if (FAILED(hr) || bytesread != xorBytes) goto fail;
-        }
-        break;
-    }
-    default:
-        FIXME("unsupported bitcount: %u\n", bih.biBitCount);
-        goto fail;
-    }
-
-    if (bih.biBitCount < 32)
-    {
-        /* set alpha data based on the AND mask */
-        UINT andBytesPerRow = (width+31)/32*4;
-        UINT andBytes = andBytesPerRow * height;
-        INT andStride;
-        BYTE *andRow;
-        BYTE *bitsRow;
-        UINT x, y;
-
-        tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
-        if (!tempdata)
-        {
-            hr = E_OUTOFMEMORY;
-            goto fail;
-        }
 
-        hr = IStream_Read(This->parent->stream, tempdata, andBytes, &bytesread);
-        if (FAILED(hr) || bytesread != andBytes) goto fail;
+            if (!nonzero_alpha)
+            {
+                for (i=0; i<(result->height*result->width); i++)
+                    result->bits[i*4+3] = 0xff;
 
-        if (bih.biHeight > 0) /* bottom-up DIB */
-        {
-            andStride = -andBytesPerRow;
-            andRow = tempdata + (height-1)*andBytesPerRow;
-        }
-        else /* top-down DIB */
-        {
-            andStride = andBytesPerRow;
-            andRow = tempdata;
+                has_alpha = FALSE;
+            }
         }
 
-        bitsRow = bits;
-        for (y=0; y<height; y++) {
-            BYTE *andByte=andRow;
-            DWORD *bitsPixel=(DWORD*)bitsRow;
-            for (x=0; x<width; x+=8) {
-                BYTE andVal=*andByte++;
-                pixel_set_trans(bitsPixel++, andVal>>7&1);
-                if (x+1 < width) pixel_set_trans(bitsPixel++, andVal>>6&1);
-                if (x+2 < width) pixel_set_trans(bitsPixel++, andVal>>5&1);
-                if (x+3 < width) pixel_set_trans(bitsPixel++, andVal>>4&1);
-                if (x+4 < width) pixel_set_trans(bitsPixel++, andVal>>3&1);
-                if (x+5 < width) pixel_set_trans(bitsPixel++, andVal>>2&1);
-                if (x+6 < width) pixel_set_trans(bitsPixel++, andVal>>1&1);
-                if (x+7 < width) pixel_set_trans(bitsPixel++, andVal&1);
+        if (SUCCEEDED(hr) && !has_alpha)
+        {
+            /* set alpha data based on the AND mask */
+            UINT andBytesPerRow = (result->width+31)/32*4;
+            UINT andBytes = andBytesPerRow * result->height;
+            INT andStride;
+            BYTE *tempdata=NULL;
+            BYTE *andRow;
+            BYTE *bitsRow;
+            UINT bitsStride = result->width * 4;
+            UINT x, y;
+            ULONG offset;
+            ULONG bytesread;
+            LARGE_INTEGER seek;
+            int topdown;
+
+            BmpDecoder_FindIconMask(bmp_decoder, &offset, &topdown);
+
+            if (offset)
+            {
+                seek.QuadPart = offset;
+
+                hr = IStream_Seek(stream, seek, STREAM_SEEK_SET, 0);
+
+                if (SUCCEEDED(hr))
+                {
+                    tempdata = HeapAlloc(GetProcessHeap(), 0, andBytes);
+                    if (!tempdata) hr = E_OUTOFMEMORY;
+                }
+
+                if (SUCCEEDED(hr))
+                    hr = IStream_Read(stream, tempdata, andBytes, &bytesread);
+
+                if (SUCCEEDED(hr) && bytesread == andBytes)
+                {
+                    if (topdown)
+                    {
+                        andStride = andBytesPerRow;
+                        andRow = tempdata;
+                    }
+                    else
+                    {
+                        andStride = -andBytesPerRow;
+                        andRow = tempdata + (result->height-1)*andBytesPerRow;
+                    }
+
+                    bitsRow = result->bits;
+                    for (y=0; y<result->height; y++) {
+                        BYTE *andByte=andRow;
+                        DWORD *bitsPixel=(DWORD*)bitsRow;
+                        for (x=0; x<result->width; x+=8) {
+                            BYTE andVal=*andByte++;
+                            pixel_set_trans(bitsPixel++, andVal>>7&1);
+                            if (x+1 < result->width) pixel_set_trans(bitsPixel++, andVal>>6&1);
+                            if (x+2 < result->width) pixel_set_trans(bitsPixel++, andVal>>5&1);
+                            if (x+3 < result->width) pixel_set_trans(bitsPixel++, andVal>>4&1);
+                            if (x+4 < result->width) pixel_set_trans(bitsPixel++, andVal>>3&1);
+                            if (x+5 < result->width) pixel_set_trans(bitsPixel++, andVal>>2&1);
+                            if (x+6 < result->width) pixel_set_trans(bitsPixel++, andVal>>1&1);
+                            if (x+7 < result->width) pixel_set_trans(bitsPixel++, andVal&1);
+                        }
+                        andRow += andStride;
+                        bitsRow += bitsStride;
+                    }
+                }
+
+                HeapFree(GetProcessHeap(), 0, tempdata);
             }
-            andRow += andStride;
-            bitsRow += bitsStride;
         }
 
-        HeapFree(GetProcessHeap(), 0, tempdata);
+        IWICBitmapDecoder_Release(decoder);
     }
 
-    This->bits = bits;
-
-    return S_OK;
-
-fail:
-    HeapFree(GetProcessHeap(), 0, tempdata);
-    HeapFree(GetProcessHeap(), 0, bits);
-    if (SUCCEEDED(hr)) hr = E_FAIL;
-    TRACE("<-- %x\n", hr);
     return hr;
 }
 
-static HRESULT WINAPI IcoFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface,
-    const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
+static HRESULT ReadIcoPng(IStream *stream, IcoFrameDecode *result)
 {
-    IcoFrameDecode *This = (IcoFrameDecode*)iface;
-    HRESULT hr=S_OK;
-    UINT width, height, stride;
-    TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
+    IWICBitmapDecoder *decoder = NULL;
+    IWICBitmapFrameDecode *sourceFrame = NULL;
+    IWICBitmapSource *sourceBitmap = NULL;
+    WICRect rect;
+    HRESULT hr;
 
-    EnterCriticalSection(&This->parent->lock);
-    if (!This->bits)
+    hr = PngDecoder_CreateInstance(NULL, &IID_IWICBitmapDecoder, (void**)&decoder);
+    if (FAILED(hr))
+        goto end;
+    hr = IWICBitmapDecoder_Initialize(decoder, stream, WICDecodeMetadataCacheOnLoad);
+    if (FAILED(hr))
+        goto end;
+    hr = IWICBitmapDecoder_GetFrame(decoder, 0, &sourceFrame);
+    if (FAILED(hr))
+        goto end;
+    hr = WICConvertBitmapSource(&GUID_WICPixelFormat32bppBGRA, (IWICBitmapSource*)sourceFrame, &sourceBitmap);
+    if (FAILED(hr))
+        goto end;
+    hr = IWICBitmapFrameDecode_GetSize(sourceFrame, &result->width, &result->height);
+    if (FAILED(hr))
+        goto end;
+    hr = IWICBitmapFrameDecode_GetResolution(sourceFrame, &result->dpiX, &result->dpiY);
+    if (FAILED(hr))
+        goto end;
+    result->bits = HeapAlloc(GetProcessHeap(), 0, 4 * result->width * result->height);
+    if (result->bits == NULL)
     {
-        hr = IcoFrameDecode_ReadPixels(This);
+        hr = E_OUTOFMEMORY;
+        goto end;
     }
-    LeaveCriticalSection(&This->parent->lock);
-    if (FAILED(hr)) return hr;
-
-    width = This->entry.bWidth ? This->entry.bWidth : 256;
-    height = This->entry.bHeight ? This->entry.bHeight : 256;
-    stride = width * 4;
-
-    return copy_pixels(32, This->bits, width, height, stride,
-        prc, cbStride, cbBufferSize, pbBuffer);
-}
-
-static HRESULT WINAPI IcoFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface,
-    IWICMetadataQueryReader **ppIMetadataQueryReader)
-{
-    TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader);
-    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
-
-static HRESULT WINAPI IcoFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface,
-    UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount)
-{
-    TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount);
-    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
-}
+    rect.X = 0;
+    rect.Y = 0;
+    rect.Width = result->width;
+    rect.Height = result->height;
+    hr = IWICBitmapSource_CopyPixels(sourceBitmap, &rect, 4*result->width,
+                                     4*result->width*result->height, result->bits);
 
-static HRESULT WINAPI IcoFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface,
-    IWICBitmapSource **ppIThumbnail)
-{
-    TRACE("(%p,%p)\n", iface, ppIThumbnail);
-    return WINCODEC_ERR_CODECNOTHUMBNAIL;
+end:
+    if (decoder != NULL)
+        IWICBitmapDecoder_Release(decoder);
+    if (sourceFrame != NULL)
+        IWICBitmapFrameDecode_Release(sourceFrame);
+    if (sourceBitmap != NULL)
+        IWICBitmapSource_Release(sourceBitmap);
+    return hr;
 }
 
-static const IWICBitmapFrameDecodeVtbl IcoFrameDecode_Vtbl = {
-    IcoFrameDecode_QueryInterface,
-    IcoFrameDecode_AddRef,
-    IcoFrameDecode_Release,
-    IcoFrameDecode_GetSize,
-    IcoFrameDecode_GetPixelFormat,
-    IcoFrameDecode_GetResolution,
-    IcoFrameDecode_CopyPalette,
-    IcoFrameDecode_CopyPixels,
-    IcoFrameDecode_GetMetadataQueryReader,
-    IcoFrameDecode_GetColorContexts,
-    IcoFrameDecode_GetThumbnail
-};
-
 static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
     void **ppv)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoDecoder *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))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapDecoder, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapDecoder_iface;
     }
     else
     {
@@ -592,7 +463,7 @@ static HRESULT WINAPI IcoDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID
 
 static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -602,7 +473,7 @@ static ULONG WINAPI IcoDecoder_AddRef(IWICBitmapDecoder *iface)
 
 static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -618,17 +489,26 @@ static ULONG WINAPI IcoDecoder_Release(IWICBitmapDecoder *iface)
     return ref;
 }
 
-static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
-    DWORD *pdwCapability)
+static HRESULT WINAPI IcoDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
+    DWORD *capability)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
-    return E_NOTIMPL;
+    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 = WICBitmapDecoderCapabilityCanDecodeAllImages;
+    return S_OK;
 }
 
 static HRESULT WINAPI IcoDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
     WICDecodeOptions cacheOptions)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
     LARGE_INTEGER seek;
     HRESULT hr;
     ULONG bytesread;
@@ -670,15 +550,27 @@ end:
 static HRESULT WINAPI IcoDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
     GUID *pguidContainerFormat)
 {
-    FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
-    return E_NOTIMPL;
+    memcpy(pguidContainerFormat, &GUID_ContainerFormatIco, sizeof(GUID));
+    return S_OK;
 }
 
 static HRESULT WINAPI IcoDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
-    return E_NOTIMPL;
+    HRESULT hr;
+    IWICComponentInfo *compinfo;
+
+    TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
+
+    hr = CreateComponentInfo(&CLSID_WICIcoDecoder, &compinfo);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void**)ppIDecoderInfo);
+
+    IWICComponentInfo_Release(compinfo);
+
+    return hr;
 }
 
 static HRESULT WINAPI IcoDecoder_CopyPalette(IWICBitmapDecoder *iface,
@@ -719,13 +611,15 @@ static HRESULT WINAPI IcoDecoder_GetThumbnail(IWICBitmapDecoder *iface,
 static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
     UINT *pCount)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
-    TRACE("(%p,%p)\n", iface, pCount);
+    IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
 
-    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+    if (!pCount) return E_INVALIDARG;
 
-    *pCount = This->header.idCount;
-    TRACE("<-- %u\n", *pCount);
+    EnterCriticalSection(&This->lock);
+    *pCount = This->initialized ? This->header.idCount : 0;
+    LeaveCriticalSection(&This->lock);
+
+    TRACE("(%p) <-- %d\n", iface, *pCount);
 
     return S_OK;
 }
@@ -733,18 +627,22 @@ static HRESULT WINAPI IcoDecoder_GetFrameCount(IWICBitmapDecoder *iface,
 static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
 {
-    IcoDecoder *This = (IcoDecoder*)iface;
+    IcoDecoder *This = impl_from_IWICBitmapDecoder(iface);
     IcoFrameDecode *result=NULL;
     LARGE_INTEGER seek;
+    ULARGE_INTEGER offset, length;
     HRESULT hr;
     ULONG bytesread;
+    ICONDIRENTRY entry;
+    IWICStream *substream=NULL;
+    DWORD magic;
     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
 
     EnterCriticalSection(&This->lock);
 
     if (!This->initialized)
     {
-        hr = WINCODEC_ERR_NOTINITIALIZED;
+        hr = WINCODEC_ERR_FRAMEMISSING;
         goto fail;
     }
 
@@ -761,9 +659,8 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
         goto fail;
     }
 
-    result->lpVtbl = &IcoFrameDecode_Vtbl;
+    result->IWICBitmapFrameDecode_iface.lpVtbl = &IcoFrameDecode_Vtbl;
     result->ref = 1;
-    result->parent = This;
     result->bits = NULL;
 
     /* read the icon entry */
@@ -771,20 +668,54 @@ static HRESULT WINAPI IcoDecoder_GetFrame(IWICBitmapDecoder *iface,
     hr = IStream_Seek(This->stream, seek, STREAM_SEEK_SET, 0);
     if (FAILED(hr)) goto fail;
 
-    hr = IStream_Read(This->stream, &result->entry, sizeof(ICONDIRENTRY), &bytesread);
+    hr = IStream_Read(This->stream, &entry, sizeof(ICONDIRENTRY), &bytesread);
     if (FAILED(hr) || bytesread != sizeof(ICONDIRENTRY)) goto fail;
 
-    IWICBitmapDecoder_AddRef(iface);
+    /* create a stream object for this icon */
+    hr = StreamImpl_Create(&substream);
+    if (FAILED(hr)) goto fail;
+
+    offset.QuadPart = entry.dwDIBOffset;
+    length.QuadPart = entry.dwDIBSize;
+    hr = IWICStream_InitializeFromIStreamRegion(substream, This->stream, offset, length);
+    if (FAILED(hr)) goto fail;
+
+    /* read the bitmapinfo size or magic number */
+    hr = IWICStream_Read(substream, &magic, sizeof(magic), &bytesread);
+    if (FAILED(hr) || bytesread != sizeof(magic)) goto fail;
+
+    /* forward to the appropriate decoding function based on the magic number */
+    switch (magic)
+    {
+    case sizeof(BITMAPCOREHEADER):
+    case 64: /* sizeof(BITMAPCOREHEADER2) */
+    case sizeof(BITMAPINFOHEADER):
+    case sizeof(BITMAPV4HEADER):
+    case sizeof(BITMAPV5HEADER):
+        hr = ReadIcoDib((IStream*)substream, result);
+        break;
+    case 0x474e5089:
+        hr = ReadIcoPng((IStream*)substream, result);
+        break;
+    default:
+        FIXME("Unrecognized ICO frame magic: %x\n", magic);
+        hr = E_FAIL;
+        break;
+    }
+    if (FAILED(hr)) goto fail;
 
-    *ppIBitmapFrame = (IWICBitmapFrameDecode*)result;
+    *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface;
 
     LeaveCriticalSection(&This->lock);
 
+    IWICStream_Release(substream);
+
     return S_OK;
 
 fail:
     LeaveCriticalSection(&This->lock);
     HeapFree(GetProcessHeap(), 0, result);
+    if (substream) IWICStream_Release(substream);
     if (SUCCEEDED(hr)) hr = E_FAIL;
     TRACE("<-- %x\n", hr);
     return hr;
@@ -821,15 +752,15 @@ HRESULT IcoDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(IcoDecoder));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &IcoDecoder_Vtbl;
+    This->IWICBitmapDecoder_iface.lpVtbl = &IcoDecoder_Vtbl;
     This->ref = 1;
     This->stream = NULL;
     This->initialized = FALSE;
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IcoDecoder.lock");
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+    IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 
     return ret;
 }
index 5c81b98..54b390b 100644 (file)
@@ -28,6 +28,7 @@
 #include "objbase.h"
 #include "shellapi.h"
 #include "wincodec.h"
+#include "wincodecsdk.h"
 
 #include "wincodecs_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
 typedef struct {
-    const IWICImagingFactoryVtbl    *lpIWICImagingFactoryVtbl;
+    IWICComponentFactory IWICComponentFactory_iface;
     LONG ref;
-} ImagingFactory;
+} ComponentFactory;
 
-static HRESULT WINAPI ImagingFactory_QueryInterface(IWICImagingFactory *iface, REFIID iid,
+static inline ComponentFactory *impl_from_IWICComponentFactory(IWICComponentFactory *iface)
+{
+    return CONTAINING_RECORD(iface, ComponentFactory, IWICComponentFactory_iface);
+}
+
+static HRESULT WINAPI ComponentFactory_QueryInterface(IWICComponentFactory *iface, REFIID iid,
     void **ppv)
 {
-    ImagingFactory *This = (ImagingFactory*)iface;
+    ComponentFactory *This = impl_from_IWICComponentFactory(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
 
-    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICImagingFactory, iid))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICImagingFactory, iid) ||
+        IsEqualIID(&IID_IWICComponentFactory, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICComponentFactory_iface;
     }
     else
     {
@@ -62,9 +70,9 @@ static HRESULT WINAPI ImagingFactory_QueryInterface(IWICImagingFactory *iface, R
     return S_OK;
 }
 
-static ULONG WINAPI ImagingFactory_AddRef(IWICImagingFactory *iface)
+static ULONG WINAPI ComponentFactory_AddRef(IWICComponentFactory *iface)
 {
-    ImagingFactory *This = (ImagingFactory*)iface;
+    ComponentFactory *This = impl_from_IWICComponentFactory(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -72,9 +80,9 @@ static ULONG WINAPI ImagingFactory_AddRef(IWICImagingFactory *iface)
     return ref;
 }
 
-static ULONG WINAPI ImagingFactory_Release(IWICImagingFactory *iface)
+static ULONG WINAPI ComponentFactory_Release(IWICComponentFactory *iface)
 {
-    ImagingFactory *This = (ImagingFactory*)iface;
+    ComponentFactory *This = impl_from_IWICComponentFactory(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -85,8 +93,8 @@ static ULONG WINAPI ImagingFactory_Release(IWICImagingFactory *iface)
     return ref;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateDecoderFromFilename(
-    IWICImagingFactory *iface, LPCWSTR wzFilename, const GUID *pguidVendor,
+static HRESULT WINAPI ComponentFactory_CreateDecoderFromFilename(
+    IWICComponentFactory *iface, LPCWSTR wzFilename, const GUID *pguidVendor,
     DWORD dwDesiredAccess, WICDecodeOptions metadataOptions,
     IWICBitmapDecoder **ppIDecoder)
 {
@@ -103,7 +111,7 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromFilename(
 
         if (SUCCEEDED(hr))
         {
-            hr = IWICImagingFactory_CreateDecoderFromStream(iface, (IStream*)stream,
+            hr = IWICComponentFactory_CreateDecoderFromStream(iface, (IStream*)stream,
                 pguidVendor, metadataOptions, ppIDecoder);
         }
 
@@ -113,27 +121,20 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromFilename(
     return hr;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateDecoderFromStream(
-    IWICImagingFactory *iface, IStream *pIStream, const GUID *pguidVendor,
-    WICDecodeOptions metadataOptions, IWICBitmapDecoder **ppIDecoder)
+static IWICBitmapDecoder *find_decoder(IStream *pIStream, const GUID *pguidVendor,
+                                       WICDecodeOptions metadataOptions)
 {
-    static int fixme=0;
     IEnumUnknown *enumdecoders;
     IUnknown *unkdecoderinfo;
     IWICBitmapDecoderInfo *decoderinfo;
-    IWICBitmapDecoder *decoder=NULL;
-    HRESULT res=S_OK;
+    IWICBitmapDecoder *decoder = NULL;
+    GUID vendor;
+    HRESULT res;
     ULONG num_fetched;
     BOOL matches;
 
-    TRACE("(%p,%p,%s,%u,%p)\n", iface, pIStream, debugstr_guid(pguidVendor),
-        metadataOptions, ppIDecoder);
-
-    if (pguidVendor && !fixme++)
-        FIXME("ignoring vendor GUID\n");
-
     res = CreateComponentEnumerator(WICDecoder, WICComponentEnumerateDefault, &enumdecoders);
-    if (FAILED(res)) return res;
+    if (FAILED(res)) return NULL;
 
     while (!decoder)
     {
@@ -145,6 +146,17 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromStream(
 
             if (SUCCEEDED(res))
             {
+                if (pguidVendor)
+                {
+                    res = IWICBitmapDecoderInfo_GetVendorGUID(decoderinfo, &vendor);
+                    if (FAILED(res) || !IsEqualIID(&vendor, pguidVendor))
+                    {
+                        IWICBitmapDecoderInfo_Release(decoderinfo);
+                        IUnknown_Release(unkdecoderinfo);
+                        continue;
+                    }
+                }
+
                 res = IWICBitmapDecoderInfo_MatchesPattern(decoderinfo, pIStream, &matches);
 
                 if (SUCCEEDED(res) && matches)
@@ -176,6 +188,24 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromStream(
 
     IEnumUnknown_Release(enumdecoders);
 
+    return decoder;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateDecoderFromStream(
+    IWICComponentFactory *iface, IStream *pIStream, const GUID *pguidVendor,
+    WICDecodeOptions metadataOptions, IWICBitmapDecoder **ppIDecoder)
+{
+    HRESULT res;
+    IWICBitmapDecoder *decoder = NULL;
+
+    TRACE("(%p,%p,%s,%u,%p)\n", iface, pIStream, debugstr_guid(pguidVendor),
+        metadataOptions, ppIDecoder);
+
+    if (pguidVendor)
+        decoder = find_decoder(pIStream, pguidVendor, metadataOptions);
+    if (!decoder)
+        decoder = find_decoder(pIStream, NULL, metadataOptions);
+
     if (decoder)
     {
         *ppIDecoder = decoder;
@@ -203,8 +233,8 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromStream(
     }
 }
 
-static HRESULT WINAPI ImagingFactory_CreateDecoderFromFileHandle(
-    IWICImagingFactory *iface, ULONG_PTR hFile, const GUID *pguidVendor,
+static HRESULT WINAPI ComponentFactory_CreateDecoderFromFileHandle(
+    IWICComponentFactory *iface, ULONG_PTR hFile, const GUID *pguidVendor,
     WICDecodeOptions metadataOptions, IWICBitmapDecoder **ppIDecoder)
 {
     FIXME("(%p,%lx,%s,%u,%p): stub\n", iface, hFile, debugstr_guid(pguidVendor),
@@ -212,104 +242,331 @@ static HRESULT WINAPI ImagingFactory_CreateDecoderFromFileHandle(
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateComponentInfo(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateComponentInfo(IWICComponentFactory *iface,
     REFCLSID clsidComponent, IWICComponentInfo **ppIInfo)
 {
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(clsidComponent), ppIInfo);
     return CreateComponentInfo(clsidComponent, ppIInfo);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateDecoder(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateDecoder(IWICComponentFactory *iface,
     REFGUID guidContainerFormat, const GUID *pguidVendor,
     IWICBitmapDecoder **ppIDecoder)
 {
-    FIXME("(%p,%s,%s,%p): stub\n", iface, debugstr_guid(guidContainerFormat),
+    IEnumUnknown *enumdecoders;
+    IUnknown *unkdecoderinfo;
+    IWICBitmapDecoderInfo *decoderinfo;
+    IWICBitmapDecoder *decoder = NULL, *preferred_decoder = NULL;
+    GUID vendor;
+    HRESULT res;
+    ULONG num_fetched;
+
+    TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(guidContainerFormat),
         debugstr_guid(pguidVendor), ppIDecoder);
-    return E_NOTIMPL;
+
+    if (!guidContainerFormat || !ppIDecoder) return E_INVALIDARG;
+
+    res = CreateComponentEnumerator(WICDecoder, WICComponentEnumerateDefault, &enumdecoders);
+    if (FAILED(res)) return res;
+
+    while (!preferred_decoder)
+    {
+        res = IEnumUnknown_Next(enumdecoders, 1, &unkdecoderinfo, &num_fetched);
+        if (res != S_OK) break;
+
+        res = IUnknown_QueryInterface(unkdecoderinfo, &IID_IWICBitmapDecoderInfo, (void **)&decoderinfo);
+        if (SUCCEEDED(res))
+        {
+            GUID container_guid;
+
+            res = IWICBitmapDecoderInfo_GetContainerFormat(decoderinfo, &container_guid);
+            if (SUCCEEDED(res) && IsEqualIID(&container_guid, guidContainerFormat))
+            {
+                IWICBitmapDecoder *new_decoder;
+
+                res = IWICBitmapDecoderInfo_CreateInstance(decoderinfo, &new_decoder);
+                if (SUCCEEDED(res))
+                {
+                    if (pguidVendor)
+                    {
+                        res = IWICBitmapDecoderInfo_GetVendorGUID(decoderinfo, &vendor);
+                        if (SUCCEEDED(res) && IsEqualIID(&vendor, pguidVendor))
+                        {
+                            preferred_decoder = new_decoder;
+                            new_decoder = NULL;
+                        }
+                    }
+
+                    if (new_decoder && !decoder)
+                    {
+                        decoder = new_decoder;
+                        new_decoder = NULL;
+                    }
+
+                    if (new_decoder) IWICBitmapDecoder_Release(new_decoder);
+                }
+            }
+
+            IWICBitmapDecoderInfo_Release(decoderinfo);
+        }
+
+        IUnknown_Release(unkdecoderinfo);
+    }
+
+    IEnumUnknown_Release(enumdecoders);
+
+    if (preferred_decoder)
+    {
+        *ppIDecoder = preferred_decoder;
+        if (decoder) IWICBitmapDecoder_Release(decoder);
+        return S_OK;
+    }
+
+    if (decoder)
+    {
+        *ppIDecoder = decoder;
+        return S_OK;
+    }
+
+    *ppIDecoder = NULL;
+    return WINCODEC_ERR_COMPONENTNOTFOUND;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateEncoder(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateEncoder(IWICComponentFactory *iface,
     REFGUID guidContainerFormat, const GUID *pguidVendor,
     IWICBitmapEncoder **ppIEncoder)
 {
-    FIXME("(%p,%s,%s,%p): stub\n", iface, debugstr_guid(guidContainerFormat),
+    static int fixme=0;
+    IEnumUnknown *enumencoders;
+    IUnknown *unkencoderinfo;
+    IWICBitmapEncoderInfo *encoderinfo;
+    IWICBitmapEncoder *encoder=NULL;
+    HRESULT res=S_OK;
+    ULONG num_fetched;
+    GUID actual_containerformat;
+
+    TRACE("(%p,%s,%s,%p)\n", iface, debugstr_guid(guidContainerFormat),
         debugstr_guid(pguidVendor), ppIEncoder);
-    return E_NOTIMPL;
+
+    if (pguidVendor && !fixme++)
+        FIXME("ignoring vendor GUID\n");
+
+    res = CreateComponentEnumerator(WICEncoder, WICComponentEnumerateDefault, &enumencoders);
+    if (FAILED(res)) return res;
+
+    while (!encoder)
+    {
+        res = IEnumUnknown_Next(enumencoders, 1, &unkencoderinfo, &num_fetched);
+
+        if (res == S_OK)
+        {
+            res = IUnknown_QueryInterface(unkencoderinfo, &IID_IWICBitmapEncoderInfo, (void**)&encoderinfo);
+
+            if (SUCCEEDED(res))
+            {
+                res = IWICBitmapEncoderInfo_GetContainerFormat(encoderinfo, &actual_containerformat);
+
+                if (SUCCEEDED(res) && IsEqualGUID(guidContainerFormat, &actual_containerformat))
+                {
+                    res = IWICBitmapEncoderInfo_CreateInstance(encoderinfo, &encoder);
+                    if (FAILED(res))
+                        encoder = NULL;
+                }
+
+                IWICBitmapEncoderInfo_Release(encoderinfo);
+            }
+
+            IUnknown_Release(unkencoderinfo);
+        }
+        else
+            break;
+    }
+
+    IEnumUnknown_Release(enumencoders);
+
+    if (encoder)
+    {
+        *ppIEncoder = encoder;
+        return S_OK;
+    }
+    else
+    {
+        WARN("failed to create encoder\n");
+        *ppIEncoder = NULL;
+        return WINCODEC_ERR_COMPONENTNOTFOUND;
+    }
 }
 
-static HRESULT WINAPI ImagingFactory_CreatePalette(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreatePalette(IWICComponentFactory *iface,
     IWICPalette **ppIPalette)
 {
     TRACE("(%p,%p)\n", iface, ppIPalette);
     return PaletteImpl_Create(ppIPalette);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateFormatConverter(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateFormatConverter(IWICComponentFactory *iface,
     IWICFormatConverter **ppIFormatConverter)
 {
     return FormatConverter_CreateInstance(NULL, &IID_IWICFormatConverter, (void**)ppIFormatConverter);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapScaler(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapScaler(IWICComponentFactory *iface,
     IWICBitmapScaler **ppIBitmapScaler)
 {
-    FIXME("(%p,%p): stub\n", iface, ppIBitmapScaler);
-    return E_NOTIMPL;
+    TRACE("(%p,%p)\n", iface, ppIBitmapScaler);
+
+    return BitmapScaler_Create(ppIBitmapScaler);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapClipper(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapClipper(IWICComponentFactory *iface,
     IWICBitmapClipper **ppIBitmapClipper)
 {
     FIXME("(%p,%p): stub\n", iface, ppIBitmapClipper);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFlipRotator(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFlipRotator(IWICComponentFactory *iface,
     IWICBitmapFlipRotator **ppIBitmapFlipRotator)
 {
     TRACE("(%p,%p)\n", iface, ppIBitmapFlipRotator);
     return FlipRotator_Create(ppIBitmapFlipRotator);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateStream(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateStream(IWICComponentFactory *iface,
     IWICStream **ppIWICStream)
 {
     TRACE("(%p,%p)\n", iface, ppIWICStream);
     return StreamImpl_Create(ppIWICStream);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateColorContext(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateColorContext(IWICComponentFactory *iface,
     IWICColorContext **ppIColorContext)
 {
-    FIXME("(%p,%p): stub\n", iface, ppIColorContext);
-    return E_NOTIMPL;
+    TRACE("(%p,%p)\n", iface, ppIColorContext);
+    return ColorContext_Create(ppIColorContext);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateColorTransformer(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateColorTransformer(IWICComponentFactory *iface,
     IWICColorTransform **ppIColorTransform)
 {
     FIXME("(%p,%p): stub\n", iface, ppIColorTransform);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmap(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmap(IWICComponentFactory *iface,
     UINT uiWidth, UINT uiHeight, REFWICPixelFormatGUID pixelFormat,
     WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap)
 {
-    FIXME("(%p,%u,%u,%s,%u,%p): stub\n", iface, uiWidth, uiHeight,
+    TRACE("(%p,%u,%u,%s,%u,%p)\n", iface, uiWidth, uiHeight,
         debugstr_guid(pixelFormat), option, ppIBitmap);
-    return E_NOTIMPL;
+    return BitmapImpl_Create(uiWidth, uiHeight, pixelFormat, option, ppIBitmap);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFromSource(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFromSource(IWICComponentFactory *iface,
     IWICBitmapSource *piBitmapSource, WICBitmapCreateCacheOption option,
     IWICBitmap **ppIBitmap)
 {
-    FIXME("(%p,%p,%u,%p): stub\n", iface, piBitmapSource, option, ppIBitmap);
-    return E_NOTIMPL;
+    IWICBitmap *result;
+    IWICBitmapLock *lock;
+    IWICPalette *palette;
+    UINT width, height;
+    WICPixelFormatGUID pixelformat = {0};
+    HRESULT hr;
+    WICRect rc;
+    double dpix, dpiy;
+    IWICComponentInfo *info;
+    IWICPixelFormatInfo2 *formatinfo;
+    WICPixelFormatNumericRepresentation format_type;
+
+    TRACE("(%p,%p,%u,%p)\n", iface, piBitmapSource, option, ppIBitmap);
+
+    if (!piBitmapSource || !ppIBitmap)
+        return E_INVALIDARG;
+
+    hr = IWICBitmapSource_GetSize(piBitmapSource, &width, &height);
+
+    if (SUCCEEDED(hr))
+        hr = IWICBitmapSource_GetPixelFormat(piBitmapSource, &pixelformat);
+
+    if (SUCCEEDED(hr))
+        hr = CreateComponentInfo(&pixelformat, &info);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICComponentInfo_QueryInterface(info, &IID_IWICPixelFormatInfo2, (void**)&formatinfo);
+
+        if (SUCCEEDED(hr))
+        {
+            hr = IWICPixelFormatInfo2_GetNumericRepresentation(formatinfo, &format_type);
+
+            IWICPixelFormatInfo2_Release(formatinfo);
+        }
+
+        IWICComponentInfo_Release(info);
+    }
+
+    if (SUCCEEDED(hr))
+        hr = BitmapImpl_Create(width, height, &pixelformat, option, &result);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICBitmap_Lock(result, NULL, WICBitmapLockWrite, &lock);
+        if (SUCCEEDED(hr))
+        {
+            UINT stride, buffersize;
+            BYTE *buffer;
+            rc.X = rc.Y = 0;
+            rc.Width = width;
+            rc.Height = height;
+
+            hr = IWICBitmapLock_GetStride(lock, &stride);
+
+            if (SUCCEEDED(hr))
+                hr = IWICBitmapLock_GetDataPointer(lock, &buffersize, &buffer);
+
+            if (SUCCEEDED(hr))
+                hr = IWICBitmapSource_CopyPixels(piBitmapSource, &rc, stride,
+                    buffersize, buffer);
+
+            IWICBitmapLock_Release(lock);
+        }
+
+        if (SUCCEEDED(hr))
+            hr = PaletteImpl_Create(&palette);
+
+        if (SUCCEEDED(hr) && (format_type == WICPixelFormatNumericRepresentationUnspecified ||
+                              format_type == WICPixelFormatNumericRepresentationIndexed))
+        {
+            hr = IWICBitmapSource_CopyPalette(piBitmapSource, palette);
+
+            if (SUCCEEDED(hr))
+                hr = IWICBitmap_SetPalette(result, palette);
+            else
+                hr = S_OK;
+
+            IWICPalette_Release(palette);
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            hr = IWICBitmapSource_GetResolution(piBitmapSource, &dpix, &dpiy);
+
+            if (SUCCEEDED(hr))
+                hr = IWICBitmap_SetResolution(result, dpix, dpiy);
+            else
+                hr = S_OK;
+        }
+
+        if (SUCCEEDED(hr))
+            *ppIBitmap = result;
+        else
+            IWICBitmap_Release(result);
+    }
+
+    return hr;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFromSourceRect(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFromSourceRect(IWICComponentFactory *iface,
     IWICBitmapSource *piBitmapSource, UINT x, UINT y, UINT width, UINT height,
     IWICBitmap **ppIBitmap)
 {
@@ -318,7 +575,7 @@ static HRESULT WINAPI ImagingFactory_CreateBitmapFromSourceRect(IWICImagingFacto
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFromMemory(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFactory *iface,
     UINT uiWidth, UINT uiHeight, REFWICPixelFormatGUID pixelFormat, UINT cbStride,
     UINT cbBufferSize, BYTE *pbBuffer, IWICBitmap **ppIBitmap)
 {
@@ -327,7 +584,7 @@ static HRESULT WINAPI ImagingFactory_CreateBitmapFromMemory(IWICImagingFactory *
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFromHBITMAP(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFactory *iface,
     HBITMAP hBitmap, HPALETTE hPalette, WICBitmapAlphaChannelOption options,
     IWICBitmap **ppIBitmap)
 {
@@ -335,37 +592,37 @@ static HRESULT WINAPI ImagingFactory_CreateBitmapFromHBITMAP(IWICImagingFactory
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateBitmapFromHICON(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateBitmapFromHICON(IWICComponentFactory *iface,
     HICON hIcon, IWICBitmap **ppIBitmap)
 {
     FIXME("(%p,%p,%p): stub\n", iface, hIcon, ppIBitmap);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateComponentEnumerator(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateComponentEnumerator(IWICComponentFactory *iface,
     DWORD componentTypes, DWORD options, IEnumUnknown **ppIEnumUnknown)
 {
     TRACE("(%p,%u,%u,%p)\n", iface, componentTypes, options, ppIEnumUnknown);
     return CreateComponentEnumerator(componentTypes, options, ppIEnumUnknown);
 }
 
-static HRESULT WINAPI ImagingFactory_CreateFastMetadataEncoderFromDecoder(
-    IWICImagingFactory *iface, IWICBitmapDecoder *pIDecoder,
+static HRESULT WINAPI ComponentFactory_CreateFastMetadataEncoderFromDecoder(
+    IWICComponentFactory *iface, IWICBitmapDecoder *pIDecoder,
     IWICFastMetadataEncoder **ppIFastEncoder)
 {
     FIXME("(%p,%p,%p): stub\n", iface, pIDecoder, ppIFastEncoder);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateFastMetadataEncoderFromFrameDecode(
-    IWICImagingFactory *iface, IWICBitmapFrameDecode *pIFrameDecoder,
+static HRESULT WINAPI ComponentFactory_CreateFastMetadataEncoderFromFrameDecode(
+    IWICComponentFactory *iface, IWICBitmapFrameDecode *pIFrameDecoder,
     IWICFastMetadataEncoder **ppIFastEncoder)
 {
     FIXME("(%p,%p,%p): stub\n", iface, pIFrameDecoder, ppIFastEncoder);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateQueryWriter(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateQueryWriter(IWICComponentFactory *iface,
     REFGUID guidMetadataFormat, const GUID *pguidVendor,
     IWICMetadataQueryWriter **ppIQueryWriter)
 {
@@ -374,7 +631,7 @@ static HRESULT WINAPI ImagingFactory_CreateQueryWriter(IWICImagingFactory *iface
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI ImagingFactory_CreateQueryWriterFromReader(IWICImagingFactory *iface,
+static HRESULT WINAPI ComponentFactory_CreateQueryWriterFromReader(IWICComponentFactory *iface,
     IWICMetadataQueryReader *pIQueryReader, const GUID *pguidVendor,
     IWICMetadataQueryWriter **ppIQueryWriter)
 {
@@ -383,40 +640,98 @@ static HRESULT WINAPI ImagingFactory_CreateQueryWriterFromReader(IWICImagingFact
     return E_NOTIMPL;
 }
 
-static const IWICImagingFactoryVtbl ImagingFactory_Vtbl = {
-    ImagingFactory_QueryInterface,
-    ImagingFactory_AddRef,
-    ImagingFactory_Release,
-    ImagingFactory_CreateDecoderFromFilename,
-    ImagingFactory_CreateDecoderFromStream,
-    ImagingFactory_CreateDecoderFromFileHandle,
-    ImagingFactory_CreateComponentInfo,
-    ImagingFactory_CreateDecoder,
-    ImagingFactory_CreateEncoder,
-    ImagingFactory_CreatePalette,
-    ImagingFactory_CreateFormatConverter,
-    ImagingFactory_CreateBitmapScaler,
-    ImagingFactory_CreateBitmapClipper,
-    ImagingFactory_CreateBitmapFlipRotator,
-    ImagingFactory_CreateStream,
-    ImagingFactory_CreateColorContext,
-    ImagingFactory_CreateColorTransformer,
-    ImagingFactory_CreateBitmap,
-    ImagingFactory_CreateBitmapFromSource,
-    ImagingFactory_CreateBitmapFromSourceRect,
-    ImagingFactory_CreateBitmapFromMemory,
-    ImagingFactory_CreateBitmapFromHBITMAP,
-    ImagingFactory_CreateBitmapFromHICON,
-    ImagingFactory_CreateComponentEnumerator,
-    ImagingFactory_CreateFastMetadataEncoderFromDecoder,
-    ImagingFactory_CreateFastMetadataEncoderFromFrameDecode,
-    ImagingFactory_CreateQueryWriter,
-    ImagingFactory_CreateQueryWriterFromReader
+static HRESULT WINAPI ComponentFactory_CreateMetadataReader(IWICComponentFactory *iface,
+        REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader)
+{
+    FIXME("%p,%s,%s,%x,%p,%p: stub\n", iface, debugstr_guid(format), debugstr_guid(vendor),
+        options, stream, reader);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateMetadataReaderFromContainer(IWICComponentFactory *iface,
+        REFGUID format, const GUID *vendor, DWORD options, IStream *stream, IWICMetadataReader **reader)
+{
+    FIXME("%p,%s,%s,%x,%p,%p: stub\n", iface, debugstr_guid(format), debugstr_guid(vendor),
+        options, stream, reader);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateMetadataWriter(IWICComponentFactory *iface,
+        REFGUID format, const GUID *vendor, DWORD options, IWICMetadataWriter **writer)
+{
+    FIXME("%p,%s,%s,%x,%p: stub\n", iface, debugstr_guid(format), debugstr_guid(vendor), options, writer);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateMetadataWriterFromReader(IWICComponentFactory *iface,
+        IWICMetadataReader *reader, const GUID *vendor, IWICMetadataWriter **writer)
+{
+    FIXME("%p,%p,%s,%p: stub\n", iface, reader, debugstr_guid(vendor), writer);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateQueryReaderFromBlockReader(IWICComponentFactory *iface,
+        IWICMetadataBlockReader *block_reader, IWICMetadataQueryReader **query_reader)
+{
+    FIXME("%p,%p,%p: stub\n", iface, block_reader, query_reader);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateQueryWriterFromBlockWriter(IWICComponentFactory *iface,
+        IWICMetadataBlockWriter *block_writer, IWICMetadataQueryWriter **query_writer)
+{
+    FIXME("%p,%p,%p: stub\n", iface, block_writer, query_writer);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI ComponentFactory_CreateEncoderPropertyBag(IWICComponentFactory *iface,
+        PROPBAG2 *options, UINT count, IPropertyBag2 **property)
+{
+    FIXME("%p,%p,%u,%p: stub\n", iface, options, count, property);
+    return E_NOTIMPL;
+}
+
+static const IWICComponentFactoryVtbl ComponentFactory_Vtbl = {
+    ComponentFactory_QueryInterface,
+    ComponentFactory_AddRef,
+    ComponentFactory_Release,
+    ComponentFactory_CreateDecoderFromFilename,
+    ComponentFactory_CreateDecoderFromStream,
+    ComponentFactory_CreateDecoderFromFileHandle,
+    ComponentFactory_CreateComponentInfo,
+    ComponentFactory_CreateDecoder,
+    ComponentFactory_CreateEncoder,
+    ComponentFactory_CreatePalette,
+    ComponentFactory_CreateFormatConverter,
+    ComponentFactory_CreateBitmapScaler,
+    ComponentFactory_CreateBitmapClipper,
+    ComponentFactory_CreateBitmapFlipRotator,
+    ComponentFactory_CreateStream,
+    ComponentFactory_CreateColorContext,
+    ComponentFactory_CreateColorTransformer,
+    ComponentFactory_CreateBitmap,
+    ComponentFactory_CreateBitmapFromSource,
+    ComponentFactory_CreateBitmapFromSourceRect,
+    ComponentFactory_CreateBitmapFromMemory,
+    ComponentFactory_CreateBitmapFromHBITMAP,
+    ComponentFactory_CreateBitmapFromHICON,
+    ComponentFactory_CreateComponentEnumerator,
+    ComponentFactory_CreateFastMetadataEncoderFromDecoder,
+    ComponentFactory_CreateFastMetadataEncoderFromFrameDecode,
+    ComponentFactory_CreateQueryWriter,
+    ComponentFactory_CreateQueryWriterFromReader,
+    ComponentFactory_CreateMetadataReader,
+    ComponentFactory_CreateMetadataReaderFromContainer,
+    ComponentFactory_CreateMetadataWriter,
+    ComponentFactory_CreateMetadataWriterFromReader,
+    ComponentFactory_CreateQueryReaderFromBlockReader,
+    ComponentFactory_CreateQueryWriterFromBlockWriter,
+    ComponentFactory_CreateEncoderPropertyBag
 };
 
-HRESULT ImagingFactory_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+HRESULT ComponentFactory_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
 {
-    ImagingFactory *This;
+    ComponentFactory *This;
     HRESULT ret;
 
     TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
@@ -425,14 +740,14 @@ HRESULT ImagingFactory_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** pp
 
     if (pUnkOuter) return CLASS_E_NOAGGREGATION;
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ImagingFactory));
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(ComponentFactory));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpIWICImagingFactoryVtbl = &ImagingFactory_Vtbl;
+    This->IWICComponentFactory_iface.lpVtbl = &ComponentFactory_Vtbl;
     This->ref = 1;
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICComponentFactory_QueryInterface(&This->IWICComponentFactory_iface, iid, ppv);
+    IWICComponentFactory_Release(&This->IWICComponentFactory_iface);
 
     return ret;
 }
index f790dbc..3da5b20 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2009 Vincent Povirk for CodeWeavers
+ * Copyright 2012 Dmitry Timoshkov
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -27,6 +28,7 @@
 #include "winreg.h"
 #include "objbase.h"
 #include "wincodec.h"
+#include "wincodecsdk.h"
 
 #include "wincodecs_private.h"
 
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
-static WCHAR const pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
+static const WCHAR mimetypes_valuename[] = {'M','i','m','e','T','y','p','e','s',0};
+static const WCHAR author_valuename[] = {'A','u','t','h','o','r',0};
+static const WCHAR friendlyname_valuename[] = {'F','r','i','e','n','d','l','y','N','a','m','e',0};
+static const WCHAR pixelformats_keyname[] = {'P','i','x','e','l','F','o','r','m','a','t','s',0};
+static const WCHAR formats_keyname[] = {'F','o','r','m','a','t','s',0};
+static const WCHAR containerformat_valuename[] = {'C','o','n','t','a','i','n','e','r','F','o','r','m','a','t',0};
+static const WCHAR metadataformat_valuename[] = {'M','e','t','a','d','a','t','a','F','o','r','m','a','t',0};
+static const WCHAR vendor_valuename[] = {'V','e','n','d','o','r',0};
+static const WCHAR version_valuename[] = {'V','e','r','s','i','o','n',0};
+static const WCHAR specversion_valuename[] = {'S','p','e','c','V','e','r','s','i','o','n',0};
+static const WCHAR bitsperpixel_valuename[] = {'B','i','t','L','e','n','g','t','h',0};
+static const WCHAR channelcount_valuename[] = {'C','h','a','n','n','e','l','C','o','u','n','t',0};
+static const WCHAR channelmasks_keyname[] = {'C','h','a','n','n','e','l','M','a','s','k','s',0};
+static const WCHAR numericrepresentation_valuename[] = {'N','u','m','e','r','i','c','R','e','p','r','e','s','e','n','t','a','t','i','o','n',0};
+static const WCHAR supportstransparency_valuename[] = {'S','u','p','p','o','r','t','s','T','r','a','n','s','p','a','r','e','n','c','y',0};
+static const WCHAR requiresfullstream_valuename[] = {'R','e','q','u','i','r','e','s','F','u','l','l','S','t','r','e','a','m',0};
+static const WCHAR supportspadding_valuename[] = {'S','u','p','p','o','r','t','s','P','a','d','d','i','n','g',0};
+static const WCHAR fileextensions_valuename[] = {'F','i','l','e','E','x','t','e','n','s','i','o','n','s',0};
+
+static HRESULT ComponentInfo_GetStringValue(HKEY classkey, LPCWSTR value,
+    UINT buffer_size, WCHAR *buffer, UINT *actual_size)
+{
+    LONG ret;
+    DWORD cbdata=buffer_size * sizeof(WCHAR);
+
+    if (!actual_size)
+        return E_INVALIDARG;
+
+    ret = RegGetValueW(classkey, NULL, value, RRF_RT_REG_SZ|RRF_NOEXPAND, NULL,
+        buffer, &cbdata);
+
+    if (ret == ERROR_FILE_NOT_FOUND)
+    {
+        *actual_size = 0;
+        return S_OK;
+    }
+
+    if (ret == 0 || ret == ERROR_MORE_DATA)
+        *actual_size = cbdata/sizeof(WCHAR);
+
+    if (!buffer && buffer_size != 0)
+        /* Yes, native returns the correct size in this case. */
+        return E_INVALIDARG;
+
+    if (ret == ERROR_MORE_DATA)
+        return WINCODEC_ERR_INSUFFICIENTBUFFER;
+
+    return HRESULT_FROM_WIN32(ret);
+}
+
+static HRESULT ComponentInfo_GetGUIDValue(HKEY classkey, LPCWSTR value,
+    GUID *result)
+{
+    LONG ret;
+    WCHAR guid_string[39];
+    DWORD cbdata = sizeof(guid_string);
+    HRESULT hr;
+
+    if (!result)
+        return E_INVALIDARG;
+
+    ret = RegGetValueW(classkey, NULL, value, RRF_RT_REG_SZ|RRF_NOEXPAND, NULL,
+        guid_string, &cbdata);
+
+    if (ret != ERROR_SUCCESS)
+        return HRESULT_FROM_WIN32(ret);
+
+    if (cbdata < sizeof(guid_string))
+    {
+        ERR("incomplete GUID value\n");
+        return E_FAIL;
+    }
+
+    hr = CLSIDFromString(guid_string, result);
+
+    return hr;
+}
+
+static HRESULT ComponentInfo_GetDWORDValue(HKEY classkey, LPCWSTR value,
+    DWORD *result)
+{
+    LONG ret;
+    DWORD cbdata = sizeof(DWORD);
+
+    if (!result)
+        return E_INVALIDARG;
+
+    ret = RegGetValueW(classkey, NULL, value, RRF_RT_DWORD, NULL,
+        result, &cbdata);
+
+    if (ret == ERROR_FILE_NOT_FOUND)
+    {
+        *result = 0;
+        return S_OK;
+    }
+
+    return HRESULT_FROM_WIN32(ret);
+}
+
+static HRESULT ComponentInfo_GetGuidList(HKEY classkey, LPCWSTR subkeyname,
+    UINT buffersize, GUID *buffer, UINT *actual_size)
+{
+    LONG ret;
+    HKEY subkey;
+    UINT items_returned;
+    WCHAR guid_string[39];
+    DWORD guid_string_size;
+    HRESULT hr=S_OK;
+
+    if (!actual_size)
+        return E_INVALIDARG;
+
+    ret = RegOpenKeyExW(classkey, subkeyname, 0, KEY_READ, &subkey);
+    if (ret != ERROR_SUCCESS) return HRESULT_FROM_WIN32(ret);
+
+    if (buffer)
+    {
+        items_returned = 0;
+        guid_string_size = 39;
+        while (items_returned < buffersize)
+        {
+            ret = RegEnumKeyExW(subkey, items_returned, guid_string,
+                &guid_string_size, NULL, NULL, NULL, NULL);
+
+            if (ret != ERROR_SUCCESS)
+            {
+                hr = HRESULT_FROM_WIN32(ret);
+                break;
+            }
+
+            if (guid_string_size != 38)
+            {
+                hr = E_FAIL;
+                break;
+            }
+
+            hr = CLSIDFromString(guid_string, &buffer[items_returned]);
+            if (FAILED(hr))
+                break;
+
+            items_returned++;
+            guid_string_size = 39;
+        }
+
+        if (ret == ERROR_NO_MORE_ITEMS)
+            hr = S_OK;
+
+        *actual_size = items_returned;
+    }
+    else
+    {
+        ret = RegQueryInfoKeyW(subkey, NULL, NULL, NULL, actual_size, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+        if (ret != ERROR_SUCCESS)
+            hr = HRESULT_FROM_WIN32(ret);
+    }
+
+    RegCloseKey(subkey);
+
+    return hr;
+}
 
 typedef struct {
-    const IWICBitmapDecoderInfoVtbl *lpIWICBitmapDecoderInfoVtbl;
+    IWICBitmapDecoderInfo IWICBitmapDecoderInfo_iface;
     LONG ref;
     HKEY classkey;
     CLSID clsid;
 } BitmapDecoderInfo;
 
+static inline BitmapDecoderInfo *impl_from_IWICBitmapDecoderInfo(IWICBitmapDecoderInfo *iface)
+{
+    return CONTAINING_RECORD(iface, BitmapDecoderInfo, IWICBitmapDecoderInfo_iface);
+}
+
 static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *iface, REFIID iid,
     void **ppv)
 {
-    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -72,7 +238,7 @@ static HRESULT WINAPI BitmapDecoderInfo_QueryInterface(IWICBitmapDecoderInfo *if
 
 static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
 {
-    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -82,7 +248,7 @@ static ULONG WINAPI BitmapDecoderInfo_AddRef(IWICBitmapDecoderInfo *iface)
 
 static ULONG WINAPI BitmapDecoderInfo_Release(IWICBitmapDecoderInfo *iface)
 {
-    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -100,14 +266,22 @@ static HRESULT WINAPI BitmapDecoderInfo_GetComponentType(IWICBitmapDecoderInfo *
     WICComponentType *pType)
 {
     TRACE("(%p,%p)\n", iface, pType);
+    if (!pType) return E_INVALIDARG;
     *pType = WICDecoder;
     return S_OK;
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetCLSID(IWICBitmapDecoderInfo *iface, CLSID *pclsid)
 {
-    FIXME("(%p,%p): stub\n", iface, pclsid);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+    TRACE("(%p,%p)\n", iface, pclsid);
+
+    if (!pclsid)
+        return E_INVALIDARG;
+
+    memcpy(pclsid, &This->clsid, sizeof(CLSID));
+
+    return S_OK;
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *iface, DWORD *pStatus)
@@ -119,49 +293,70 @@ static HRESULT WINAPI BitmapDecoderInfo_GetSigningStatus(IWICBitmapDecoderInfo *
 static HRESULT WINAPI BitmapDecoderInfo_GetAuthor(IWICBitmapDecoderInfo *iface, UINT cchAuthor,
     WCHAR *wzAuthor, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, author_valuename,
+        cchAuthor, wzAuthor, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetVendorGUID(IWICBitmapDecoderInfo *iface, GUID *pguidVendor)
 {
-    FIXME("(%p,%p): stub\n", iface, pguidVendor);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, pguidVendor);
+
+    return ComponentInfo_GetGUIDValue(This->classkey, vendor_valuename, pguidVendor);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetVersion(IWICBitmapDecoderInfo *iface, UINT cchVersion,
     WCHAR *wzVersion, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, version_valuename,
+        cchVersion, wzVersion, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetSpecVersion(IWICBitmapDecoderInfo *iface, UINT cchSpecVersion,
     WCHAR *wzSpecVersion, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, specversion_valuename,
+        cchSpecVersion, wzSpecVersion, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetFriendlyName(IWICBitmapDecoderInfo *iface, UINT cchFriendlyName,
     WCHAR *wzFriendlyName, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, friendlyname_valuename,
+        cchFriendlyName, wzFriendlyName, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetContainerFormat(IWICBitmapDecoderInfo *iface,
     GUID *pguidContainerFormat)
 {
-    FIXME("(%p,%p): stub\n", iface, pguidContainerFormat);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+    TRACE("(%p,%p)\n", iface, pguidContainerFormat);
+    return ComponentInfo_GetGUIDValue(This->classkey, containerformat_valuename, pguidContainerFormat);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetPixelFormats(IWICBitmapDecoderInfo *iface,
     UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+    TRACE("(%p,%u,%p,%p)\n", iface, cFormats, pguidPixelFormats, pcActual);
+    return ComponentInfo_GetGuidList(This->classkey, formats_keyname, cFormats, pguidPixelFormats, pcActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetColorManagementVersion(IWICBitmapDecoderInfo *iface,
@@ -188,15 +383,23 @@ static HRESULT WINAPI BitmapDecoderInfo_GetDeviceModels(IWICBitmapDecoderInfo *i
 static HRESULT WINAPI BitmapDecoderInfo_GetMimeTypes(IWICBitmapDecoderInfo *iface,
     UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, mimetypes_valuename,
+        cchMimeTypes, wzMimeTypes, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_GetFileExtensions(IWICBitmapDecoderInfo *iface,
     UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
-    return E_NOTIMPL;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, fileextensions_valuename,
+        cchFileExtensions, wzFileExtensions, pcchActual);
 }
 
 static HRESULT WINAPI BitmapDecoderInfo_DoesSupportAnimation(IWICBitmapDecoderInfo *iface,
@@ -237,7 +440,7 @@ static HRESULT WINAPI BitmapDecoderInfo_MatchesMimeType(IWICBitmapDecoderInfo *i
 static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface,
     UINT cbSizePatterns, WICBitmapPattern *pPatterns, UINT *pcPatterns, UINT *pcbPatternsActual)
 {
-    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
     UINT pattern_count=0, patterns_size=0;
     WCHAR subkeyname[11];
     LONG res;
@@ -297,167 +500,970 @@ static HRESULT WINAPI BitmapDecoderInfo_GetPatterns(IWICBitmapDecoderInfo *iface
                             pPatterns[i].Pattern, &valuesize);
                     }
 
-                    if (res == ERROR_SUCCESS)
-                    {
-                        pPatterns[i].Mask = bPatterns+patterns_size-length;
-                        valuesize = length;
-                        res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
-                            pPatterns[i].Mask, &valuesize);
-                    }
-                }
+                    if (res == ERROR_SUCCESS)
+                    {
+                        pPatterns[i].Mask = bPatterns+patterns_size-length;
+                        valuesize = length;
+                        res = RegGetValueW(patternkey, NULL, maskW, RRF_RT_REG_BINARY, NULL,
+                            pPatterns[i].Mask, &valuesize);
+                    }
+                }
+
+                RegCloseKey(patternkey);
+            }
+            if (res != ERROR_SUCCESS)
+            {
+                hr = HRESULT_FROM_WIN32(res);
+                break;
+            }
+        }
+    }
+    else hr = HRESULT_FROM_WIN32(res);
+
+    RegCloseKey(patternskey);
+
+    if (hr == S_OK)
+    {
+        *pcPatterns = pattern_count;
+        *pcbPatternsActual = patterns_size;
+        if (pPatterns && cbSizePatterns < patterns_size)
+            hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
+    IStream *pIStream, BOOL *pfMatches)
+{
+    WICBitmapPattern *patterns;
+    UINT pattern_count=0, patterns_size=0;
+    HRESULT hr;
+    int i, pos;
+    BYTE *data=NULL;
+    ULONG datasize=0;
+    ULONG bytesread;
+    LARGE_INTEGER seekpos;
+
+    TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
+
+    hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
+    if (FAILED(hr)) return hr;
+
+    patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
+    if (!patterns) return E_OUTOFMEMORY;
+
+    hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
+    if (FAILED(hr)) goto end;
+
+    for (i=0; i<pattern_count; i++)
+    {
+        if (datasize < patterns[i].Length)
+        {
+            HeapFree(GetProcessHeap(), 0, data);
+            datasize = patterns[i].Length;
+            data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
+            if (!data)
+            {
+                hr = E_OUTOFMEMORY;
+                break;
+            }
+        }
+
+        if (patterns[i].EndOfStream)
+            seekpos.QuadPart = -patterns[i].Position.QuadPart;
+        else
+            seekpos.QuadPart = patterns[i].Position.QuadPart;
+        hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
+        if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
+        if (FAILED(hr)) break;
+
+        hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
+        if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
+            continue;
+        if (FAILED(hr)) break;
+
+        for (pos=0; pos<patterns[i].Length; pos++)
+        {
+            if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
+                break;
+        }
+        if (pos == patterns[i].Length) /* matches pattern */
+        {
+            hr = S_OK;
+            *pfMatches = TRUE;
+            break;
+        }
+    }
+
+    if (i == pattern_count) /* does not match any pattern */
+    {
+        hr = S_OK;
+        *pfMatches = FALSE;
+    }
+
+end:
+    HeapFree(GetProcessHeap(), 0, patterns);
+    HeapFree(GetProcessHeap(), 0, data);
+
+    return hr;
+}
+
+static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
+    IWICBitmapDecoder **ppIBitmapDecoder)
+{
+    BitmapDecoderInfo *This = impl_from_IWICBitmapDecoderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
+
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
+}
+
+static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
+    BitmapDecoderInfo_QueryInterface,
+    BitmapDecoderInfo_AddRef,
+    BitmapDecoderInfo_Release,
+    BitmapDecoderInfo_GetComponentType,
+    BitmapDecoderInfo_GetCLSID,
+    BitmapDecoderInfo_GetSigningStatus,
+    BitmapDecoderInfo_GetAuthor,
+    BitmapDecoderInfo_GetVendorGUID,
+    BitmapDecoderInfo_GetVersion,
+    BitmapDecoderInfo_GetSpecVersion,
+    BitmapDecoderInfo_GetFriendlyName,
+    BitmapDecoderInfo_GetContainerFormat,
+    BitmapDecoderInfo_GetPixelFormats,
+    BitmapDecoderInfo_GetColorManagementVersion,
+    BitmapDecoderInfo_GetDeviceManufacturer,
+    BitmapDecoderInfo_GetDeviceModels,
+    BitmapDecoderInfo_GetMimeTypes,
+    BitmapDecoderInfo_GetFileExtensions,
+    BitmapDecoderInfo_DoesSupportAnimation,
+    BitmapDecoderInfo_DoesSupportChromaKey,
+    BitmapDecoderInfo_DoesSupportLossless,
+    BitmapDecoderInfo_DoesSupportMultiframe,
+    BitmapDecoderInfo_MatchesMimeType,
+    BitmapDecoderInfo_GetPatterns,
+    BitmapDecoderInfo_MatchesPattern,
+    BitmapDecoderInfo_CreateInstance
+};
+
+static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    BitmapDecoderInfo *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
+    if (!This)
+    {
+        RegCloseKey(classkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->IWICBitmapDecoderInfo_iface.lpVtbl = &BitmapDecoderInfo_Vtbl;
+    This->ref = 1;
+    This->classkey = classkey;
+    memcpy(&This->clsid, clsid, sizeof(CLSID));
+
+    *ppIInfo = (IWICComponentInfo*)This;
+    return S_OK;
+}
+
+typedef struct {
+    IWICBitmapEncoderInfo IWICBitmapEncoderInfo_iface;
+    LONG ref;
+    HKEY classkey;
+    CLSID clsid;
+} BitmapEncoderInfo;
+
+static inline BitmapEncoderInfo *impl_from_IWICBitmapEncoderInfo(IWICBitmapEncoderInfo *iface)
+{
+    return CONTAINING_RECORD(iface, BitmapEncoderInfo, IWICBitmapEncoderInfo_iface);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_QueryInterface(IWICBitmapEncoderInfo *iface, REFIID iid,
+    void **ppv)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICComponentInfo, iid) ||
+        IsEqualIID(&IID_IWICBitmapCodecInfo, iid) ||
+        IsEqualIID(&IID_IWICBitmapEncoderInfo ,iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI BitmapEncoderInfo_AddRef(IWICBitmapEncoderInfo *iface)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI BitmapEncoderInfo_Release(IWICBitmapEncoderInfo *iface)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        RegCloseKey(This->classkey);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetComponentType(IWICBitmapEncoderInfo *iface,
+    WICComponentType *pType)
+{
+    TRACE("(%p,%p)\n", iface, pType);
+    if (!pType) return E_INVALIDARG;
+    *pType = WICEncoder;
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetCLSID(IWICBitmapEncoderInfo *iface, CLSID *pclsid)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    TRACE("(%p,%p)\n", iface, pclsid);
+
+    if (!pclsid)
+        return E_INVALIDARG;
+
+    memcpy(pclsid, &This->clsid, sizeof(CLSID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetSigningStatus(IWICBitmapEncoderInfo *iface, DWORD *pStatus)
+{
+    FIXME("(%p,%p): stub\n", iface, pStatus);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetAuthor(IWICBitmapEncoderInfo *iface, UINT cchAuthor,
+    WCHAR *wzAuthor, UINT *pcchActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, author_valuename,
+        cchAuthor, wzAuthor, pcchActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetVendorGUID(IWICBitmapEncoderInfo *iface, GUID *pguidVendor)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, pguidVendor);
+
+    return ComponentInfo_GetGUIDValue(This->classkey, vendor_valuename, pguidVendor);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetVersion(IWICBitmapEncoderInfo *iface, UINT cchVersion,
+    WCHAR *wzVersion, UINT *pcchActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, version_valuename,
+        cchVersion, wzVersion, pcchActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetSpecVersion(IWICBitmapEncoderInfo *iface, UINT cchSpecVersion,
+    WCHAR *wzSpecVersion, UINT *pcchActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, specversion_valuename,
+        cchSpecVersion, wzSpecVersion, pcchActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetFriendlyName(IWICBitmapEncoderInfo *iface, UINT cchFriendlyName,
+    WCHAR *wzFriendlyName, UINT *pcchActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, friendlyname_valuename,
+        cchFriendlyName, wzFriendlyName, pcchActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetContainerFormat(IWICBitmapEncoderInfo *iface,
+    GUID *pguidContainerFormat)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    TRACE("(%p,%p)\n", iface, pguidContainerFormat);
+    return ComponentInfo_GetGUIDValue(This->classkey, containerformat_valuename, pguidContainerFormat);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetPixelFormats(IWICBitmapEncoderInfo *iface,
+    UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+    TRACE("(%p,%u,%p,%p)\n", iface, cFormats, pguidPixelFormats, pcActual);
+    return ComponentInfo_GetGuidList(This->classkey, formats_keyname, cFormats, pguidPixelFormats, pcActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetColorManagementVersion(IWICBitmapEncoderInfo *iface,
+    UINT cchColorManagementVersion, WCHAR *wzColorManagementVersion, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchColorManagementVersion, wzColorManagementVersion, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetDeviceManufacturer(IWICBitmapEncoderInfo *iface,
+    UINT cchDeviceManufacturer, WCHAR *wzDeviceManufacturer, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceManufacturer, wzDeviceManufacturer, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetDeviceModels(IWICBitmapEncoderInfo *iface,
+    UINT cchDeviceModels, WCHAR *wzDeviceModels, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchDeviceModels, wzDeviceModels, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetMimeTypes(IWICBitmapEncoderInfo *iface,
+    UINT cchMimeTypes, WCHAR *wzMimeTypes, UINT *pcchActual)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchMimeTypes, wzMimeTypes, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, mimetypes_valuename,
+        cchMimeTypes, wzMimeTypes, pcchActual);
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_GetFileExtensions(IWICBitmapEncoderInfo *iface,
+    UINT cchFileExtensions, WCHAR *wzFileExtensions, UINT *pcchActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFileExtensions, wzFileExtensions, pcchActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_DoesSupportAnimation(IWICBitmapEncoderInfo *iface,
+    BOOL *pfSupportAnimation)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportAnimation);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_DoesSupportChromaKey(IWICBitmapEncoderInfo *iface,
+    BOOL *pfSupportChromaKey)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportChromaKey);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_DoesSupportLossless(IWICBitmapEncoderInfo *iface,
+    BOOL *pfSupportLossless)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportLossless);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_DoesSupportMultiframe(IWICBitmapEncoderInfo *iface,
+    BOOL *pfSupportMultiframe)
+{
+    FIXME("(%p,%p): stub\n", iface, pfSupportMultiframe);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_MatchesMimeType(IWICBitmapEncoderInfo *iface,
+    LPCWSTR wzMimeType, BOOL *pfMatches)
+{
+    FIXME("(%p,%s,%p): stub\n", iface, debugstr_w(wzMimeType), pfMatches);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI BitmapEncoderInfo_CreateInstance(IWICBitmapEncoderInfo *iface,
+    IWICBitmapEncoder **ppIBitmapEncoder)
+{
+    BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, ppIBitmapEncoder);
+
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICBitmapEncoder, (void**)ppIBitmapEncoder);
+}
+
+static const IWICBitmapEncoderInfoVtbl BitmapEncoderInfo_Vtbl = {
+    BitmapEncoderInfo_QueryInterface,
+    BitmapEncoderInfo_AddRef,
+    BitmapEncoderInfo_Release,
+    BitmapEncoderInfo_GetComponentType,
+    BitmapEncoderInfo_GetCLSID,
+    BitmapEncoderInfo_GetSigningStatus,
+    BitmapEncoderInfo_GetAuthor,
+    BitmapEncoderInfo_GetVendorGUID,
+    BitmapEncoderInfo_GetVersion,
+    BitmapEncoderInfo_GetSpecVersion,
+    BitmapEncoderInfo_GetFriendlyName,
+    BitmapEncoderInfo_GetContainerFormat,
+    BitmapEncoderInfo_GetPixelFormats,
+    BitmapEncoderInfo_GetColorManagementVersion,
+    BitmapEncoderInfo_GetDeviceManufacturer,
+    BitmapEncoderInfo_GetDeviceModels,
+    BitmapEncoderInfo_GetMimeTypes,
+    BitmapEncoderInfo_GetFileExtensions,
+    BitmapEncoderInfo_DoesSupportAnimation,
+    BitmapEncoderInfo_DoesSupportChromaKey,
+    BitmapEncoderInfo_DoesSupportLossless,
+    BitmapEncoderInfo_DoesSupportMultiframe,
+    BitmapEncoderInfo_MatchesMimeType,
+    BitmapEncoderInfo_CreateInstance
+};
+
+static HRESULT BitmapEncoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    BitmapEncoderInfo *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapEncoderInfo));
+    if (!This)
+    {
+        RegCloseKey(classkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->IWICBitmapEncoderInfo_iface.lpVtbl = &BitmapEncoderInfo_Vtbl;
+    This->ref = 1;
+    This->classkey = classkey;
+    memcpy(&This->clsid, clsid, sizeof(CLSID));
+
+    *ppIInfo = (IWICComponentInfo*)This;
+    return S_OK;
+}
+
+typedef struct {
+    IWICFormatConverterInfo IWICFormatConverterInfo_iface;
+    LONG ref;
+    HKEY classkey;
+    CLSID clsid;
+} FormatConverterInfo;
+
+static inline FormatConverterInfo *impl_from_IWICFormatConverterInfo(IWICFormatConverterInfo *iface)
+{
+    return CONTAINING_RECORD(iface, FormatConverterInfo, IWICFormatConverterInfo_iface);
+}
+
+static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
+    void **ppv)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICComponentInfo, iid) ||
+        IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        RegCloseKey(This->classkey);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
+    WICComponentType *pType)
+{
+    TRACE("(%p,%p)\n", iface, pType);
+    if (!pType) return E_INVALIDARG;
+    *pType = WICPixelFormatConverter;
+    return S_OK;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+    TRACE("(%p,%p)\n", iface, pclsid);
+
+    if (!pclsid)
+        return E_INVALIDARG;
+
+    memcpy(pclsid, &This->clsid, sizeof(CLSID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
+{
+    FIXME("(%p,%p): stub\n", iface, pStatus);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
+    WCHAR *wzAuthor, UINT *pcchActual)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, author_valuename,
+        cchAuthor, wzAuthor, pcchActual);
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, pguidVendor);
+
+    return ComponentInfo_GetGUIDValue(This->classkey, vendor_valuename, pguidVendor);
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
+    WCHAR *wzVersion, UINT *pcchActual)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, version_valuename,
+        cchVersion, wzVersion, pcchActual);
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
+    WCHAR *wzSpecVersion, UINT *pcchActual)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, specversion_valuename,
+        cchSpecVersion, wzSpecVersion, pcchActual);
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
+    WCHAR *wzFriendlyName, UINT *pcchActual)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, friendlyname_valuename,
+        cchFriendlyName, wzFriendlyName, pcchActual);
+}
+
+static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
+    UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
+{
+    FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
+    IWICFormatConverter **ppIFormatConverter)
+{
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, ppIFormatConverter);
+
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+        &IID_IWICFormatConverter, (void**)ppIFormatConverter);
+}
+
+static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
+{
+    LONG res;
+    FormatConverterInfo *This = impl_from_IWICFormatConverterInfo(iface);
+    HKEY formats_key, guid_key;
+
+    /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
+        would be O(n). A registry test should do better. */
+
+    res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
+    if (res != ERROR_SUCCESS) return FALSE;
+
+    res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
+    if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
+
+    RegCloseKey(formats_key);
+
+    return (res == ERROR_SUCCESS);
+}
+
+static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
+    FormatConverterInfo_QueryInterface,
+    FormatConverterInfo_AddRef,
+    FormatConverterInfo_Release,
+    FormatConverterInfo_GetComponentType,
+    FormatConverterInfo_GetCLSID,
+    FormatConverterInfo_GetSigningStatus,
+    FormatConverterInfo_GetAuthor,
+    FormatConverterInfo_GetVendorGUID,
+    FormatConverterInfo_GetVersion,
+    FormatConverterInfo_GetSpecVersion,
+    FormatConverterInfo_GetFriendlyName,
+    FormatConverterInfo_GetPixelFormats,
+    FormatConverterInfo_CreateInstance
+};
+
+static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+{
+    FormatConverterInfo *This;
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
+    if (!This)
+    {
+        RegCloseKey(classkey);
+        return E_OUTOFMEMORY;
+    }
+
+    This->IWICFormatConverterInfo_iface.lpVtbl = &FormatConverterInfo_Vtbl;
+    This->ref = 1;
+    This->classkey = classkey;
+    memcpy(&This->clsid, clsid, sizeof(CLSID));
+
+    *ppIInfo = (IWICComponentInfo*)This;
+    return S_OK;
+}
+
+typedef struct {
+    IWICPixelFormatInfo2 IWICPixelFormatInfo2_iface;
+    LONG ref;
+    HKEY classkey;
+    CLSID clsid;
+} PixelFormatInfo;
+
+static inline PixelFormatInfo *impl_from_IWICPixelFormatInfo2(IWICPixelFormatInfo2 *iface)
+{
+    return CONTAINING_RECORD(iface, PixelFormatInfo, IWICPixelFormatInfo2_iface);
+}
+
+static HRESULT WINAPI PixelFormatInfo_QueryInterface(IWICPixelFormatInfo2 *iface, REFIID iid,
+    void **ppv)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICComponentInfo, iid) ||
+        IsEqualIID(&IID_IWICPixelFormatInfo, iid) ||
+        IsEqualIID(&IID_IWICPixelFormatInfo2 ,iid))
+    {
+        *ppv = This;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI PixelFormatInfo_AddRef(IWICPixelFormatInfo2 *iface)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI PixelFormatInfo_Release(IWICPixelFormatInfo2 *iface)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        RegCloseKey(This->classkey);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetComponentType(IWICPixelFormatInfo2 *iface,
+    WICComponentType *pType)
+{
+    TRACE("(%p,%p)\n", iface, pType);
+    if (!pType) return E_INVALIDARG;
+    *pType = WICPixelFormat;
+    return S_OK;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetCLSID(IWICPixelFormatInfo2 *iface, CLSID *pclsid)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    TRACE("(%p,%p)\n", iface, pclsid);
+
+    if (!pclsid)
+        return E_INVALIDARG;
+
+    memcpy(pclsid, &This->clsid, sizeof(CLSID));
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetSigningStatus(IWICPixelFormatInfo2 *iface, DWORD *pStatus)
+{
+    TRACE("(%p,%p)\n", iface, pStatus);
+
+    if (!pStatus)
+        return E_INVALIDARG;
+
+    /* Pixel formats don't require code, so they are considered signed. */
+    *pStatus = WICComponentSigned;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetAuthor(IWICPixelFormatInfo2 *iface, UINT cchAuthor,
+    WCHAR *wzAuthor, UINT *pcchActual)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchAuthor, wzAuthor, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, author_valuename,
+        cchAuthor, wzAuthor, pcchActual);
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetVendorGUID(IWICPixelFormatInfo2 *iface, GUID *pguidVendor)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%p)\n", iface, pguidVendor);
+
+    return ComponentInfo_GetGUIDValue(This->classkey, vendor_valuename, pguidVendor);
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetVersion(IWICPixelFormatInfo2 *iface, UINT cchVersion,
+    WCHAR *wzVersion, UINT *pcchActual)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchVersion, wzVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, version_valuename,
+        cchVersion, wzVersion, pcchActual);
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetSpecVersion(IWICPixelFormatInfo2 *iface, UINT cchSpecVersion,
+    WCHAR *wzSpecVersion, UINT *pcchActual)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, specversion_valuename,
+        cchSpecVersion, wzSpecVersion, pcchActual);
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetFriendlyName(IWICPixelFormatInfo2 *iface, UINT cchFriendlyName,
+    WCHAR *wzFriendlyName, UINT *pcchActual)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+
+    return ComponentInfo_GetStringValue(This->classkey, friendlyname_valuename,
+        cchFriendlyName, wzFriendlyName, pcchActual);
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetFormatGUID(IWICPixelFormatInfo2 *iface,
+    GUID *pFormat)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    TRACE("(%p,%p)\n", iface, pFormat);
+
+    if (!pFormat)
+        return E_INVALIDARG;
+
+    *pFormat = This->clsid;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetColorContext(IWICPixelFormatInfo2 *iface,
+    IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI PixelFormatInfo_GetBitsPerPixel(IWICPixelFormatInfo2 *iface,
+    UINT *puiBitsPerPixel)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
 
-                RegCloseKey(patternkey);
-            }
-            if (res != ERROR_SUCCESS)
-            {
-                hr = HRESULT_FROM_WIN32(res);
-                break;
-            }
-        }
-    }
-    else hr = HRESULT_FROM_WIN32(res);
+    TRACE("(%p,%p)\n", iface, puiBitsPerPixel);
 
-    RegCloseKey(patternskey);
+    return ComponentInfo_GetDWORDValue(This->classkey, bitsperpixel_valuename, puiBitsPerPixel);
+}
 
-    if (hr == S_OK)
-    {
-        *pcPatterns = pattern_count;
-        *pcbPatternsActual = patterns_size;
-        if (pPatterns && cbSizePatterns < patterns_size)
-            hr = WINCODEC_ERR_INSUFFICIENTBUFFER;
-    }
+static HRESULT WINAPI PixelFormatInfo_GetChannelCount(IWICPixelFormatInfo2 *iface,
+    UINT *puiChannelCount)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
 
-    return hr;
+    TRACE("(%p,%p)\n", iface, puiChannelCount);
+
+    return ComponentInfo_GetDWORDValue(This->classkey, channelcount_valuename, puiChannelCount);
 }
 
-static HRESULT WINAPI BitmapDecoderInfo_MatchesPattern(IWICBitmapDecoderInfo *iface,
-    IStream *pIStream, BOOL *pfMatches)
+static HRESULT WINAPI PixelFormatInfo_GetChannelMask(IWICPixelFormatInfo2 *iface,
+    UINT uiChannelIndex, UINT cbMaskBuffer, BYTE *pbMaskBuffer, UINT *pcbActual)
 {
-    WICBitmapPattern *patterns;
-    UINT pattern_count=0, patterns_size=0;
+    static const WCHAR uintformatW[] = {'%','u',0};
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+    UINT channel_count;
     HRESULT hr;
-    int i, pos;
-    BYTE *data=NULL;
-    ULONG datasize=0;
-    ULONG bytesread;
-    LARGE_INTEGER seekpos;
+    LONG ret;
+    WCHAR valuename[11];
+    DWORD cbData;
 
-    TRACE("(%p,%p,%p)\n", iface, pIStream, pfMatches);
+    TRACE("(%p,%u,%u,%p,%p)\n", iface, uiChannelIndex, cbMaskBuffer, pbMaskBuffer, pcbActual);
 
-    hr = BitmapDecoderInfo_GetPatterns(iface, 0, NULL, &pattern_count, &patterns_size);
-    if (FAILED(hr)) return hr;
+    if (!pcbActual)
+        return E_INVALIDARG;
 
-    patterns = HeapAlloc(GetProcessHeap(), 0, patterns_size);
-    if (!patterns) return E_OUTOFMEMORY;
+    hr = PixelFormatInfo_GetChannelCount(iface, &channel_count);
 
-    hr = BitmapDecoderInfo_GetPatterns(iface, patterns_size, patterns, &pattern_count, &patterns_size);
-    if (FAILED(hr)) goto end;
+    if (SUCCEEDED(hr) && uiChannelIndex >= channel_count)
+        hr = E_INVALIDARG;
 
-    for (i=0; i<pattern_count; i++)
+    if (SUCCEEDED(hr))
     {
-        if (datasize < patterns[i].Length)
-        {
-            HeapFree(GetProcessHeap(), 0, data);
-            datasize = patterns[i].Length;
-            data = HeapAlloc(GetProcessHeap(), 0, patterns[i].Length);
-            if (!data)
-            {
-                hr = E_OUTOFMEMORY;
-                break;
-            }
-        }
+        snprintfW(valuename, 11, uintformatW, uiChannelIndex);
 
-        if (patterns[i].EndOfStream)
-            seekpos.QuadPart = -patterns[i].Position.QuadPart;
-        else
-            seekpos.QuadPart = patterns[i].Position.QuadPart;
-        hr = IStream_Seek(pIStream, seekpos, patterns[i].EndOfStream ? STREAM_SEEK_END : STREAM_SEEK_SET, NULL);
-        if (hr == STG_E_INVALIDFUNCTION) continue; /* before start of stream */
-        if (FAILED(hr)) break;
+        cbData = cbMaskBuffer;
 
-        hr = IStream_Read(pIStream, data, patterns[i].Length, &bytesread);
-        if (hr == S_FALSE || (hr == S_OK && bytesread != patterns[i].Length)) /* past end of stream */
-            continue;
-        if (FAILED(hr)) break;
+        ret = RegGetValueW(This->classkey, channelmasks_keyname, valuename, RRF_RT_REG_BINARY, NULL, pbMaskBuffer, &cbData);
 
-        for (pos=0; pos<patterns[i].Length; pos++)
-        {
-            if ((data[pos] & patterns[i].Mask[pos]) != patterns[i].Pattern[pos])
-                break;
-        }
-        if (pos == patterns[i].Length) /* matches pattern */
-        {
-            hr = S_OK;
-            *pfMatches = TRUE;
-            break;
-        }
-    }
+        if (ret == ERROR_SUCCESS || ret == ERROR_MORE_DATA)
+            *pcbActual = cbData;
 
-    if (i == pattern_count) /* does not match any pattern */
-    {
-        hr = S_OK;
-        *pfMatches = FALSE;
+        if (ret == ERROR_MORE_DATA)
+            hr = E_INVALIDARG;
+        else
+            hr = HRESULT_FROM_WIN32(ret);
     }
 
-end:
-    HeapFree(GetProcessHeap(), 0, patterns);
-    HeapFree(GetProcessHeap(), 0, data);
-
     return hr;
 }
 
-static HRESULT WINAPI BitmapDecoderInfo_CreateInstance(IWICBitmapDecoderInfo *iface,
-    IWICBitmapDecoder **ppIBitmapDecoder)
+static HRESULT WINAPI PixelFormatInfo_SupportsTransparency(IWICPixelFormatInfo2 *iface,
+    BOOL *pfSupportsTransparency)
 {
-    BitmapDecoderInfo *This = (BitmapDecoderInfo*)iface;
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
 
-    TRACE("(%p,%p)\n", iface, ppIBitmapDecoder);
+    TRACE("(%p,%p)\n", iface, pfSupportsTransparency);
 
-    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
-        &IID_IWICBitmapDecoder, (void**)ppIBitmapDecoder);
+    return ComponentInfo_GetDWORDValue(This->classkey, supportstransparency_valuename, (DWORD*)pfSupportsTransparency);
 }
 
-static const IWICBitmapDecoderInfoVtbl BitmapDecoderInfo_Vtbl = {
-    BitmapDecoderInfo_QueryInterface,
-    BitmapDecoderInfo_AddRef,
-    BitmapDecoderInfo_Release,
-    BitmapDecoderInfo_GetComponentType,
-    BitmapDecoderInfo_GetCLSID,
-    BitmapDecoderInfo_GetSigningStatus,
-    BitmapDecoderInfo_GetAuthor,
-    BitmapDecoderInfo_GetVendorGUID,
-    BitmapDecoderInfo_GetVersion,
-    BitmapDecoderInfo_GetSpecVersion,
-    BitmapDecoderInfo_GetFriendlyName,
-    BitmapDecoderInfo_GetContainerFormat,
-    BitmapDecoderInfo_GetPixelFormats,
-    BitmapDecoderInfo_GetColorManagementVersion,
-    BitmapDecoderInfo_GetDeviceManufacturer,
-    BitmapDecoderInfo_GetDeviceModels,
-    BitmapDecoderInfo_GetMimeTypes,
-    BitmapDecoderInfo_GetFileExtensions,
-    BitmapDecoderInfo_DoesSupportAnimation,
-    BitmapDecoderInfo_DoesSupportChromaKey,
-    BitmapDecoderInfo_DoesSupportLossless,
-    BitmapDecoderInfo_DoesSupportMultiframe,
-    BitmapDecoderInfo_MatchesMimeType,
-    BitmapDecoderInfo_GetPatterns,
-    BitmapDecoderInfo_MatchesPattern,
-    BitmapDecoderInfo_CreateInstance
+static HRESULT WINAPI PixelFormatInfo_GetNumericRepresentation(IWICPixelFormatInfo2 *iface,
+    WICPixelFormatNumericRepresentation *pNumericRepresentation)
+{
+    PixelFormatInfo *This = impl_from_IWICPixelFormatInfo2(iface);
+
+    TRACE("(%p,%p)\n", iface, pNumericRepresentation);
+
+    return ComponentInfo_GetDWORDValue(This->classkey, numericrepresentation_valuename, pNumericRepresentation);
+}
+
+static const IWICPixelFormatInfo2Vtbl PixelFormatInfo_Vtbl = {
+    PixelFormatInfo_QueryInterface,
+    PixelFormatInfo_AddRef,
+    PixelFormatInfo_Release,
+    PixelFormatInfo_GetComponentType,
+    PixelFormatInfo_GetCLSID,
+    PixelFormatInfo_GetSigningStatus,
+    PixelFormatInfo_GetAuthor,
+    PixelFormatInfo_GetVendorGUID,
+    PixelFormatInfo_GetVersion,
+    PixelFormatInfo_GetSpecVersion,
+    PixelFormatInfo_GetFriendlyName,
+    PixelFormatInfo_GetFormatGUID,
+    PixelFormatInfo_GetColorContext,
+    PixelFormatInfo_GetBitsPerPixel,
+    PixelFormatInfo_GetChannelCount,
+    PixelFormatInfo_GetChannelMask,
+    PixelFormatInfo_SupportsTransparency,
+    PixelFormatInfo_GetNumericRepresentation
 };
 
-static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static HRESULT PixelFormatInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
 {
-    BitmapDecoderInfo *This;
+    PixelFormatInfo *This;
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapDecoderInfo));
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(PixelFormatInfo));
     if (!This)
     {
         RegCloseKey(classkey);
         return E_OUTOFMEMORY;
     }
 
-    This->lpIWICBitmapDecoderInfoVtbl = &BitmapDecoderInfo_Vtbl;
+    This->IWICPixelFormatInfo2_iface.lpVtbl = &PixelFormatInfo_Vtbl;
     This->ref = 1;
     This->classkey = classkey;
     memcpy(&This->clsid, clsid, sizeof(CLSID));
@@ -466,24 +1472,32 @@ static HRESULT BitmapDecoderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWIC
     return S_OK;
 }
 
-typedef struct {
-    const IWICFormatConverterInfoVtbl *lpIWICFormatConverterInfoVtbl;
+typedef struct
+{
+    IWICMetadataReaderInfo IWICMetadataReaderInfo_iface;
     LONG ref;
     HKEY classkey;
     CLSID clsid;
-} FormatConverterInfo;
+} MetadataReaderInfo;
 
-static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo *iface, REFIID iid,
-    void **ppv)
+static inline MetadataReaderInfo *impl_from_IWICMetadataReaderInfo(IWICMetadataReaderInfo *iface)
 {
-    FormatConverterInfo *This = (FormatConverterInfo*)iface;
-    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+    return CONTAINING_RECORD(iface, MetadataReaderInfo, IWICMetadataReaderInfo_iface);
+}
+
+static HRESULT WINAPI MetadataReaderInfo_QueryInterface(IWICMetadataReaderInfo *iface,
+    REFIID riid, void **ppv)
+{
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(riid), ppv);
 
     if (!ppv) return E_INVALIDARG;
 
-    if (IsEqualIID(&IID_IUnknown, iid) ||
-        IsEqualIID(&IID_IWICComponentInfo, iid) ||
-        IsEqualIID(&IID_IWICFormatConverterInfo ,iid))
+    if (IsEqualIID(&IID_IUnknown, riid) ||
+        IsEqualIID(&IID_IWICComponentInfo, riid) ||
+        IsEqualIID(&IID_IWICMetadataHandlerInfo, riid) ||
+        IsEqualIID(&IID_IWICMetadataReaderInfo, riid))
     {
         *ppv = This;
     }
@@ -493,166 +1507,244 @@ static HRESULT WINAPI FormatConverterInfo_QueryInterface(IWICFormatConverterInfo
         return E_NOINTERFACE;
     }
 
-    IUnknown_AddRef((IUnknown*)*ppv);
+    IUnknown_AddRef((IUnknown *)*ppv);
     return S_OK;
 }
 
-static ULONG WINAPI FormatConverterInfo_AddRef(IWICFormatConverterInfo *iface)
+static ULONG WINAPI MetadataReaderInfo_AddRef(IWICMetadataReaderInfo *iface)
 {
-    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
-
     return ref;
 }
 
-static ULONG WINAPI FormatConverterInfo_Release(IWICFormatConverterInfo *iface)
+static ULONG WINAPI MetadataReaderInfo_Release(IWICMetadataReaderInfo *iface)
 {
-    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
 
-    if (ref == 0)
+    if (!ref)
     {
         RegCloseKey(This->classkey);
         HeapFree(GetProcessHeap(), 0, This);
     }
-
     return ref;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetComponentType(IWICFormatConverterInfo *iface,
-    WICComponentType *pType)
+static HRESULT WINAPI MetadataReaderInfo_GetComponentType(IWICMetadataReaderInfo *iface,
+    WICComponentType *type)
 {
-    TRACE("(%p,%p)\n", iface, pType);
-    *pType = WICPixelFormatConverter;
+    TRACE("(%p,%p)\n", iface, type);
+
+    if (!type) return E_INVALIDARG;
+    *type = WICMetadataReader;
     return S_OK;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetCLSID(IWICFormatConverterInfo *iface, CLSID *pclsid)
+static HRESULT WINAPI MetadataReaderInfo_GetCLSID(IWICMetadataReaderInfo *iface,
+    CLSID *clsid)
 {
-    FIXME("(%p,%p): stub\n", iface, pclsid);
-    return E_NOTIMPL;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, clsid);
+
+    if (!clsid) return E_INVALIDARG;
+    *clsid = This->clsid;
+    return S_OK;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetSigningStatus(IWICFormatConverterInfo *iface, DWORD *pStatus)
+static HRESULT WINAPI MetadataReaderInfo_GetSigningStatus(IWICMetadataReaderInfo *iface,
+    DWORD *status)
 {
-    FIXME("(%p,%p): stub\n", iface, pStatus);
+    FIXME("(%p,%p): stub\n", iface, status);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetAuthor(IWICFormatConverterInfo *iface, UINT cchAuthor,
-    WCHAR *wzAuthor, UINT *pcchActual)
+static HRESULT WINAPI MetadataReaderInfo_GetAuthor(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *author, UINT *actual_length)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchAuthor, wzAuthor, pcchActual);
-    return E_NOTIMPL;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, length, author, actual_length);
+
+    return ComponentInfo_GetStringValue(This->classkey, author_valuename,
+                                        length, author, actual_length);
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetVendorGUID(IWICFormatConverterInfo *iface, GUID *pguidVendor)
+static HRESULT WINAPI MetadataReaderInfo_GetVendorGUID(IWICMetadataReaderInfo *iface,
+    GUID *vendor)
 {
-    FIXME("(%p,%p): stub\n", iface, pguidVendor);
-    return E_NOTIMPL;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%p)\n", iface, vendor);
+
+    return ComponentInfo_GetGUIDValue(This->classkey, vendor_valuename, vendor);
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetVersion(IWICFormatConverterInfo *iface, UINT cchVersion,
-    WCHAR *wzVersion, UINT *pcchActual)
+static HRESULT WINAPI MetadataReaderInfo_GetVersion(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *version, UINT *actual_length)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchVersion, wzVersion, pcchActual);
-    return E_NOTIMPL;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, length, version, actual_length);
+
+    return ComponentInfo_GetStringValue(This->classkey, version_valuename,
+                                        length, version, actual_length);
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetSpecVersion(IWICFormatConverterInfo *iface, UINT cchSpecVersion,
-    WCHAR *wzSpecVersion, UINT *pcchActual)
+static HRESULT WINAPI MetadataReaderInfo_GetSpecVersion(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *version, UINT *actual_length)
+{
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, length, version, actual_length);
+
+    return ComponentInfo_GetStringValue(This->classkey, specversion_valuename,
+                                        length, version, actual_length);
+}
+
+static HRESULT WINAPI MetadataReaderInfo_GetFriendlyName(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *name, UINT *actual_length)
+{
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+
+    TRACE("(%p,%u,%p,%p)\n", iface, length, name, actual_length);
+
+    return ComponentInfo_GetStringValue(This->classkey, friendlyname_valuename,
+                                        length, name, actual_length);
+}
+
+static HRESULT WINAPI MetadataReaderInfo_GetMetadataFormat(IWICMetadataReaderInfo *iface,
+    GUID *format)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchSpecVersion, wzSpecVersion, pcchActual);
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+    TRACE("(%p,%p)\n", iface, format);
+    return ComponentInfo_GetGUIDValue(This->classkey, metadataformat_valuename, format);
+}
+
+static HRESULT WINAPI MetadataReaderInfo_GetContainerFormats(IWICMetadataReaderInfo *iface,
+    UINT length, GUID *formats, UINT *actual_length)
+{
+    if (!actual_length) return E_INVALIDARG;
+
+    FIXME("(%p,%u,%p,%p): stub\n", iface, length, formats, actual_length);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetFriendlyName(IWICFormatConverterInfo *iface, UINT cchFriendlyName,
-    WCHAR *wzFriendlyName, UINT *pcchActual)
+static HRESULT WINAPI MetadataReaderInfo_GetDeviceManufacturer(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *manufacturer, UINT *actual_length)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cchFriendlyName, wzFriendlyName, pcchActual);
+    FIXME("(%p,%u,%p,%p): stub\n", iface, length, manufacturer, actual_length);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI FormatConverterInfo_GetPixelFormats(IWICFormatConverterInfo *iface,
-    UINT cFormats, GUID *pguidPixelFormats, UINT *pcActual)
+static HRESULT WINAPI MetadataReaderInfo_GetDeviceModels(IWICMetadataReaderInfo *iface,
+    UINT length, WCHAR *models, UINT *actual_length)
 {
-    FIXME("(%p,%u,%p,%p): stub\n", iface, cFormats, pguidPixelFormats, pcActual);
+    FIXME("(%p,%u,%p,%p): stub\n", iface, length, models, actual_length);
     return E_NOTIMPL;
 }
 
-static HRESULT WINAPI FormatConverterInfo_CreateInstance(IWICFormatConverterInfo *iface,
-    IWICFormatConverter **ppIFormatConverter)
+static HRESULT WINAPI MetadataReaderInfo_DoesRequireFullStream(IWICMetadataReaderInfo *iface,
+    BOOL *param)
 {
-    FormatConverterInfo *This = (FormatConverterInfo*)iface;
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+    TRACE("(%p,%p)\n", iface, param);
+    return ComponentInfo_GetDWORDValue(This->classkey, requiresfullstream_valuename, (DWORD *)param);
+}
 
-    TRACE("(%p,%p)\n", iface, ppIFormatConverter);
+static HRESULT WINAPI MetadataReaderInfo_DoesSupportPadding(IWICMetadataReaderInfo *iface,
+    BOOL *param)
+{
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
+    TRACE("(%p,%p)\n", iface, param);
+    return ComponentInfo_GetDWORDValue(This->classkey, supportspadding_valuename, (DWORD *)param);
+}
 
-    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
-        &IID_IWICFormatConverter, (void**)ppIFormatConverter);
+static HRESULT WINAPI MetadataReaderInfo_DoesRequireFixedSize(IWICMetadataReaderInfo *iface,
+    BOOL *param)
+{
+    FIXME("(%p,%p): stub\n", iface, param);
+    return E_NOTIMPL;
 }
 
-static BOOL ConverterSupportsFormat(IWICFormatConverterInfo *iface, const WCHAR *formatguid)
+static HRESULT WINAPI MetadataReaderInfo_GetPatterns(IWICMetadataReaderInfo *iface,
+    REFGUID container, UINT length, WICMetadataPattern *pattern, UINT *count, UINT *actual_length)
 {
-    LONG res;
-    FormatConverterInfo *This = (FormatConverterInfo*)iface;
-    HKEY formats_key, guid_key;
+    if (!actual_length) return E_INVALIDARG;
 
-    /* Avoid testing using IWICFormatConverter_GetPixelFormats because that
-        would be O(n). A registry test should do better. */
+    FIXME("(%p,%s,%u,%p,%p,%p): stub\n", iface, debugstr_guid(container), length, pattern, count, actual_length);
+    return E_NOTIMPL;
+}
 
-    res = RegOpenKeyExW(This->classkey, pixelformats_keyname, 0, KEY_READ, &formats_key);
-    if (res != ERROR_SUCCESS) return FALSE;
+static HRESULT WINAPI MetadataReaderInfo_MatchesPattern(IWICMetadataReaderInfo *iface,
+    REFGUID container, IStream *stream, BOOL *matches)
+{
+    FIXME("(%p,%s,%p,%p): stub\n", iface, debugstr_guid(container), stream, matches);
+    return E_NOTIMPL;
+}
 
-    res = RegOpenKeyExW(formats_key, formatguid, 0, KEY_READ, &guid_key);
-    if (res == ERROR_SUCCESS) RegCloseKey(guid_key);
+static HRESULT WINAPI MetadataReaderInfo_CreateInstance(IWICMetadataReaderInfo *iface,
+    IWICMetadataReader **reader)
+{
+    MetadataReaderInfo *This = impl_from_IWICMetadataReaderInfo(iface);
 
-    RegCloseKey(formats_key);
+    TRACE("(%p,%p)\n", iface, reader);
 
-    return (res == ERROR_SUCCESS);
+    return CoCreateInstance(&This->clsid, NULL, CLSCTX_INPROC_SERVER,
+                            &IID_IWICMetadataReader, (void **)reader);
 }
 
-static const IWICFormatConverterInfoVtbl FormatConverterInfo_Vtbl = {
-    FormatConverterInfo_QueryInterface,
-    FormatConverterInfo_AddRef,
-    FormatConverterInfo_Release,
-    FormatConverterInfo_GetComponentType,
-    FormatConverterInfo_GetCLSID,
-    FormatConverterInfo_GetSigningStatus,
-    FormatConverterInfo_GetAuthor,
-    FormatConverterInfo_GetVendorGUID,
-    FormatConverterInfo_GetVersion,
-    FormatConverterInfo_GetSpecVersion,
-    FormatConverterInfo_GetFriendlyName,
-    FormatConverterInfo_GetPixelFormats,
-    FormatConverterInfo_CreateInstance
+static const IWICMetadataReaderInfoVtbl MetadataReaderInfo_Vtbl = {
+    MetadataReaderInfo_QueryInterface,
+    MetadataReaderInfo_AddRef,
+    MetadataReaderInfo_Release,
+    MetadataReaderInfo_GetComponentType,
+    MetadataReaderInfo_GetCLSID,
+    MetadataReaderInfo_GetSigningStatus,
+    MetadataReaderInfo_GetAuthor,
+    MetadataReaderInfo_GetVendorGUID,
+    MetadataReaderInfo_GetVersion,
+    MetadataReaderInfo_GetSpecVersion,
+    MetadataReaderInfo_GetFriendlyName,
+    MetadataReaderInfo_GetMetadataFormat,
+    MetadataReaderInfo_GetContainerFormats,
+    MetadataReaderInfo_GetDeviceManufacturer,
+    MetadataReaderInfo_GetDeviceModels,
+    MetadataReaderInfo_DoesRequireFullStream,
+    MetadataReaderInfo_DoesSupportPadding,
+    MetadataReaderInfo_DoesRequireFixedSize,
+    MetadataReaderInfo_GetPatterns,
+    MetadataReaderInfo_MatchesPattern,
+    MetadataReaderInfo_CreateInstance
 };
 
-static HRESULT FormatConverterInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **ppIInfo)
+static HRESULT MetadataReaderInfo_Constructor(HKEY classkey, REFCLSID clsid, IWICComponentInfo **info)
 {
-    FormatConverterInfo *This;
+    MetadataReaderInfo *This;
 
-    This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverterInfo));
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
     if (!This)
     {
         RegCloseKey(classkey);
         return E_OUTOFMEMORY;
     }
 
-    This->lpIWICFormatConverterInfoVtbl = &FormatConverterInfo_Vtbl;
+    This->IWICMetadataReaderInfo_iface.lpVtbl = &MetadataReaderInfo_Vtbl;
     This->ref = 1;
     This->classkey = classkey;
-    memcpy(&This->clsid, clsid, sizeof(CLSID));
+    This->clsid = *clsid;
 
-    *ppIInfo = (IWICComponentInfo*)This;
+    *info = (IWICComponentInfo *)This;
     return S_OK;
 }
 
-static WCHAR const clsid_keyname[] = {'C','L','S','I','D',0};
-static WCHAR const instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
+static const WCHAR clsid_keyname[] = {'C','L','S','I','D',0};
+static const WCHAR instance_keyname[] = {'I','n','s','t','a','n','c','e',0};
 
 struct category {
     WICComponentType type;
@@ -662,7 +1754,10 @@ struct category {
 
 static const struct category categories[] = {
     {WICDecoder, &CATID_WICBitmapDecoders, BitmapDecoderInfo_Constructor},
+    {WICEncoder, &CATID_WICBitmapEncoders, BitmapEncoderInfo_Constructor},
     {WICPixelFormatConverter, &CATID_WICFormatConverters, FormatConverterInfo_Constructor},
+    {WICPixelFormat, &CATID_WICPixelFormats, PixelFormatInfo_Constructor},
+    {WICMetadataReader, &CATID_WICMetadataReader, MetadataReaderInfo_Constructor},
     {0}
 };
 
@@ -714,7 +1809,10 @@ HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
             hr = HRESULT_FROM_WIN32(res);
     }
     else
+    {
+        FIXME("%s is not supported\n", wine_dbgstr_guid(clsid));
         hr = E_FAIL;
+    }
 
     RegCloseKey(clsidkey);
 
@@ -722,13 +1820,18 @@ HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo)
 }
 
 typedef struct {
-    const IEnumUnknownVtbl *IEnumUnknown_Vtbl;
+    IEnumUnknown IEnumUnknown_iface;
     LONG ref;
     struct list objects;
     struct list *cursor;
     CRITICAL_SECTION lock; /* Must be held when reading or writing cursor */
 } ComponentEnum;
 
+static inline ComponentEnum *impl_from_IEnumUnknown(IEnumUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, ComponentEnum, IEnumUnknown_iface);
+}
+
 typedef struct {
     struct list entry;
     IUnknown *unk;
@@ -739,14 +1842,15 @@ static const IEnumUnknownVtbl ComponentEnumVtbl;
 static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID iid,
     void **ppv)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
 
-    if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IEnumUnknown, iid))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IEnumUnknown, iid))
     {
-        *ppv = This;
+        *ppv = &This->IEnumUnknown_iface;
     }
     else
     {
@@ -760,7 +1864,7 @@ static HRESULT WINAPI ComponentEnum_QueryInterface(IEnumUnknown *iface, REFIID i
 
 static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -770,7 +1874,7 @@ static ULONG WINAPI ComponentEnum_AddRef(IEnumUnknown *iface)
 
 static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
     ComponentEnumItem *cursor, *cursor2;
 
@@ -795,7 +1899,7 @@ static ULONG WINAPI ComponentEnum_Release(IEnumUnknown *iface)
 static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
     IUnknown **rgelt, ULONG *pceltFetched)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     int num_fetched=0;
     ComponentEnumItem *item;
     HRESULT hr=S_OK;
@@ -824,7 +1928,7 @@ static HRESULT WINAPI ComponentEnum_Next(IEnumUnknown *iface, ULONG celt,
 
 static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     int i;
     HRESULT hr=S_OK;
 
@@ -846,7 +1950,7 @@ static HRESULT WINAPI ComponentEnum_Skip(IEnumUnknown *iface, ULONG celt)
 
 static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
 
     TRACE("(%p)\n", iface);
 
@@ -858,7 +1962,7 @@ static HRESULT WINAPI ComponentEnum_Reset(IEnumUnknown *iface)
 
 static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **ppenum)
 {
-    ComponentEnum *This = (ComponentEnum*)iface;
+    ComponentEnum *This = impl_from_IEnumUnknown(iface);
     ComponentEnum *new_enum;
     ComponentEnumItem *old_item, *new_item;
     HRESULT ret=S_OK;
@@ -871,7 +1975,7 @@ static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **pp
         return E_OUTOFMEMORY;
     }
 
-    new_enum->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
+    new_enum->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
     new_enum->ref = 1;
     new_enum->cursor = NULL;
     list_init(&new_enum->objects);
@@ -898,11 +2002,11 @@ static HRESULT WINAPI ComponentEnum_Clone(IEnumUnknown *iface, IEnumUnknown **pp
 
     if (FAILED(ret))
     {
-        IUnknown_Release((IUnknown*)new_enum);
+        IEnumUnknown_Release(&new_enum->IEnumUnknown_iface);
         *ppenum = NULL;
     }
     else
-        *ppenum = (IEnumUnknown*)new_enum;
+        *ppenum = &new_enum->IEnumUnknown_iface;
 
     return ret;
 }
@@ -942,7 +2046,7 @@ HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnkn
         return E_OUTOFMEMORY;
     }
 
-    This->IEnumUnknown_Vtbl = &ComponentEnumVtbl;
+    This->IEnumUnknown_iface.lpVtbl = &ComponentEnumVtbl;
     This->ref = 1;
     list_init(&This->objects);
     InitializeCriticalSection(&This->lock);
@@ -993,13 +2097,13 @@ HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnkn
 
     if (SUCCEEDED(hr))
     {
-        IEnumUnknown_Reset((IEnumUnknown*)This);
-        *ppIEnumUnknown = (IEnumUnknown*)This;
+        IEnumUnknown_Reset(&This->IEnumUnknown_iface);
+        *ppIEnumUnknown = &This->IEnumUnknown_iface;
     }
     else
     {
         *ppIEnumUnknown = NULL;
-        IUnknown_Release((IUnknown*)This);
+        IEnumUnknown_Release(&This->IEnumUnknown_iface);
     }
 
     return hr;
@@ -1083,8 +2187,9 @@ HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitma
 
     if (converter)
     {
-        *ppIDst = (IWICBitmapSource*)converter;
-        return S_OK;
+        res = IWICFormatConverter_QueryInterface(converter, &IID_IWICBitmapSource, (void **)ppIDst);
+        IWICFormatConverter_Release(converter);
+        return res;
     }
     else
     {
index b5676ea..6463de5 100644 (file)
@@ -25,6 +25,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
+#include <setjmp.h>
 
 #ifdef SONAME_LIBJPEG
 /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
 #ifdef SONAME_LIBJPEG
+WINE_DECLARE_DEBUG_CHANNEL(jpeg);
 
 static void *libjpeg_handle;
 
 #define MAKE_FUNCPTR(f) static typeof(f) * p##f
+MAKE_FUNCPTR(jpeg_CreateCompress);
 MAKE_FUNCPTR(jpeg_CreateDecompress);
+MAKE_FUNCPTR(jpeg_destroy_compress);
 MAKE_FUNCPTR(jpeg_destroy_decompress);
+MAKE_FUNCPTR(jpeg_finish_compress);
 MAKE_FUNCPTR(jpeg_read_header);
 MAKE_FUNCPTR(jpeg_read_scanlines);
 MAKE_FUNCPTR(jpeg_resync_to_restart);
+MAKE_FUNCPTR(jpeg_set_defaults);
+MAKE_FUNCPTR(jpeg_start_compress);
 MAKE_FUNCPTR(jpeg_start_decompress);
 MAKE_FUNCPTR(jpeg_std_error);
+MAKE_FUNCPTR(jpeg_write_scanlines);
 #undef MAKE_FUNCPTR
 
 static void *load_libjpeg(void)
@@ -79,21 +87,59 @@ static void *load_libjpeg(void)
         return NULL; \
     }
 
+        LOAD_FUNCPTR(jpeg_CreateCompress);
         LOAD_FUNCPTR(jpeg_CreateDecompress);
+        LOAD_FUNCPTR(jpeg_destroy_compress);
         LOAD_FUNCPTR(jpeg_destroy_decompress);
+        LOAD_FUNCPTR(jpeg_finish_compress);
         LOAD_FUNCPTR(jpeg_read_header);
         LOAD_FUNCPTR(jpeg_read_scanlines);
         LOAD_FUNCPTR(jpeg_resync_to_restart);
+        LOAD_FUNCPTR(jpeg_set_defaults);
+        LOAD_FUNCPTR(jpeg_start_compress);
         LOAD_FUNCPTR(jpeg_start_decompress);
         LOAD_FUNCPTR(jpeg_std_error);
+        LOAD_FUNCPTR(jpeg_write_scanlines);
 #undef LOAD_FUNCPTR
     }
     return libjpeg_handle;
 }
 
+static void error_exit_fn(j_common_ptr cinfo)
+{
+    char message[JMSG_LENGTH_MAX];
+    if (ERR_ON(jpeg))
+    {
+        cinfo->err->format_message(cinfo, message);
+        ERR_(jpeg)("%s\n", message);
+    }
+    longjmp(*(jmp_buf*)cinfo->client_data, 1);
+}
+
+static void emit_message_fn(j_common_ptr cinfo, int msg_level)
+{
+    char message[JMSG_LENGTH_MAX];
+
+    if (msg_level < 0 && ERR_ON(jpeg))
+    {
+        cinfo->err->format_message(cinfo, message);
+        ERR_(jpeg)("%s\n", message);
+    }
+    else if (msg_level == 0 && WARN_ON(jpeg))
+    {
+        cinfo->err->format_message(cinfo, message);
+        WARN_(jpeg)("%s\n", message);
+    }
+    else if (msg_level > 0 && TRACE_ON(jpeg))
+    {
+        cinfo->err->format_message(cinfo, message);
+        TRACE_(jpeg)("%s\n", message);
+    }
+}
+
 typedef struct {
-    const IWICBitmapDecoderVtbl *lpVtbl;
-    const IWICBitmapFrameDecodeVtbl *lpFrameVtbl;
+    IWICBitmapDecoder IWICBitmapDecoder_iface;
+    IWICBitmapFrameDecode IWICBitmapFrameDecode_iface;
     LONG ref;
     BOOL initialized;
     BOOL cinfo_initialized;
@@ -106,27 +152,33 @@ typedef struct {
     CRITICAL_SECTION lock;
 } JpegDecoder;
 
-static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
+static inline JpegDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface)
 {
-    return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
+    return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapDecoder_iface);
+}
+
+static inline JpegDecoder *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface)
+{
+    return CONTAINING_RECORD(iface, JpegDecoder, IWICBitmapFrameDecode_iface);
 }
 
-static inline JpegDecoder *decoder_from_frame(IWICBitmapFrameDecode *iface)
+static inline JpegDecoder *decoder_from_decompress(j_decompress_ptr decompress)
 {
-    return CONTAINING_RECORD(iface, JpegDecoder, lpFrameVtbl);
+    return CONTAINING_RECORD(decompress, JpegDecoder, cinfo);
 }
 
 static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid,
     void **ppv)
 {
-    JpegDecoder *This = (JpegDecoder*)iface;
+    JpegDecoder *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))
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapDecoder, iid))
     {
-        *ppv = This;
+        *ppv = &This->IWICBitmapDecoder_iface;
     }
     else
     {
@@ -140,7 +192,7 @@ static HRESULT WINAPI JpegDecoder_QueryInterface(IWICBitmapDecoder *iface, REFII
 
 static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
 {
-    JpegDecoder *This = (JpegDecoder*)iface;
+    JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedIncrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -150,7 +202,7 @@ static ULONG WINAPI JpegDecoder_AddRef(IWICBitmapDecoder *iface)
 
 static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
 {
-    JpegDecoder *This = (JpegDecoder*)iface;
+    JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
     ULONG ref = InterlockedDecrement(&This->ref);
 
     TRACE("(%p) refcount=%u\n", iface, ref);
@@ -168,11 +220,22 @@ static ULONG WINAPI JpegDecoder_Release(IWICBitmapDecoder *iface)
     return ref;
 }
 
-static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *pIStream,
-    DWORD *pdwCapability)
+static HRESULT WINAPI JpegDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream,
+    DWORD *capability)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pIStream, pdwCapability);
-    return E_NOTIMPL;
+    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 = WICBitmapDecoderCapabilityCanDecodeAllImages |
+                  WICBitmapDecoderCapabilityCanDecodeSomeImages;
+    /* FIXME: WICBitmapDecoderCapabilityCanEnumerateMetadata */
+    return S_OK;
 }
 
 static void source_mgr_init_source(j_decompress_ptr cinfo)
@@ -224,8 +287,10 @@ static void source_mgr_term_source(j_decompress_ptr cinfo)
 static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream,
     WICDecodeOptions cacheOptions)
 {
-    JpegDecoder *This = (JpegDecoder*)iface;
+    JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
     int ret;
+    LARGE_INTEGER seek;
+    jmp_buf jmpbuf;
     TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOptions);
 
     EnterCriticalSection(&This->lock);
@@ -236,7 +301,20 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
         return WINCODEC_ERR_WRONGSTATE;
     }
 
-    This->cinfo.err = pjpeg_std_error(&This->jerr);
+    pjpeg_std_error(&This->jerr);
+
+    This->jerr.error_exit = error_exit_fn;
+    This->jerr.emit_message = emit_message_fn;
+
+    This->cinfo.err = &This->jerr;
+
+    This->cinfo.client_data = jmpbuf;
+
+    if (setjmp(jmpbuf))
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_FAIL;
+    }
 
     pjpeg_CreateDecompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_decompress_struct));
 
@@ -245,6 +323,9 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
     This->stream = pIStream;
     IStream_AddRef(pIStream);
 
+    seek.QuadPart = 0;
+    IStream_Seek(This->stream, seek, STREAM_SEEK_SET, NULL);
+
     This->source_mgr.bytes_in_buffer = 0;
     This->source_mgr.init_source = source_mgr_init_source;
     This->source_mgr.fill_input_buffer = source_mgr_fill_input_buffer;
@@ -262,10 +343,24 @@ static HRESULT WINAPI JpegDecoder_Initialize(IWICBitmapDecoder *iface, IStream *
         return E_FAIL;
     }
 
-    if (This->cinfo.jpeg_color_space == JCS_GRAYSCALE)
+    switch (This->cinfo.jpeg_color_space)
+    {
+    case JCS_GRAYSCALE:
         This->cinfo.out_color_space = JCS_GRAYSCALE;
-    else
+        break;
+    case JCS_RGB:
+    case JCS_YCbCr:
         This->cinfo.out_color_space = JCS_RGB;
+        break;
+    case JCS_CMYK:
+    case JCS_YCCK:
+        This->cinfo.out_color_space = JCS_CMYK;
+        break;
+    default:
+        ERR("Unknown JPEG color space %i\n", This->cinfo.jpeg_color_space);
+        LeaveCriticalSection(&This->lock);
+        return E_FAIL;
+    }
 
     if (!pjpeg_start_decompress(&This->cinfo))
     {
@@ -291,8 +386,20 @@ static HRESULT WINAPI JpegDecoder_GetContainerFormat(IWICBitmapDecoder *iface,
 static HRESULT WINAPI JpegDecoder_GetDecoderInfo(IWICBitmapDecoder *iface,
     IWICBitmapDecoderInfo **ppIDecoderInfo)
 {
-    FIXME("(%p,%p): stub\n", iface, ppIDecoderInfo);
-    return E_NOTIMPL;
+    HRESULT hr;
+    IWICComponentInfo *compinfo;
+
+    TRACE("(%p,%p)\n", iface, ppIDecoderInfo);
+
+    hr = CreateComponentInfo(&CLSID_WICJpegDecoder, &compinfo);
+    if (FAILED(hr)) return hr;
+
+    hr = IWICComponentInfo_QueryInterface(compinfo, &IID_IWICBitmapDecoderInfo,
+        (void**)ppIDecoderInfo);
+
+    IWICComponentInfo_Release(compinfo);
+
+    return hr;
 }
 
 static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface,
@@ -334,6 +441,8 @@ static HRESULT WINAPI JpegDecoder_GetThumbnail(IWICBitmapDecoder *iface,
 static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface,
     UINT *pCount)
 {
+    if (!pCount) return E_INVALIDARG;
+
     *pCount = 1;
     return S_OK;
 }
@@ -341,15 +450,15 @@ static HRESULT WINAPI JpegDecoder_GetFrameCount(IWICBitmapDecoder *iface,
 static HRESULT WINAPI JpegDecoder_GetFrame(IWICBitmapDecoder *iface,
     UINT index, IWICBitmapFrameDecode **ppIBitmapFrame)
 {
-    JpegDecoder *This = (JpegDecoder*)iface;
+    JpegDecoder *This = impl_from_IWICBitmapDecoder(iface);
     TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame);
 
-    if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED;
+    if (!This->initialized) return WINCODEC_ERR_FRAMEMISSING;
 
     if (index != 0) return E_INVALIDARG;
 
     IWICBitmapDecoder_AddRef(iface);
-    *ppIBitmapFrame = (IWICBitmapFrameDecode*)&This->lpFrameVtbl;
+    *ppIBitmapFrame = &This->IWICBitmapFrameDecode_iface;
 
     return S_OK;
 }
@@ -374,6 +483,8 @@ static const IWICBitmapDecoderVtbl JpegDecoder_Vtbl = {
 static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid,
     void **ppv)
 {
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
+
     TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
 
     if (!ppv) return E_INVALIDARG;
@@ -382,7 +493,7 @@ static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *if
         IsEqualIID(&IID_IWICBitmapSource, iid) ||
         IsEqualIID(&IID_IWICBitmapFrameDecode, iid))
     {
-        *ppv = iface;
+        *ppv = &This->IWICBitmapFrameDecode_iface;
     }
     else
     {
@@ -396,20 +507,20 @@ static HRESULT WINAPI JpegDecoder_Frame_QueryInterface(IWICBitmapFrameDecode *if
 
 static ULONG WINAPI JpegDecoder_Frame_AddRef(IWICBitmapFrameDecode *iface)
 {
-    JpegDecoder *This = decoder_from_frame(iface);
-    return IUnknown_AddRef((IUnknown*)This);
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
+    return IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface);
 }
 
 static ULONG WINAPI JpegDecoder_Frame_Release(IWICBitmapFrameDecode *iface)
 {
-    JpegDecoder *This = decoder_from_frame(iface);
-    return IUnknown_Release((IUnknown*)This);
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
+    return IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 }
 
 static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
     UINT *puiWidth, UINT *puiHeight)
 {
-    JpegDecoder *This = decoder_from_frame(iface);
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     *puiWidth = This->cinfo.output_width;
     *puiHeight = This->cinfo.output_height;
     TRACE("(%p)->(%u,%u)\n", iface, *puiWidth, *puiHeight);
@@ -419,10 +530,12 @@ static HRESULT WINAPI JpegDecoder_Frame_GetSize(IWICBitmapFrameDecode *iface,
 static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *iface,
     WICPixelFormatGUID *pPixelFormat)
 {
-    JpegDecoder *This = decoder_from_frame(iface);
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     TRACE("(%p,%p)\n", iface, pPixelFormat);
     if (This->cinfo.out_color_space == JCS_RGB)
         memcpy(pPixelFormat, &GUID_WICPixelFormat24bppBGR, sizeof(GUID));
+    else if (This->cinfo.out_color_space == JCS_CMYK)
+        memcpy(pPixelFormat, &GUID_WICPixelFormat32bppCMYK, sizeof(GUID));
     else /* This->cinfo.out_color_space == JCS_GRAYSCALE */
         memcpy(pPixelFormat, &GUID_WICPixelFormat8bppGray, sizeof(GUID));
     return S_OK;
@@ -431,8 +544,27 @@ static HRESULT WINAPI JpegDecoder_Frame_GetPixelFormat(IWICBitmapFrameDecode *if
 static HRESULT WINAPI JpegDecoder_Frame_GetResolution(IWICBitmapFrameDecode *iface,
     double *pDpiX, double *pDpiY)
 {
-    FIXME("(%p,%p,%p): stub\n", iface, pDpiX, pDpiY);
-    return E_NOTIMPL;
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->cinfo.density_unit == 2) /* pixels per centimeter */
+    {
+        *pDpiX = This->cinfo.X_density * 2.54;
+        *pDpiY = This->cinfo.Y_density * 2.54;
+    }
+    else
+    {
+        /* 1 = pixels per inch, 0 = unknown */
+        *pDpiX = This->cinfo.X_density;
+        *pDpiY = This->cinfo.Y_density;
+    }
+
+    LeaveCriticalSection(&This->lock);
+
+    TRACE("(%p)->(%0.2f,%0.2f)\n", iface, *pDpiX, *pDpiY);
+
+    return S_OK;
 }
 
 static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface,
@@ -445,14 +577,32 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPalette(IWICBitmapFrameDecode *iface
 static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
     const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer)
 {
-    JpegDecoder *This = decoder_from_frame(iface);
+    JpegDecoder *This = impl_from_IWICBitmapFrameDecode(iface);
     UINT bpp;
     UINT stride;
     UINT data_size;
     UINT max_row_needed;
+    jmp_buf jmpbuf;
+    WICRect rect;
     TRACE("(%p,%p,%u,%u,%p)\n", iface, prc, cbStride, cbBufferSize, pbBuffer);
 
+    if (!prc)
+    {
+        rect.X = 0;
+        rect.Y = 0;
+        rect.Width = This->cinfo.output_width;
+        rect.Height = This->cinfo.output_height;
+        prc = &rect;
+    }
+    else
+    {
+        if (prc->X < 0 || prc->Y < 0 || prc->X+prc->Width > This->cinfo.output_width ||
+            prc->Y+prc->Height > This->cinfo.output_height)
+            return E_INVALIDARG;
+    }
+
     if (This->cinfo.out_color_space == JCS_GRAYSCALE) bpp = 8;
+    else if (This->cinfo.out_color_space == JCS_CMYK) bpp = 32;
     else bpp = 24;
 
     stride = bpp * This->cinfo.output_width;
@@ -473,12 +623,20 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
         }
     }
 
+    This->cinfo.client_data = jmpbuf;
+
+    if (setjmp(jmpbuf))
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_FAIL;
+    }
+
     while (max_row_needed > This->cinfo.output_scanline)
     {
         UINT first_scanline = This->cinfo.output_scanline;
         UINT max_rows;
         JSAMPROW out_rows[4];
-        UINT i, j;
+        UINT i;
         JDIMENSION ret;
 
         max_rows = min(This->cinfo.output_height-first_scanline, 4);
@@ -497,19 +655,15 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface,
         if (bpp == 24)
         {
             /* libjpeg gives us RGB data and we want BGR, so byteswap the data */
-            for (i=first_scanline; i<This->cinfo.output_scanline; i++)
-            {
-                BYTE *pixel = This->image_data + stride * i;
-                for (j=0; j<This->cinfo.output_width; j++)
-                {
-                    BYTE red=pixel[0];
-                    BYTE blue=pixel[2];
-                    pixel[0]=blue;
-                    pixel[2]=red;
-                    pixel+=3;
-                }
-            }
+            reverse_bgr8(3, This->image_data + stride * first_scanline,
+                This->cinfo.output_width, This->cinfo.output_scanline - first_scanline,
+                stride);
         }
+
+        if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker)
+            /* Adobe JPEG's have inverted CMYK data. */
+            for (i=0; i<data_size; i++)
+                This->image_data[i] ^= 0xff;
     }
 
     LeaveCriticalSection(&This->lock);
@@ -574,8 +728,8 @@ HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
     This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegDecoder));
     if (!This) return E_OUTOFMEMORY;
 
-    This->lpVtbl = &JpegDecoder_Vtbl;
-    This->lpFrameVtbl = &JpegDecoder_Frame_Vtbl;
+    This->IWICBitmapDecoder_iface.lpVtbl = &JpegDecoder_Vtbl;
+    This->IWICBitmapFrameDecode_iface.lpVtbl = &JpegDecoder_Frame_Vtbl;
     This->ref = 1;
     This->initialized = FALSE;
     This->cinfo_initialized = FALSE;
@@ -584,17 +738,771 @@ HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
     InitializeCriticalSection(&This->lock);
     This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegDecoder.lock");
 
-    ret = IUnknown_QueryInterface((IUnknown*)This, iid, ppv);
-    IUnknown_Release((IUnknown*)This);
+    ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv);
+    IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface);
 
     return ret;
 }
 
-#else /* !defined(SONAME_LIBJPEG) */
+typedef struct jpeg_compress_format {
+    const WICPixelFormatGUID *guid;
+    int bpp;
+    int num_components;
+    J_COLOR_SPACE color_space;
+    int swap_rgb;
+} jpeg_compress_format;
+
+static const jpeg_compress_format compress_formats[] = {
+    { &GUID_WICPixelFormat24bppBGR, 24, 3, JCS_RGB, 1 },
+    { &GUID_WICPixelFormat32bppCMYK, 32, 4, JCS_CMYK },
+    { &GUID_WICPixelFormat8bppGray, 8, 1, JCS_GRAYSCALE },
+    { 0 }
+};
 
-HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+typedef struct JpegEncoder {
+    IWICBitmapEncoder IWICBitmapEncoder_iface;
+    IWICBitmapFrameEncode IWICBitmapFrameEncode_iface;
+    LONG ref;
+    struct jpeg_compress_struct cinfo;
+    struct jpeg_error_mgr jerr;
+    struct jpeg_destination_mgr dest_mgr;
+    int initialized;
+    int frame_count;
+    int frame_initialized;
+    int started_compress;
+    int lines_written;
+    int frame_committed;
+    int committed;
+    UINT width, height;
+    double xres, yres;
+    const jpeg_compress_format *format;
+    IStream *stream;
+    CRITICAL_SECTION lock;
+    BYTE dest_buffer[1024];
+} JpegEncoder;
+
+static inline JpegEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface)
 {
-    ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
+    return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapEncoder_iface);
+}
+
+static inline JpegEncoder *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface)
+{
+    return CONTAINING_RECORD(iface, JpegEncoder, IWICBitmapFrameEncode_iface);
+}
+
+static inline JpegEncoder *encoder_from_compress(j_compress_ptr compress)
+{
+    return CONTAINING_RECORD(compress, JpegEncoder, cinfo);
+}
+
+static void dest_mgr_init_destination(j_compress_ptr cinfo)
+{
+    JpegEncoder *This = encoder_from_compress(cinfo);
+
+    This->dest_mgr.next_output_byte = This->dest_buffer;
+    This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
+}
+
+static jpeg_boolean dest_mgr_empty_output_buffer(j_compress_ptr cinfo)
+{
+    JpegEncoder *This = encoder_from_compress(cinfo);
+    HRESULT hr;
+    ULONG byteswritten;
+
+    hr = IStream_Write(This->stream, This->dest_buffer,
+        sizeof(This->dest_buffer), &byteswritten);
+
+    if (hr != S_OK || byteswritten == 0)
+    {
+        ERR("Failed writing data, hr=%x\n", hr);
+        return FALSE;
+    }
+
+    This->dest_mgr.next_output_byte = This->dest_buffer;
+    This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
+    return TRUE;
+}
+
+static void dest_mgr_term_destination(j_compress_ptr cinfo)
+{
+    JpegEncoder *This = encoder_from_compress(cinfo);
+    ULONG byteswritten;
+    HRESULT hr;
+
+    if (This->dest_mgr.free_in_buffer != sizeof(This->dest_buffer))
+    {
+        hr = IStream_Write(This->stream, This->dest_buffer,
+            sizeof(This->dest_buffer) - This->dest_mgr.free_in_buffer, &byteswritten);
+
+        if (hr != S_OK || byteswritten == 0)
+            ERR("Failed writing data, hr=%x\n", hr);
+    }
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid,
+    void **ppv)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapFrameEncode, iid))
+    {
+        *ppv = &This->IWICBitmapFrameEncode_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI JpegEncoder_Frame_AddRef(IWICBitmapFrameEncode *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface);
+}
+
+static ULONG WINAPI JpegEncoder_Frame_Release(IWICBitmapFrameEncode *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_Initialize(IWICBitmapFrameEncode *iface,
+    IPropertyBag2 *pIEncoderOptions)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    TRACE("(%p,%p)\n", iface, pIEncoderOptions);
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->frame_initialized)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    This->frame_initialized = TRUE;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetSize(IWICBitmapFrameEncode *iface,
+    UINT uiWidth, UINT uiHeight)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->frame_initialized || This->started_compress)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    This->width = uiWidth;
+    This->height = uiHeight;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetResolution(IWICBitmapFrameEncode *iface,
+    double dpiX, double dpiY)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->frame_initialized || This->started_compress)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    This->xres = dpiX;
+    This->yres = dpiY;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetPixelFormat(IWICBitmapFrameEncode *iface,
+    WICPixelFormatGUID *pPixelFormat)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    int i;
+    TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat));
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->frame_initialized || This->started_compress)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    for (i=0; compress_formats[i].guid; i++)
+    {
+        if (memcmp(compress_formats[i].guid, pPixelFormat, sizeof(GUID)) == 0)
+            break;
+    }
+
+    if (!compress_formats[i].guid) i = 0;
+
+    This->format = &compress_formats[i];
+    memcpy(pPixelFormat, This->format->guid, sizeof(GUID));
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetColorContexts(IWICBitmapFrameEncode *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetPalette(IWICBitmapFrameEncode *iface,
+    IWICPalette *pIPalette)
+{
+    FIXME("(%p,%p): stub\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_SetThumbnail(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIThumbnail)
+{
+    FIXME("(%p,%p): stub\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_WritePixels(IWICBitmapFrameEncode *iface,
+    UINT lineCount, UINT cbStride, UINT cbBufferSize, BYTE *pbPixels)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    jmp_buf jmpbuf;
+    BYTE *swapped_data = NULL, *current_row;
+    int line, row_size;
+    TRACE("(%p,%u,%u,%u,%p)\n", iface, lineCount, cbStride, cbBufferSize, pbPixels);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->frame_initialized || !This->width || !This->height || !This->format)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    if (lineCount == 0 || lineCount + This->lines_written > This->height)
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_INVALIDARG;
+    }
+
+    /* set up setjmp/longjmp error handling */
+    if (setjmp(jmpbuf))
+    {
+        LeaveCriticalSection(&This->lock);
+        HeapFree(GetProcessHeap(), 0, swapped_data);
+        return E_FAIL;
+    }
+    This->cinfo.client_data = jmpbuf;
+
+    if (!This->started_compress)
+    {
+        This->cinfo.image_width = This->width;
+        This->cinfo.image_height = This->height;
+        This->cinfo.input_components = This->format->num_components;
+        This->cinfo.in_color_space = This->format->color_space;
+
+        pjpeg_set_defaults(&This->cinfo);
+
+        if (This->xres != 0.0 && This->yres != 0.0)
+        {
+            This->cinfo.density_unit = 1; /* dots per inch */
+            This->cinfo.X_density = This->xres;
+            This->cinfo.Y_density = This->yres;
+        }
+
+        pjpeg_start_compress(&This->cinfo, TRUE);
+
+        This->started_compress = 1;
+    }
+
+    row_size = This->format->bpp / 8 * This->width;
+
+    if (This->format->swap_rgb)
+    {
+        swapped_data = HeapAlloc(GetProcessHeap(), 0, row_size);
+        if (!swapped_data)
+        {
+            LeaveCriticalSection(&This->lock);
+            return E_OUTOFMEMORY;
+        }
+    }
+
+    for (line=0; line < lineCount; line++)
+    {
+        if (This->format->swap_rgb)
+        {
+            int x;
+
+            memcpy(swapped_data, pbPixels + (cbStride * line), row_size);
+
+            for (x=0; x < This->width; x++)
+            {
+                BYTE b;
+
+                b = swapped_data[x*3];
+                swapped_data[x*3] = swapped_data[x*3+2];
+                swapped_data[x*3+2] = b;
+            }
+
+            current_row = swapped_data;
+        }
+        else
+            current_row = pbPixels + (cbStride * line);
+
+        if (!pjpeg_write_scanlines(&This->cinfo, &current_row, 1))
+        {
+            ERR("failed writing scanlines\n");
+            LeaveCriticalSection(&This->lock);
+            HeapFree(GetProcessHeap(), 0, swapped_data);
+            return E_FAIL;
+        }
+
+        This->lines_written++;
+    }
+
+    LeaveCriticalSection(&This->lock);
+    HeapFree(GetProcessHeap(), 0, swapped_data);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_WriteSource(IWICBitmapFrameEncode *iface,
+    IWICBitmapSource *pIBitmapSource, WICRect *prc)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    HRESULT hr;
+    WICRect rc;
+    WICPixelFormatGUID guid;
+    UINT stride;
+    BYTE *pixeldata;
+    TRACE("(%p,%p,%p)\n", iface, pIBitmapSource, prc);
+
+    if (!This->frame_initialized || !This->width || !This->height)
+        return WINCODEC_ERR_WRONGSTATE;
+
+    if (!This->format)
+    {
+        hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
+        if (FAILED(hr)) return hr;
+        hr = IWICBitmapFrameEncode_SetPixelFormat(iface, &guid);
+        if (FAILED(hr)) return hr;
+    }
+
+    hr = IWICBitmapSource_GetPixelFormat(pIBitmapSource, &guid);
+    if (FAILED(hr)) return hr;
+    if (memcmp(&guid, This->format->guid, sizeof(GUID)) != 0)
+    {
+        /* FIXME: should use WICConvertBitmapSource to convert */
+        ERR("format %s unsupported\n", debugstr_guid(&guid));
+        return E_FAIL;
+    }
+
+    if (This->xres == 0.0 || This->yres == 0.0)
+    {
+        double xres, yres;
+        hr = IWICBitmapSource_GetResolution(pIBitmapSource, &xres, &yres);
+        if (FAILED(hr)) return hr;
+        hr = IWICBitmapFrameEncode_SetResolution(iface, xres, yres);
+        if (FAILED(hr)) return hr;
+    }
+
+    if (!prc)
+    {
+        UINT width, height;
+        hr = IWICBitmapSource_GetSize(pIBitmapSource, &width, &height);
+        if (FAILED(hr)) return hr;
+        rc.X = 0;
+        rc.Y = 0;
+        rc.Width = width;
+        rc.Height = height;
+        prc = &rc;
+    }
+
+    if (prc->Width != This->width) return E_INVALIDARG;
+
+    stride = (This->format->bpp * This->width + 7)/8;
+
+    pixeldata = HeapAlloc(GetProcessHeap(), 0, stride * prc->Height);
+    if (!pixeldata) return E_OUTOFMEMORY;
+
+    hr = IWICBitmapSource_CopyPixels(pIBitmapSource, prc, stride,
+        stride*prc->Height, pixeldata);
+
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICBitmapFrameEncode_WritePixels(iface, prc->Height, stride,
+            stride*prc->Height, pixeldata);
+    }
+
+    HeapFree(GetProcessHeap(), 0, pixeldata);
+
+    return hr;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_Commit(IWICBitmapFrameEncode *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapFrameEncode(iface);
+    jmp_buf jmpbuf;
+    TRACE("(%p)\n", iface);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->started_compress || This->lines_written != This->height || This->frame_committed)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    /* set up setjmp/longjmp error handling */
+    if (setjmp(jmpbuf))
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_FAIL;
+    }
+    This->cinfo.client_data = jmpbuf;
+
+    pjpeg_finish_compress(&This->cinfo);
+
+    This->frame_committed = TRUE;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Frame_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapFrameEncodeVtbl JpegEncoder_FrameVtbl = {
+    JpegEncoder_Frame_QueryInterface,
+    JpegEncoder_Frame_AddRef,
+    JpegEncoder_Frame_Release,
+    JpegEncoder_Frame_Initialize,
+    JpegEncoder_Frame_SetSize,
+    JpegEncoder_Frame_SetResolution,
+    JpegEncoder_Frame_SetPixelFormat,
+    JpegEncoder_Frame_SetColorContexts,
+    JpegEncoder_Frame_SetPalette,
+    JpegEncoder_Frame_SetThumbnail,
+    JpegEncoder_Frame_WritePixels,
+    JpegEncoder_Frame_WriteSource,
+    JpegEncoder_Frame_Commit,
+    JpegEncoder_Frame_GetMetadataQueryWriter
+};
+
+static HRESULT WINAPI JpegEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid,
+    void **ppv)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv);
+
+    if (!ppv) return E_INVALIDARG;
+
+    if (IsEqualIID(&IID_IUnknown, iid) ||
+        IsEqualIID(&IID_IWICBitmapEncoder, iid))
+    {
+        *ppv = &This->IWICBitmapEncoder_iface;
+    }
+    else
+    {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown*)*ppv);
+    return S_OK;
+}
+
+static ULONG WINAPI JpegEncoder_AddRef(IWICBitmapEncoder *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    ULONG ref = InterlockedIncrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    return ref;
+}
+
+static ULONG WINAPI JpegEncoder_Release(IWICBitmapEncoder *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE("(%p) refcount=%u\n", iface, ref);
+
+    if (ref == 0)
+    {
+        This->lock.DebugInfo->Spare[0] = 0;
+        DeleteCriticalSection(&This->lock);
+        if (This->initialized) pjpeg_destroy_compress(&This->cinfo);
+        if (This->stream) IStream_Release(This->stream);
+        HeapFree(GetProcessHeap(), 0, This);
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI JpegEncoder_Initialize(IWICBitmapEncoder *iface,
+    IStream *pIStream, WICBitmapEncoderCacheOption cacheOption)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    jmp_buf jmpbuf;
+
+    TRACE("(%p,%p,%u)\n", iface, pIStream, cacheOption);
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->initialized)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    pjpeg_std_error(&This->jerr);
+
+    This->jerr.error_exit = error_exit_fn;
+    This->jerr.emit_message = emit_message_fn;
+
+    This->cinfo.err = &This->jerr;
+
+    This->cinfo.client_data = jmpbuf;
+
+    if (setjmp(jmpbuf))
+    {
+        LeaveCriticalSection(&This->lock);
+        return E_FAIL;
+    }
+
+    pjpeg_CreateCompress(&This->cinfo, JPEG_LIB_VERSION, sizeof(struct jpeg_compress_struct));
+
+    This->stream = pIStream;
+    IStream_AddRef(pIStream);
+
+    This->dest_mgr.next_output_byte = This->dest_buffer;
+    This->dest_mgr.free_in_buffer = sizeof(This->dest_buffer);
+
+    This->dest_mgr.init_destination = dest_mgr_init_destination;
+    This->dest_mgr.empty_output_buffer = dest_mgr_empty_output_buffer;
+    This->dest_mgr.term_destination = dest_mgr_term_destination;
+
+    This->cinfo.dest = &This->dest_mgr;
+
+    This->initialized = TRUE;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface,
+    GUID *pguidContainerFormat)
+{
+    FIXME("(%p,%s): stub\n", iface, debugstr_guid(pguidContainerFormat));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface,
+    IWICBitmapEncoderInfo **ppIEncoderInfo)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface,
+    UINT cCount, IWICColorContext **ppIColorContext)
+{
+    FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI JpegEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *pIPalette)
+{
+    TRACE("(%p,%p)\n", iface, pIPalette);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI JpegEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail)
+{
+    TRACE("(%p,%p)\n", iface, pIThumbnail);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI JpegEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview)
+{
+    TRACE("(%p,%p)\n", iface, pIPreview);
+    return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+}
+
+static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface,
+    IWICBitmapFrameEncode **ppIFrameEncode, IPropertyBag2 **ppIEncoderOptions)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    HRESULT hr;
+
+    TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions);
+
+    EnterCriticalSection(&This->lock);
+
+    if (This->frame_count != 0)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_UNSUPPORTEDOPERATION;
+    }
+
+    if (!This->initialized)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_NOTINITIALIZED;
+    }
+
+    hr = CreatePropertyBag2(ppIEncoderOptions);
+    if (FAILED(hr))
+    {
+        LeaveCriticalSection(&This->lock);
+        return hr;
+    }
+
+    This->frame_count = 1;
+
+    LeaveCriticalSection(&This->lock);
+
+    IWICBitmapEncoder_AddRef(iface);
+    *ppIFrameEncode = &This->IWICBitmapFrameEncode_iface;
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_Commit(IWICBitmapEncoder *iface)
+{
+    JpegEncoder *This = impl_from_IWICBitmapEncoder(iface);
+    TRACE("(%p)\n", iface);
+
+    EnterCriticalSection(&This->lock);
+
+    if (!This->frame_committed || This->committed)
+    {
+        LeaveCriticalSection(&This->lock);
+        return WINCODEC_ERR_WRONGSTATE;
+    }
+
+    This->committed = TRUE;
+
+    LeaveCriticalSection(&This->lock);
+
+    return S_OK;
+}
+
+static HRESULT WINAPI JpegEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface,
+    IWICMetadataQueryWriter **ppIMetadataQueryWriter)
+{
+    FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter);
+    return E_NOTIMPL;
+}
+
+static const IWICBitmapEncoderVtbl JpegEncoder_Vtbl = {
+    JpegEncoder_QueryInterface,
+    JpegEncoder_AddRef,
+    JpegEncoder_Release,
+    JpegEncoder_Initialize,
+    JpegEncoder_GetContainerFormat,
+    JpegEncoder_GetEncoderInfo,
+    JpegEncoder_SetColorContexts,
+    JpegEncoder_SetPalette,
+    JpegEncoder_SetThumbnail,
+    JpegEncoder_SetPreview,
+    JpegEncoder_CreateNewFrame,
+    JpegEncoder_Commit,
+    JpegEncoder_GetMetadataQueryWriter
+};
+
+HRESULT JpegEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    JpegEncoder *This;
+    HRESULT ret;
+
+    TRACE("(%p,%s,%p)\n", pUnkOuter, debugstr_guid(iid), ppv);
+
+    *ppv = NULL;
+
+    if (pUnkOuter) return CLASS_E_NOAGGREGATION;
+
+    if (!libjpeg_handle && !load_libjpeg())
+    {
+        ERR("Failed writing JPEG because unable to find %s\n",SONAME_LIBJPEG);
+        return E_FAIL;
+    }
+
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(JpegEncoder));
+    if (!This) return E_OUTOFMEMORY;
+
+    This->IWICBitmapEncoder_iface.lpVtbl = &JpegEncoder_Vtbl;
+    This->IWICBitmapFrameEncode_iface.lpVtbl = &JpegEncoder_FrameVtbl;
+    This->ref = 1;
+    This->initialized = 0;
+    This->frame_count = 0;
+    This->frame_initialized = 0;
+    This->started_compress = 0;
+    This->lines_written = 0;
+    This->frame_committed = 0;
+    This->committed = 0;
+    This->width = This->height = 0;
+    This->xres = This->yres = 0.0;
+    This->format = NULL;
+    This->stream = NULL;
+    InitializeCriticalSection(&This->lock);
+    This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JpegEncoder.lock");
+
+    ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv);
+    IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface);
+
+    return ret;
+}
+
+#else /* !defined(SONAME_LIBJPEG) */
+
+HRESULT JpegDecoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    ERR("Trying to load JPEG picture, but JPEG support is not compiled in.\n");
+    return E_FAIL;
+}
+
+HRESULT JpegEncoder_CreateInstance(IUnknown *pUnkOuter, REFIID iid, void** ppv)
+{
+    ERR("Trying to save JPEG picture, but JPEG support is not compiled in.\n");
     return E_FAIL;
 }
 
index 7ec5d41..2898d97 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 
+#define COBJMACROS
 #include "config.h"
 
 #include <stdarg.h>
 
 WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
 
+extern BOOL WINAPI WIC_DllMain(HINSTANCE, DWORD, LPVOID) DECLSPEC_HIDDEN;
+
 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
 {
 
     switch (fdwReason)
     {
-        case DLL_WINE_PREATTACH:
-            return FALSE;    /* prefer native version */
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
             break;
@@ -46,7 +47,12 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             break;
     }
 
-    return TRUE;
+    return WIC_DllMain(hinstDLL, fdwReason, lpvReserved);
+}
+
+HRESULT WINAPI DllCanUnloadNow(void)
+{
+    return S_FALSE;
 }
 
 HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
@@ -55,18 +61,37 @@ HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
 {
     UINT bytesperrow;
     UINT row_offset; /* number of bits into the source rows where the data starts */
+    WICRect rect;
 
-    if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
-        return E_INVALIDARG;
+    if (!rc)
+    {
+        rect.X = 0;
+        rect.Y = 0;
+        rect.Width = srcwidth;
+        rect.Height = srcheight;
+        rc = &rect;
+    }
+    else
+    {
+        if (rc->X < 0 || rc->Y < 0 || rc->X+rc->Width > srcwidth || rc->Y+rc->Height > srcheight)
+            return E_INVALIDARG;
+    }
 
     bytesperrow = ((bpp * rc->Width)+7)/8;
 
     if (dststride < bytesperrow)
         return E_INVALIDARG;
 
-    if ((dststride * rc->Height) > dstbuffersize)
+    if ((dststride * (rc->Height-1)) + ((rc->Width * bpp) + 7)/8 > dstbuffersize)
         return E_INVALIDARG;
 
+    /* if the whole bitmap is copied and the buffer format matches then it's a matter of a single memcpy */
+    if (rc->X == 0 && rc->Y == 0 && rc->Width == srcwidth && rc->Height == srcheight && srcstride == dststride)
+    {
+        memcpy(dstbuffer, srcbuffer, srcstride * srcheight);
+        return S_OK;
+    }
+
     row_offset = rc->X * bpp;
 
     if (row_offset % 8 == 0)
@@ -93,3 +118,46 @@ HRESULT copy_pixels(UINT bpp, const BYTE *srcbuffer,
         return E_FAIL;
     }
 }
+
+void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT height, INT stride)
+{
+    UINT x, y;
+    BYTE *pixel, temp;
+
+    for (y=0; y<height; y++)
+    {
+        pixel = bits + stride * y;
+
+        for (x=0; x<width; x++)
+        {
+            temp = pixel[2];
+            pixel[2] = pixel[0];
+            pixel[0] = temp;
+            pixel += bytesperpixel;
+        }
+    }
+}
+
+HRESULT get_pixelformat_bpp(const GUID *pixelformat, UINT *bpp)
+{
+    HRESULT hr;
+    IWICComponentInfo *info;
+    IWICPixelFormatInfo *formatinfo;
+
+    hr = CreateComponentInfo(pixelformat, &info);
+    if (SUCCEEDED(hr))
+    {
+        hr = IWICComponentInfo_QueryInterface(info, &IID_IWICPixelFormatInfo, (void**)&formatinfo);
+
+        if (SUCCEEDED(hr))
+        {
+            hr = IWICPixelFormatInfo_GetBitsPerPixel(formatinfo, bpp);
+
+            IWICPixelFormatInfo_Release(formatinfo);
+        }
+
+        IWICComponentInfo_Release(info);
+    }
+
+    return hr;
+}
diff --git a/reactos/dll/win32/windowscodecs/metadatahandler.c b/reactos/dll/win32/windowscodecs/metadatahandler.c
new file mode 100644 (file)
index 0000000..6b19f84
--- /dev/null
@@ -0,0 +1,1166 @@
+/*
+ * Copyright 2012 Vincent Povirk for CodeWeavers
+ * Copyright 2012 Dmitry Timoshkov
+ *
+ * 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 <stdarg.h>
+#include <stdio.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+
+#include "windef.h"
+#include "winbase.h"
+#include "winternl.h"
+#include "objbase.h"
+#include "wincodec.h"
+#include "wincodecsdk.h"
+
+#include "wincodecs_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
+
+typedef struct MetadataHandler {
+    IWICMetadataWriter IWICMetadataWriter_iface;
+    LONG ref;
+    IWICPersistStream IWICPersistStream_iface;
+    const MetadataHandlerVtbl *vtable;
+    MetadataItem *items;
+    DWORD item_count;
+    CRITICAL_SECTION lock;
+} MetadataHandler;
+
+static inline MetadataHandler *impl_from_IWICMetadataWriter(IWICMetadataWriter *iface)
+{
+    return CONTAI