From ae80686d816b6383d5e46b90ced89b680b62642d Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 5 Mar 2018 00:19:05 +0100 Subject: [PATCH] [WINDOWSCODECS] Sync with Wine Staging 3.3. CORE-14434 --- dll/win32/windowscodecs/CMakeLists.txt | 15 +- dll/win32/windowscodecs/bitmap.c | 225 +++- dll/win32/windowscodecs/bmpdecode.c | 19 +- dll/win32/windowscodecs/bmpencode.c | 112 +- dll/win32/windowscodecs/clipper.c | 12 + dll/win32/windowscodecs/clsfactory.c | 18 + dll/win32/windowscodecs/colorcontext.c | 14 + dll/win32/windowscodecs/colortransform.c | 14 + dll/win32/windowscodecs/converter.c | 269 ++++- dll/win32/windowscodecs/fliprotate.c | 14 + dll/win32/windowscodecs/gifformat.c | 1036 ++++++++++++++++- dll/win32/windowscodecs/icnsformat.c | 25 +- dll/win32/windowscodecs/icoformat.c | 19 +- dll/win32/windowscodecs/imgfactory.c | 133 ++- dll/win32/windowscodecs/info.c | 37 +- dll/win32/windowscodecs/jpegformat.c | 99 +- dll/win32/windowscodecs/main.c | 14 + dll/win32/windowscodecs/metadatahandler.c | 67 +- dll/win32/windowscodecs/metadataquery.c | 16 +- dll/win32/windowscodecs/palette.c | 294 ++++- dll/win32/windowscodecs/pngformat.c | 74 +- dll/win32/windowscodecs/precomp.h | 30 + dll/win32/windowscodecs/propertybag.c | 19 +- dll/win32/windowscodecs/proxy.c | 14 + dll/win32/windowscodecs/regsvr.c | 132 ++- dll/win32/windowscodecs/scaler.c | 183 +++ dll/win32/windowscodecs/stream.c | 10 +- dll/win32/windowscodecs/tgaformat.c | 16 + dll/win32/windowscodecs/tiffformat.c | 431 +++++-- dll/win32/windowscodecs/ungif.c | 9 +- dll/win32/windowscodecs/wincodecs_private.h | 110 +- dll/win32/windowscodecs/windowscodecs.spec | 3 +- .../windowscodecs/windowscodecs_wincodec.idl | 7 + media/doc/README.WINE | 2 +- 34 files changed, 3112 insertions(+), 380 deletions(-) create mode 100644 dll/win32/windowscodecs/precomp.h diff --git a/dll/win32/windowscodecs/CMakeLists.txt b/dll/win32/windowscodecs/CMakeLists.txt index 7ed058d1121..6c67bfe1a9e 100644 --- a/dll/win32/windowscodecs/CMakeLists.txt +++ b/dll/win32/windowscodecs/CMakeLists.txt @@ -23,7 +23,6 @@ spec2def(windowscodecs.dll windowscodecs.spec ADD_IMPORTLIB) add_rpcproxy_files(windowscodecs_wincodec.idl) list(APPEND SOURCE - bitmap.c bmpdecode.c bmpencode.c clipper.c @@ -51,7 +50,17 @@ list(APPEND SOURCE tgaformat.c tiffformat.c ungif.c - wincodecs_private.h) + precomp.h) + +if(MSVC) + if(ARCH STREQUAL "i386") + list(APPEND SOURCE msvc-thiscall.c) + endif() + set_source_files_properties(bitmap.c PROPERTIES COMPILE_FLAGS "/FImsvc.h") + list(APPEND ADDITIONAL_SOURCE bitmap.c) +else() + list(APPEND SOURCE bitmap.c) +endif() list(APPEND ADDITIONAL_SOURCE guid.c @@ -68,5 +77,5 @@ add_library(windowscodecs SHARED set_module_type(windowscodecs win32dll) target_link_libraries(windowscodecs wine uuid ${PSEH_LIB}) add_importlibs(windowscodecs ole32 oleaut32 rpcrt4 shlwapi user32 gdi32 advapi32 advapi32_vista propsys msvcrt kernel32 ntdll) -add_pch(windowscodecs wincodecs_private.h SOURCE) +add_pch(windowscodecs precomp.h SOURCE) add_cd_file(TARGET windowscodecs DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/windowscodecs/bitmap.c b/dll/win32/windowscodecs/bitmap.c index dfd7dda89fa..69ec14fed28 100644 --- a/dll/win32/windowscodecs/bitmap.c +++ b/dll/win32/windowscodecs/bitmap.c @@ -16,8 +16,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + /* WARNING: .NET Media Integration Layer (MIL) directly dereferences * BitmapImpl members and depends on its exact layout. */ @@ -31,6 +45,7 @@ typedef struct BitmapImpl { int palette_set; LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ BYTE *data; + BOOL is_section; /* TRUE if data is a section created by an application */ UINT width, height; UINT stride; UINT bpp; @@ -121,6 +136,7 @@ static HRESULT WINAPI BitmapLockImpl_QueryInterface(IWICBitmapLock *iface, REFII } else { + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -234,12 +250,14 @@ static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid, { *ppv = &This->IWICBitmap_iface; } - else if (IsEqualIID(&IID_IMILBitmapSource, iid)) + else if (IsEqualIID(&IID_IMILBitmap, iid) || + IsEqualIID(&IID_IMILBitmapSource, iid)) { *ppv = &This->IMILBitmapSource_iface; } else { + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -270,7 +288,10 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) if (This->palette) IWICPalette_Release(This->palette); This->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->cs); - HeapFree(GetProcessHeap(), 0, This->data); + if (This->is_section) + UnmapViewOfFile(This->data); + else + HeapFree(GetProcessHeap(), 0, This->data); HeapFree(GetProcessHeap(), 0, This); } @@ -465,13 +486,22 @@ static HRESULT WINAPI IMILBitmapImpl_QueryInterface(IMILBitmapSource *iface, REF if (!ppv) return E_INVALIDARG; if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IMILBitmap, iid) || IsEqualIID(&IID_IMILBitmapSource, iid)) { IUnknown_AddRef(&This->IMILBitmapSource_iface); *ppv = &This->IMILBitmapSource_iface; return S_OK; } + else if (IsEqualIID(&IID_IWICBitmap, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid)) + { + IUnknown_AddRef(&This->IWICBitmap_iface); + *ppv = &This->IWICBitmap_iface; + return S_OK; + } + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -492,6 +522,7 @@ static HRESULT WINAPI IMILBitmapImpl_GetSize(IMILBitmapSource *iface, UINT *width, UINT *height) { BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p,%p)\n", iface, width, height); return IWICBitmap_GetSize(&This->IWICBitmap_iface, width, height); } @@ -545,6 +576,7 @@ static HRESULT WINAPI IMILBitmapImpl_GetPixelFormat(IMILBitmapSource *iface, } } + TRACE("=> %u\n", *format); return S_OK; } @@ -552,6 +584,7 @@ static HRESULT WINAPI IMILBitmapImpl_GetResolution(IMILBitmapSource *iface, double *dpix, double *dpiy) { BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p,%p)\n", iface, dpix, dpiy); return IWICBitmap_GetResolution(&This->IWICBitmap_iface, dpix, dpiy); } @@ -559,6 +592,7 @@ static HRESULT WINAPI IMILBitmapImpl_CopyPalette(IMILBitmapSource *iface, IWICPalette *palette) { BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p)\n", iface, palette); return IWICBitmap_CopyPalette(&This->IWICBitmap_iface, palette); } @@ -566,10 +600,11 @@ static HRESULT WINAPI IMILBitmapImpl_CopyPixels(IMILBitmapSource *iface, const WICRect *rc, UINT stride, UINT size, BYTE *buffer) { BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p,%u,%u,%p)\n", iface, rc, stride, size, buffer); return IWICBitmap_CopyPixels(&This->IWICBitmap_iface, rc, stride, size, buffer); } -static HRESULT WINAPI IMILBitmapImpl_UnknownMethod1(IMILBitmapSource *iface, void **ppv) +static HRESULT WINAPI IMILBitmapImpl_unknown1(IMILBitmapSource *iface, void **ppv) { BitmapImpl *This = impl_from_IMILBitmapSource(iface); @@ -577,12 +612,46 @@ static HRESULT WINAPI IMILBitmapImpl_UnknownMethod1(IMILBitmapSource *iface, voi if (!ppv) return E_INVALIDARG; - IUnknown_AddRef(&This->IMILUnknown1_iface); + /* reference count is not incremented here */ *ppv = &This->IMILUnknown1_iface; return S_OK; } +static HRESULT WINAPI IMILBitmapImpl_Lock(IMILBitmapSource *iface, const WICRect *rc, DWORD flags, IWICBitmapLock **lock) +{ + BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p,%08x,%p)\n", iface, rc, flags, lock); + return IWICBitmap_Lock(&This->IWICBitmap_iface, rc, flags, lock); +} + +static HRESULT WINAPI IMILBitmapImpl_Unlock(IMILBitmapSource *iface, IWICBitmapLock *lock) +{ + TRACE("(%p,%p)\n", iface, lock); + IWICBitmapLock_Release(lock); + return S_OK; +} + +static HRESULT WINAPI IMILBitmapImpl_SetPalette(IMILBitmapSource *iface, IWICPalette *palette) +{ + BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%p)\n", iface, palette); + return IWICBitmap_SetPalette(&This->IWICBitmap_iface, palette); +} + +static HRESULT WINAPI IMILBitmapImpl_SetResolution(IMILBitmapSource *iface, double dpix, double dpiy) +{ + BitmapImpl *This = impl_from_IMILBitmapSource(iface); + TRACE("(%p,%f,%f)\n", iface, dpix, dpiy); + return IWICBitmap_SetResolution(&This->IWICBitmap_iface, dpix, dpiy); +} + +static HRESULT WINAPI IMILBitmapImpl_AddDirtyRect(IMILBitmapSource *iface, const WICRect *rc) +{ + FIXME("(%p,%p): stub\n", iface, rc); + return E_NOTIMPL; +} + static const IMILBitmapSourceVtbl IMILBitmapImpl_Vtbl = { IMILBitmapImpl_QueryInterface, @@ -593,26 +662,20 @@ static const IMILBitmapSourceVtbl IMILBitmapImpl_Vtbl = IMILBitmapImpl_GetResolution, IMILBitmapImpl_CopyPalette, IMILBitmapImpl_CopyPixels, - IMILBitmapImpl_UnknownMethod1, + IMILBitmapImpl_unknown1, + IMILBitmapImpl_Lock, + IMILBitmapImpl_Unlock, + IMILBitmapImpl_SetPalette, + IMILBitmapImpl_SetResolution, + IMILBitmapImpl_AddDirtyRect }; static HRESULT WINAPI IMILUnknown1Impl_QueryInterface(IMILUnknown1 *iface, REFIID iid, void **ppv) { - BitmapImpl *This = impl_from_IMILUnknown1(iface); - - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); - - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid)) - { - IUnknown_AddRef(&This->IMILUnknown1_iface); - *ppv = iface; - return S_OK; - } - - return IWICBitmap_QueryInterface(&This->IWICBitmap_iface, iid, ppv); + FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv); + *ppv = NULL; + return E_NOINTERFACE; } static ULONG WINAPI IMILUnknown1Impl_AddRef(IMILUnknown1 *iface) @@ -627,47 +690,108 @@ static ULONG WINAPI IMILUnknown1Impl_Release(IMILUnknown1 *iface) return IWICBitmap_Release(&This->IWICBitmap_iface); } +DECLSPEC_HIDDEN void WINAPI IMILUnknown1Impl_unknown1(IMILUnknown1 *iface, void *arg) +{ + FIXME("(%p,%p): stub\n", iface, arg); +} + +static HRESULT WINAPI IMILUnknown1Impl_unknown2(IMILUnknown1 *iface, void *arg1, void *arg2) +{ + FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2); + return E_NOTIMPL; +} + +DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown3(IMILUnknown1 *iface, void *arg) +{ + FIXME("(%p,%p): stub\n", iface, arg); + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown1Impl_unknown4(IMILUnknown1 *iface, void *arg) +{ + FIXME("(%p,%p): stub\n", iface, arg); + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown1Impl_unknown5(IMILUnknown1 *iface, void *arg) +{ + FIXME("(%p,%p): stub\n", iface, arg); + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown1Impl_unknown6(IMILUnknown1 *iface, DWORD64 arg) +{ + FIXME("(%p,%s): stub\n", iface, wine_dbgstr_longlong(arg)); + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown1Impl_unknown7(IMILUnknown1 *iface, void *arg) +{ + FIXME("(%p,%p): stub\n", iface, arg); + return E_NOTIMPL; +} + +DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown8(IMILUnknown1 *iface) +{ + FIXME("(%p): stub\n", iface); + return E_NOTIMPL; +} + +DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown1, 8) +DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown3, 8) +DEFINE_THISCALL_WRAPPER(IMILUnknown1Impl_unknown8, 4) + static const IMILUnknown1Vtbl IMILUnknown1Impl_Vtbl = { IMILUnknown1Impl_QueryInterface, IMILUnknown1Impl_AddRef, IMILUnknown1Impl_Release, + THISCALL(IMILUnknown1Impl_unknown1), + IMILUnknown1Impl_unknown2, + THISCALL(IMILUnknown1Impl_unknown3), + IMILUnknown1Impl_unknown4, + IMILUnknown1Impl_unknown5, + IMILUnknown1Impl_unknown6, + IMILUnknown1Impl_unknown7, + THISCALL(IMILUnknown1Impl_unknown8) }; static HRESULT WINAPI IMILUnknown2Impl_QueryInterface(IMILUnknown2 *iface, REFIID iid, void **ppv) { - BitmapImpl *This = impl_from_IMILUnknown2(iface); - - TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); - - if (!ppv) return E_INVALIDARG; - - if (IsEqualIID(&IID_IUnknown, iid)) - { - IUnknown_AddRef(&This->IMILUnknown2_iface); - *ppv = iface; - return S_OK; - } - - return IWICBitmap_QueryInterface(&This->IWICBitmap_iface, iid, ppv); + FIXME("(%p,%s,%p): stub\n", iface, debugstr_guid(iid), ppv); + *ppv = NULL; + return E_NOINTERFACE; } static ULONG WINAPI IMILUnknown2Impl_AddRef(IMILUnknown2 *iface) { - BitmapImpl *This = impl_from_IMILUnknown2(iface); - return IWICBitmap_AddRef(&This->IWICBitmap_iface); + FIXME("(%p): stub\n", iface); + return 0; } static ULONG WINAPI IMILUnknown2Impl_Release(IMILUnknown2 *iface) { - BitmapImpl *This = impl_from_IMILUnknown2(iface); - return IWICBitmap_Release(&This->IWICBitmap_iface); + FIXME("(%p): stub\n", iface); + return 0; } -static HRESULT WINAPI IMILUnknown2Impl_UnknownMethod1(IMILUnknown2 *iface, void *arg1, void *arg2) +static HRESULT WINAPI IMILUnknown2Impl_unknown1(IMILUnknown2 *iface, void *arg1, void **arg2) { FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2); + if (arg2) *arg2 = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown2Impl_unknown2(IMILUnknown2 *iface, void *arg1, void *arg2) +{ + FIXME("(%p,%p,%p): stub\n", iface, arg1, arg2); + return E_NOTIMPL; +} + +static HRESULT WINAPI IMILUnknown2Impl_unknown3(IMILUnknown2 *iface, void *arg1) +{ + FIXME("(%p,%p): stub\n", iface, arg1); return E_NOTIMPL; } @@ -676,17 +800,18 @@ static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl = IMILUnknown2Impl_QueryInterface, IMILUnknown2Impl_AddRef, IMILUnknown2Impl_Release, - IMILUnknown2Impl_UnknownMethod1, + IMILUnknown2Impl_unknown1, + IMILUnknown2Impl_unknown2, + IMILUnknown2Impl_unknown3 }; HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, - UINT stride, UINT datasize, BYTE *bits, + UINT stride, UINT datasize, BYTE *data, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap) { HRESULT hr; BitmapImpl *This; - BYTE *data; UINT bpp; hr = get_pixelformat_bpp(pixelFormat, &bpp); @@ -699,14 +824,20 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG; This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); - if (!This || !data) + if (!This) return E_OUTOFMEMORY; + + if (!data) { - HeapFree(GetProcessHeap(), 0, This); - HeapFree(GetProcessHeap(), 0, data); - return E_OUTOFMEMORY; + data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); + if (!data) + { + HeapFree(GetProcessHeap(), 0, This); + return E_OUTOFMEMORY; + } + This->is_section = FALSE; } - if (bits) memcpy(data, bits, datasize); + else + This->is_section = TRUE; This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl; This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl; diff --git a/dll/win32/windowscodecs/bmpdecode.c b/dll/win32/windowscodecs/bmpdecode.c index 5039694a764..47f312ffcf0 100644 --- a/dll/win32/windowscodecs/bmpdecode.c +++ b/dll/win32/windowscodecs/bmpdecode.c @@ -16,9 +16,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wincodecs_private.h" +#include "config.h" #include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wingdi.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); typedef struct { DWORD bc2Size; @@ -256,7 +271,7 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, if (This->bih.bV5ClrUsed == 0) count = 1 << This->bih.bV5BitCount; else - count = This->bih.bV5ClrUsed; + count = min(This->bih.bV5ClrUsed, 1 << This->bih.bV5BitCount); tablesize = sizeof(WICColor) * count; wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize); diff --git a/dll/win32/windowscodecs/bmpencode.c b/dll/win32/windowscodecs/bmpencode.c index e339324015b..cb8b4897e49 100644 --- a/dll/win32/windowscodecs/bmpencode.c +++ b/dll/win32/windowscodecs/bmpencode.c @@ -1,5 +1,6 @@ /* * Copyright 2009 Vincent Povirk for CodeWeavers + * Copyright 2016 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,13 +17,28 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "wingdi.h" +#include "objbase.h" + #include "wincodecs_private.h" -#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); struct bmp_pixelformat { const WICPixelFormatGUID *guid; UINT bpp; + UINT colors; /* palette size */ DWORD compression; DWORD redmask; DWORD greenmask; @@ -31,13 +47,18 @@ struct bmp_pixelformat { }; static const struct bmp_pixelformat formats[] = { - {&GUID_WICPixelFormat24bppBGR, 24, BI_RGB}, - {&GUID_WICPixelFormat16bppBGR555, 16, BI_RGB}, - {&GUID_WICPixelFormat16bppBGR565, 16, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0}, - {&GUID_WICPixelFormat32bppBGR, 32, BI_RGB}, + {&GUID_WICPixelFormat24bppBGR, 24, 0, BI_RGB}, + {&GUID_WICPixelFormatBlackWhite, 1, 2, BI_RGB}, + {&GUID_WICPixelFormat1bppIndexed, 1, 2, BI_RGB}, + {&GUID_WICPixelFormat2bppIndexed, 2, 4, BI_RGB}, + {&GUID_WICPixelFormat4bppIndexed, 4, 16, BI_RGB}, + {&GUID_WICPixelFormat8bppIndexed, 8, 256, BI_RGB}, + {&GUID_WICPixelFormat16bppBGR555, 16, 0, BI_RGB}, + {&GUID_WICPixelFormat16bppBGR565, 16, 0, BI_BITFIELDS, 0xf800, 0x7e0, 0x1f, 0}, + {&GUID_WICPixelFormat32bppBGR, 32, 0, BI_RGB}, #if 0 /* Windows doesn't seem to support this one. */ - {&GUID_WICPixelFormat32bppBGRA, 32, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000}, + {&GUID_WICPixelFormat32bppBGRA, 32, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000}, #endif {NULL} }; @@ -58,6 +79,8 @@ typedef struct BmpFrameEncode { BOOL committed; } BmpFrameEncode; +static const WCHAR wszEnableV5Header32bppBGRA[] = {'E','n','a','b','l','e','V','5','H','e','a','d','e','r','3','2','b','p','p','B','G','R','A',0}; + static inline BmpFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) { return CONTAINING_RECORD(iface, BmpFrameEncode, IWICBitmapFrameEncode_iface); @@ -121,6 +144,9 @@ static HRESULT WINAPI BmpFrameEncode_Initialize(IWICBitmapFrameEncode *iface, if (This->initialized) return WINCODEC_ERR_WRONGSTATE; + if (pIEncoderOptions) + WARN("ignoring encoder options.\n"); + This->initialized = TRUE; return S_OK; @@ -165,11 +191,13 @@ static HRESULT WINAPI BmpFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface for (i=0; formats[i].guid; i++) { - if (memcmp(formats[i].guid, pPixelFormat, sizeof(GUID)) == 0) + if (IsEqualGUID(formats[i].guid, pPixelFormat)) break; } if (!formats[i].guid) i = 0; + else if (IsEqualGUID(pPixelFormat, &GUID_WICPixelFormatBlackWhite)) + i = 2; /* GUID_WICPixelFormat1bppIndexed */ This->format = &formats[i]; memcpy(pPixelFormat, This->format->guid, sizeof(GUID)); @@ -188,6 +216,7 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette) { BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; TRACE("(%p,%p)\n", iface, palette); @@ -196,7 +225,14 @@ static HRESULT WINAPI BmpFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, if (!This->initialized) return WINCODEC_ERR_NOTINITIALIZED; - return IWICPalette_GetColors(palette, 256, This->palette, &This->colors); + hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); + if (hr == S_OK) + { + UINT i; + for (i = 0; i < This->colors; i++) + This->palette[i] |= 0xff000000; /* BMP palette has no alpha */ + } + return hr; } static HRESULT WINAPI BmpFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, @@ -278,10 +314,11 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); BITMAPFILEHEADER bfh; BITMAPV5HEADER bih; - UINT info_size; + UINT info_size, i; LARGE_INTEGER pos; ULONG byteswritten; HRESULT hr; + const BYTE *bits; TRACE("(%p)\n", iface); @@ -294,15 +331,15 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) bih.bV5Size = info_size = sizeof(BITMAPINFOHEADER); bih.bV5Width = This->width; - bih.bV5Height = -This->height; /* top-down bitmap */ + bih.bV5Height = This->height; /* bottom-top bitmap */ bih.bV5Planes = 1; bih.bV5BitCount = This->format->bpp; bih.bV5Compression = This->format->compression; bih.bV5SizeImage = This->stride*This->height; bih.bV5XPelsPerMeter = (This->xres+0.0127) / 0.0254; bih.bV5YPelsPerMeter = (This->yres+0.0127) / 0.0254; - bih.bV5ClrUsed = 0; - bih.bV5ClrImportant = 0; + bih.bV5ClrUsed = (This->format->bpp <= 8) ? This->colors : 0; + bih.bV5ClrImportant = bih.bV5ClrUsed; if (This->format->compression == BI_BITFIELDS) { @@ -319,6 +356,7 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) bfh.bfSize = sizeof(BITMAPFILEHEADER) + info_size + bih.bV5SizeImage; bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + info_size; + bfh.bfOffBits += bih.bV5ClrUsed * sizeof(WICColor); pos.QuadPart = 0; hr = IStream_Seek(This->stream, pos, STREAM_SEEK_SET, NULL); @@ -332,9 +370,23 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) if (FAILED(hr)) return hr; if (byteswritten != info_size) return E_FAIL; - hr = IStream_Write(This->stream, This->bits, bih.bV5SizeImage, &byteswritten); - if (FAILED(hr)) return hr; - if (byteswritten != bih.bV5SizeImage) return E_FAIL; + /* write the palette */ + if (This->format->colors) + { + hr = IStream_Write(This->stream, This->palette, This->colors * sizeof(WICColor), &byteswritten); + if (FAILED(hr)) return hr; + if (byteswritten != This->colors * sizeof(WICColor)) return E_FAIL; + } + + /* write the image bits as a bottom-top array */ + bits = This->bits + bih.bV5SizeImage; + for (i = 0; i < This->height; i++) + { + bits -= This->stride; + hr = IStream_Write(This->stream, bits, This->stride, &byteswritten); + if (FAILED(hr)) return hr; + if (byteswritten != This->stride) return E_FAIL; + } This->committed = TRUE; @@ -447,11 +499,22 @@ static HRESULT WINAPI BmpEncoder_GetContainerFormat(IWICBitmapEncoder *iface, return S_OK; } -static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, - IWICBitmapEncoderInfo **ppIEncoderInfo) +static HRESULT WINAPI BmpEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) { - FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo); - return E_NOTIMPL; + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICBmpEncoder, &comp_info); + if (hr == S_OK) + { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; } static HRESULT WINAPI BmpEncoder_SetColorContexts(IWICBitmapEncoder *iface, @@ -487,6 +550,10 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface, BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); BmpFrameEncode *encode; HRESULT hr; + static const PROPBAG2 opts[1] = + { + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszEnableV5Header32bppBGRA }, + }; TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -494,8 +561,11 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface, if (!This->stream) return WINCODEC_ERR_NOTINITIALIZED; - hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions); - if (FAILED(hr)) return hr; + if (ppIEncoderOptions) + { + hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); + if (FAILED(hr)) return hr; + } encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode)); if (!encode) diff --git a/dll/win32/windowscodecs/clipper.c b/dll/win32/windowscodecs/clipper.c index f7df2302478..94127f3df15 100644 --- a/dll/win32/windowscodecs/clipper.c +++ b/dll/win32/windowscodecs/clipper.c @@ -16,8 +16,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct BitmapClipper { IWICBitmapClipper IWICBitmapClipper_iface; LONG ref; diff --git a/dll/win32/windowscodecs/clsfactory.c b/dll/win32/windowscodecs/clsfactory.c index 2116ff9e8b4..98938eb8726 100644 --- a/dll/win32/windowscodecs/clsfactory.c +++ b/dll/win32/windowscodecs/clsfactory.c @@ -16,8 +16,25 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "objbase.h" +#include "ocidl.h" +#include "initguid.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + extern HRESULT WINAPI WIC_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN; typedef struct { @@ -32,6 +49,7 @@ static const classinfo wic_classes[] = { {&CLSID_WICPngEncoder, PngEncoder_CreateInstance}, {&CLSID_WICBmpEncoder, BmpEncoder_CreateInstance}, {&CLSID_WICGifDecoder, GifDecoder_CreateInstance}, + {&CLSID_WICGifEncoder, GifEncoder_CreateInstance}, {&CLSID_WICIcoDecoder, IcoDecoder_CreateInstance}, {&CLSID_WICJpegDecoder, JpegDecoder_CreateInstance}, {&CLSID_WICJpegEncoder, JpegEncoder_CreateInstance}, diff --git a/dll/win32/windowscodecs/colorcontext.c b/dll/win32/windowscodecs/colorcontext.c index d0c0a3bb364..eb13482cf43 100644 --- a/dll/win32/windowscodecs/colorcontext.c +++ b/dll/win32/windowscodecs/colorcontext.c @@ -16,8 +16,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct ColorContext { IWICColorContext IWICColorContext_iface; LONG ref; diff --git a/dll/win32/windowscodecs/colortransform.c b/dll/win32/windowscodecs/colortransform.c index 6a3f7d1528f..5b1c7e8b70e 100644 --- a/dll/win32/windowscodecs/colortransform.c +++ b/dll/win32/windowscodecs/colortransform.c @@ -16,8 +16,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct ColorTransform { IWICColorTransform IWICColorTransform_iface; LONG ref; diff --git a/dll/win32/windowscodecs/converter.c b/dll/win32/windowscodecs/converter.c index d6086b087a5..c3bcce89e00 100644 --- a/dll/win32/windowscodecs/converter.c +++ b/dll/win32/windowscodecs/converter.c @@ -17,9 +17,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" -#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); struct FormatConverter; @@ -40,8 +53,11 @@ enum pixelformat { format_24bppRGB, format_32bppGrayFloat, format_32bppBGR, + format_32bppRGB, format_32bppBGRA, + format_32bppRGBA, format_32bppPBGRA, + format_32bppPRGBA, format_48bppRGB, format_64bppRGBA, format_32bppCMYK, @@ -63,7 +79,7 @@ typedef struct FormatConverter { const struct pixelformatinfo *dst_format, *src_format; WICBitmapDitherType dither; double alpha_threshold; - WICBitmapPaletteType palette_type; + IWICPalette *palette; CRITICAL_SECTION lock; /* must be held when initialized */ } FormatConverter; @@ -847,6 +863,27 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } } +static HRESULT copypixels_to_32bppRGBA(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + HRESULT hr; + + switch (source_format) + { + case format_32bppRGB: + case format_32bppRGBA: + case format_32bppPRGBA: + 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) + reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride); + return hr; + } +} + static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) { @@ -863,6 +900,22 @@ static HRESULT copypixels_to_32bppBGR(struct FormatConverter *This, const WICRec } } +static HRESULT copypixels_to_32bppRGB(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + switch (source_format) + { + case format_32bppRGB: + case format_32bppRGBA: + case format_32bppPRGBA: + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + return S_OK; + default: + return copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); + } +} + static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) { @@ -896,6 +949,39 @@ static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICR } } +static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + HRESULT hr; + + switch (source_format) + { + case format_32bppPRGBA: + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + return S_OK; + default: + hr = copypixels_to_32bppRGBA(This, prc, cbStride, cbBufferSize, pbBuffer, source_format); + if (SUCCEEDED(hr) && prc) + { + INT x, y; + + for (y=0; yHeight; y++) + for (x=0; xWidth; 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 HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) { @@ -1208,11 +1294,95 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec return hr; } +static UINT rgb_to_palette_index(BYTE r, BYTE g, BYTE b, WICColor *colors, UINT count) +{ + UINT best_diff, best_index, i; + + best_diff = ~0; + best_index = 0; + + for (i = 0; i < count; i++) + { + BYTE pal_r, pal_g, pal_b; + DWORD diff_r, diff_g, diff_b, diff; + + pal_r = colors[i] >> 16; + pal_g = colors[i] >> 8; + pal_b = colors[i]; + + diff_r = r - pal_r; + diff_g = g - pal_g; + diff_b = b - pal_b; + + diff = diff_r * diff_r + diff_g * diff_g + diff_b * diff_b; + if (diff == 0) return i; + + if (diff < best_diff) + { + best_diff = diff; + best_index = i; + } + } + + return best_index; +} + +static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + HRESULT hr; + BYTE *srcdata; + WICColor colors[256]; + UINT srcstride, srcdatasize, count; + + if (source_format == format_8bppIndexed) + { + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + + return S_OK; + } + + if (!This->palette) return WINCODEC_ERR_WRONGSTATE; + + hr = IWICPalette_GetColors(This->palette, 256, colors, &count); + if (hr != S_OK) return hr; + + srcstride = 3 * prc->Width; + srcdatasize = srcstride * prc->Height; + + srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + if (!srcdata) return E_OUTOFMEMORY; + + hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); + if (SUCCEEDED(hr) && prc) + { + INT x, y; + BYTE *src = srcdata, *dst = pbBuffer; + + for (y = 0; y < prc->Height; y++) + { + BYTE *bgr = src; + + for (x = 0; x < prc->Width; x++) + { + dst[x] = rgb_to_palette_index(bgr[2], bgr[1], bgr[0], colors, count); + bgr += 3; + } + src += srcstride; + dst += cbStride; + } + } + + HeapFree(GetProcessHeap(), 0, srcdata); + return hr; +} + static const struct pixelformatinfo supported_formats[] = { {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL}, {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL}, {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL}, - {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, NULL}, + {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed}, {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL}, {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL}, {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL}, @@ -1225,8 +1395,11 @@ static const struct pixelformatinfo supported_formats[] = { {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB}, {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat}, {format_32bppBGR, &GUID_WICPixelFormat32bppBGR, copypixels_to_32bppBGR}, + {format_32bppRGB, &GUID_WICPixelFormat32bppRGB, copypixels_to_32bppRGB}, {format_32bppBGRA, &GUID_WICPixelFormat32bppBGRA, copypixels_to_32bppBGRA}, + {format_32bppRGBA, &GUID_WICPixelFormat32bppRGBA, copypixels_to_32bppRGBA}, {format_32bppPBGRA, &GUID_WICPixelFormat32bppPBGRA, copypixels_to_32bppPBGRA}, + {format_32bppPRGBA, &GUID_WICPixelFormat32bppPRGBA, copypixels_to_32bppPRGBA}, {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL}, {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, NULL}, {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL}, @@ -1289,6 +1462,7 @@ static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface) This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); if (This->source) IWICBitmapSource_Release(This->source); + if (This->palette) IWICPalette_Release(This->palette); HeapFree(GetProcessHeap(), 0, This); } @@ -1337,10 +1511,27 @@ static HRESULT WINAPI FormatConverter_GetResolution(IWICFormatConverter *iface, } static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface, - IWICPalette *pIPalette) + IWICPalette *palette) { - FIXME("(%p,%p): stub\n", iface, pIPalette); - return E_NOTIMPL; + FormatConverter *This = impl_from_IWICFormatConverter(iface); + + TRACE("(%p,%p)\n", iface, palette); + + if (!palette) return E_INVALIDARG; + if (!This->source) return WINCODEC_ERR_WRONGSTATE; + + if (!This->palette) + { + HRESULT hr; + UINT bpp; + + hr = get_pixelformat_bpp(This->dst_format->guid, &bpp); + if (hr != S_OK) return hr; + if (bpp <= 8) return WINCODEC_ERR_WRONGSTATE; + return IWICBitmapSource_CopyPalette(This->source, palette); + } + + return IWICPalette_InitializeFromPalette(palette, This->palette); } static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface, @@ -1369,23 +1560,59 @@ static HRESULT WINAPI FormatConverter_CopyPixels(IWICFormatConverter *iface, pbBuffer, This->src_format->format); } else - return WINCODEC_ERR_NOTINITIALIZED; + return WINCODEC_ERR_WRONGSTATE; } static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, - IWICBitmapSource *pISource, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither, - IWICPalette *pIPalette, double alphaThresholdPercent, WICBitmapPaletteType paletteTranslate) + IWICBitmapSource *source, REFWICPixelFormatGUID dstFormat, WICBitmapDitherType dither, + IWICPalette *palette, double alpha_threshold, WICBitmapPaletteType palette_type) { FormatConverter *This = impl_from_IWICFormatConverter(iface); const struct pixelformatinfo *srcinfo, *dstinfo; - static INT fixme=0; GUID srcFormat; - HRESULT res=S_OK; + HRESULT res; - TRACE("(%p,%p,%s,%u,%p,%0.1f,%u)\n", iface, pISource, debugstr_guid(dstFormat), - dither, pIPalette, alphaThresholdPercent, paletteTranslate); + TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat), + dither, palette, alpha_threshold, palette_type); - if (pIPalette && !fixme++) FIXME("ignoring palette\n"); + if (!palette) + { + UINT bpp; + res = get_pixelformat_bpp(dstFormat, &bpp); + if (res != S_OK) return res; + + res = PaletteImpl_Create(&palette); + if (res != S_OK) return res; + + switch (palette_type) + { + case WICBitmapPaletteTypeCustom: + IWICPalette_Release(palette); + palette = NULL; + if (bpp <= 8) return E_INVALIDARG; + break; + + case WICBitmapPaletteTypeMedianCut: + { + if (bpp <= 8) + res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE); + break; + } + + default: + if (bpp <= 8) + res = IWICPalette_InitializePredefined(palette, palette_type, FALSE); + break; + } + + if (res != S_OK) + { + IWICPalette_Release(palette); + return res; + } + } + else + IWICPalette_AddRef(palette); EnterCriticalSection(&This->lock); @@ -1395,7 +1622,7 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, goto end; } - res = IWICBitmapSource_GetPixelFormat(pISource, &srcFormat); + res = IWICBitmapSource_GetPixelFormat(source, &srcFormat); if (FAILED(res)) goto end; srcinfo = get_formatinfo(&srcFormat); @@ -1416,13 +1643,13 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, if (dstinfo->copy_function) { - IWICBitmapSource_AddRef(pISource); + IWICBitmapSource_AddRef(source); This->src_format = srcinfo; This->dst_format = dstinfo; This->dither = dither; - This->alpha_threshold = alphaThresholdPercent; - This->palette_type = paletteTranslate; - This->source = pISource; + This->alpha_threshold = alpha_threshold; + This->palette = palette; + This->source = source; } else { @@ -1434,6 +1661,9 @@ end: LeaveCriticalSection(&This->lock); + if (res != S_OK && palette) + IWICPalette_Release(palette); + return res; } @@ -1501,6 +1731,7 @@ HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv) This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl; This->ref = 1; This->source = NULL; + This->palette = NULL; InitializeCriticalSection(&This->lock); This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock"); diff --git a/dll/win32/windowscodecs/fliprotate.c b/dll/win32/windowscodecs/fliprotate.c index e75107161a5..72d1e8a2878 100644 --- a/dll/win32/windowscodecs/fliprotate.c +++ b/dll/win32/windowscodecs/fliprotate.c @@ -16,8 +16,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct FlipRotator { IWICBitmapFlipRotator IWICBitmapFlipRotator_iface; LONG ref; diff --git a/dll/win32/windowscodecs/gifformat.c b/dll/win32/windowscodecs/gifformat.c index 3bc3bac4094..e898d9c852d 100644 --- a/dll/win32/windowscodecs/gifformat.c +++ b/dll/win32/windowscodecs/gifformat.c @@ -1,6 +1,6 @@ /* * Copyright 2009 Vincent Povirk for CodeWeavers - * Copyright 2012 Dmitry Timoshkov + * Copyright 2012,2016 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,12 +17,63 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wincodecs_private.h" +#include "config.h" -#include +#include + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" #include "ungif.h" +#include "wincodecs_private.h" + +#include "wine/debug.h" + +#ifdef __REACTOS__ +#include +#endif + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +#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; +}; + +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 LPWSTR strdupAtoW(const char *src) { int len = MultiByteToWideChar(CP_ACP, 0, src, -1, NULL, 0); @@ -34,22 +85,7 @@ static LPWSTR strdupAtoW(const char *src) 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" + struct logical_screen_descriptor lsd_data; HRESULT hr; ULONG bytesread, i; MetadataItem *result; @@ -134,23 +170,6 @@ HRESULT LSDReader_CreateInstance(REFIID iid, void **ppv) return MetadataReader_Create(&LSDReader_Vtbl, 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) { @@ -1183,6 +1202,9 @@ static HRESULT WINAPI GifDecoder_CopyPalette(IWICBitmapDecoder *iface, IWICPalet TRACE("(%p,%p)\n", iface, palette); + if (!This->gif) + return WINCODEC_ERR_WRONGSTATE; + cm = This->gif->SColorMap; if (cm) { @@ -1447,3 +1469,945 @@ HRESULT GifDecoder_CreateInstance(REFIID iid, void** ppv) return ret; } + +typedef struct GifEncoder +{ + IWICBitmapEncoder IWICBitmapEncoder_iface; + LONG ref; + IStream *stream; + CRITICAL_SECTION lock; + BOOL initialized, info_written, committed; + UINT n_frames; + WICColor palette[256]; + UINT colors; +} GifEncoder; + +static inline GifEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) +{ + return CONTAINING_RECORD(iface, GifEncoder, IWICBitmapEncoder_iface); +} + +typedef struct GifFrameEncode +{ + IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; + LONG ref; + GifEncoder *encoder; + BOOL initialized, interlace, committed; + UINT width, height, lines; + double xres, yres; + WICColor palette[256]; + UINT colors; + BYTE *image_data; +} GifFrameEncode; + +static inline GifFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) +{ + return CONTAINING_RECORD(iface, GifFrameEncode, IWICBitmapFrameEncode_iface); +} + +static HRESULT WINAPI GifFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv) +{ + TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) + { + IWICBitmapFrameEncode_AddRef(iface); + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI GifFrameEncode_AddRef(IWICBitmapFrameEncode *iface) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("%p -> %u\n", iface, ref); + return ref; +} + +static ULONG WINAPI GifFrameEncode_Release(IWICBitmapFrameEncode *iface) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("%p -> %u\n", iface, ref); + + if (!ref) + { + IWICBitmapEncoder_Release(&This->encoder->IWICBitmapEncoder_iface); + HeapFree(GetProcessHeap(), 0, This->image_data); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI GifFrameEncode_Initialize(IWICBitmapFrameEncode *iface, IPropertyBag2 *options) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%p\n", iface, options); + + EnterCriticalSection(&This->encoder->lock); + + if (!This->initialized) + { + This->initialized = TRUE; + hr = S_OK; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + + return hr; +} + +static HRESULT WINAPI GifFrameEncode_SetSize(IWICBitmapFrameEncode *iface, UINT width, UINT height) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%u,%u\n", iface, width, height); + + if (!width || !height) return E_INVALIDARG; + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized) + { + HeapFree(GetProcessHeap(), 0, This->image_data); + + This->image_data = HeapAlloc(GetProcessHeap(), 0, width * height); + if (This->image_data) + { + This->width = width; + This->height = height; + hr = S_OK; + } + else + hr = E_OUTOFMEMORY; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + + return hr; +} + +static HRESULT WINAPI GifFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, double xres, double yres) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%f,%f\n", iface, xres, yres); + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized) + { + This->xres = xres; + This->yres = yres; + hr = S_OK; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + + return hr; +} + +static HRESULT WINAPI GifFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, WICPixelFormatGUID *format) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%s\n", iface, debugstr_guid(format)); + + if (!format) return E_INVALIDARG; + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized) + { + *format = GUID_WICPixelFormat8bppIndexed; + hr = S_OK; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + + return hr; +} + +static HRESULT WINAPI GifFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, UINT count, IWICColorContext **context) +{ + FIXME("%p,%u,%p: stub\n", iface, count, context); + return E_NOTIMPL; +} + +static HRESULT WINAPI GifFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, IWICPalette *palette) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%p\n", iface, palette); + + if (!palette) return E_INVALIDARG; + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized) + hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); + else + hr = WINCODEC_ERR_NOTINITIALIZED; + + LeaveCriticalSection(&This->encoder->lock); + return hr; +} + +static HRESULT WINAPI GifFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, IWICBitmapSource *thumbnail) +{ + FIXME("%p,%p: stub\n", iface, thumbnail); + return E_NOTIMPL; +} + +static HRESULT WINAPI GifFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, UINT lines, UINT stride, UINT size, BYTE *pixels) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%u,%u,%u,%p\n", iface, lines, stride, size, pixels); + + if (!pixels) return E_INVALIDARG; + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized && This->image_data) + { + if (This->lines + lines <= This->height) + { + UINT i; + BYTE *src, *dst; + + src = pixels; + dst = This->image_data + This->lines * This->width; + + for (i = 0; i < lines; i++) + { + memcpy(dst, src, This->width); + src += stride; + dst += This->width; + } + + This->lines += lines; + hr = S_OK; + } + else + hr = E_INVALIDARG; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + return hr; +} + +static HRESULT WINAPI GifFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, IWICBitmapSource *source, WICRect *rc) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p,%p,%p\n", iface, source, rc); + + if (!source) return E_INVALIDARG; + + EnterCriticalSection(&This->encoder->lock); + + if (This->initialized) + { + const GUID *format = &GUID_WICPixelFormat8bppIndexed; + + hr = configure_write_source(iface, source, rc, format, + This->width, This->height, This->xres, This->yres); + if (hr == S_OK) + hr = write_source(iface, source, rc, format, 8, This->width, This->height); + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + return hr; +} + +#define LZW_DICT_SIZE (1 << 12) + +struct lzw_dict +{ + short prefix[LZW_DICT_SIZE]; + unsigned char suffix[LZW_DICT_SIZE]; +}; + +struct lzw_state +{ + struct lzw_dict dict; + short init_code_bits, code_bits, next_code, clear_code, eof_code; + unsigned bits_buf; + int bits_count; + int (*user_write_data)(void *user_ptr, void *data, int length); + void *user_ptr; +}; + +struct input_stream +{ + unsigned len; + const BYTE *in; +}; + +struct output_stream +{ + struct + { + unsigned char len; + char data[255]; + } gif_block; + IStream *out; +}; + +static int lzw_output_code(struct lzw_state *state, short code) +{ + state->bits_buf |= code << state->bits_count; + state->bits_count += state->code_bits; + + while (state->bits_count >= 8) + { + unsigned char byte = (unsigned char)state->bits_buf; + if (state->user_write_data(state->user_ptr, &byte, 1) != 1) + return 0; + state->bits_buf >>= 8; + state->bits_count -= 8; + } + + return 1; +} + +static inline int lzw_output_clear_code(struct lzw_state *state) +{ + return lzw_output_code(state, state->clear_code); +} + +static inline int lzw_output_eof_code(struct lzw_state *state) +{ + return lzw_output_code(state, state->eof_code); +} + +static int lzw_flush_bits(struct lzw_state *state) +{ + unsigned char byte; + + while (state->bits_count >= 8) + { + byte = (unsigned char)state->bits_buf; + if (state->user_write_data(state->user_ptr, &byte, 1) != 1) + return 0; + state->bits_buf >>= 8; + state->bits_count -= 8; + } + + if (state->bits_count) + { + static const char mask[8] = { 0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f }; + + byte = (unsigned char)state->bits_buf & mask[state->bits_count]; + if (state->user_write_data(state->user_ptr, &byte, 1) != 1) + return 0; + } + + state->bits_buf = 0; + state->bits_count = 0; + + return 1; +} + +static void lzw_dict_reset(struct lzw_state *state) +{ + int i; + + state->code_bits = state->init_code_bits + 1; + state->next_code = (1 << state->init_code_bits) + 2; + + for(i = 0; i < LZW_DICT_SIZE; i++) + { + state->dict.prefix[i] = 1 << 12; /* impossible LZW code value */ + state->dict.suffix[i] = 0; + } +} + +static void lzw_state_init(struct lzw_state *state, short init_code_bits, void *user_write_data, void *user_ptr) +{ + state->init_code_bits = init_code_bits; + state->clear_code = 1 << init_code_bits; + state->eof_code = state->clear_code + 1; + state->bits_buf = 0; + state->bits_count = 0; + state->user_write_data = user_write_data; + state->user_ptr = user_ptr; + + lzw_dict_reset(state); +} + +static int lzw_dict_add(struct lzw_state *state, short prefix, unsigned char suffix) +{ + if (state->next_code < LZW_DICT_SIZE) + { + state->dict.prefix[state->next_code] = prefix; + state->dict.suffix[state->next_code] = suffix; + + if ((state->next_code & (state->next_code - 1)) == 0) + state->code_bits++; + + state->next_code++; + return state->next_code; + } + + return -1; +} + +static short lzw_dict_lookup(const struct lzw_state *state, short prefix, unsigned char suffix) +{ + short i; + + for (i = 0; i < state->next_code; i++) + { + if (state->dict.prefix[i] == prefix && state->dict.suffix[i] == suffix) + return i; + } + + return -1; +} + +static inline int write_byte(struct output_stream *out, char byte) +{ + if (out->gif_block.len == 255) + { + if (IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block), NULL) != S_OK) + return 0; + + out->gif_block.len = 0; + } + + out->gif_block.data[out->gif_block.len++] = byte; + + return 1; +} + +static int write_data(void *user_ptr, void *user_data, int length) +{ + unsigned char *data = user_data; + struct output_stream *out = user_ptr; + int len = length; + + while (len-- > 0) + { + if (!write_byte(out, *data++)) return 0; + } + + return length; +} + +static int flush_output_data(void *user_ptr) +{ + struct output_stream *out = user_ptr; + + if (out->gif_block.len) + { + if (IStream_Write(out->out, &out->gif_block, out->gif_block.len + sizeof(out->gif_block.len), NULL) != S_OK) + return 0; + } + + /* write GIF block terminator */ + out->gif_block.len = 0; + return IStream_Write(out->out, &out->gif_block, sizeof(out->gif_block.len), NULL) == S_OK; +} + +static inline int read_byte(struct input_stream *in, unsigned char *byte) +{ + if (in->len) + { + in->len--; + *byte = *in->in++; + return 1; + } + + return 0; +} + +static HRESULT gif_compress(IStream *out_stream, const BYTE *in_data, ULONG in_size) +{ + struct input_stream in; + struct output_stream out; + struct lzw_state state; + short init_code_bits, prefix, code; + unsigned char suffix; + + in.in = in_data; + in.len = in_size; + + out.gif_block.len = 0; + out.out = out_stream; + + init_code_bits = suffix = 8; + if (IStream_Write(out.out, &suffix, sizeof(suffix), NULL) != S_OK) + return E_FAIL; + + lzw_state_init(&state, init_code_bits, write_data, &out); + + if (!lzw_output_clear_code(&state)) + return E_FAIL; + + if (read_byte(&in, &suffix)) + { + prefix = suffix; + + while (read_byte(&in, &suffix)) + { + code = lzw_dict_lookup(&state, prefix, suffix); + if (code == -1) + { + if (!lzw_output_code(&state, prefix)) + return E_FAIL; + + if (lzw_dict_add(&state, prefix, suffix) == -1) + { + if (!lzw_output_clear_code(&state)) + return E_FAIL; + lzw_dict_reset(&state); + } + + prefix = suffix; + } + else + prefix = code; + } + + if (!lzw_output_code(&state, prefix)) + return E_FAIL; + if (!lzw_output_eof_code(&state)) + return E_FAIL; + if (!lzw_flush_bits(&state)) + return E_FAIL; + } + + return flush_output_data(&out) ? S_OK : E_FAIL; +} + +static HRESULT WINAPI GifFrameEncode_Commit(IWICBitmapFrameEncode *iface) +{ + GifFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("%p\n", iface); + + EnterCriticalSection(&This->encoder->lock); + + if (This->image_data && This->lines == This->height && !This->committed) + { + BYTE gif_palette[256][3]; + + hr = S_OK; + + if (!This->encoder->info_written) + { + struct logical_screen_descriptor lsd; + + /* Logical Screen Descriptor */ + memcpy(lsd.signature, "GIF89a", 6); + lsd.width = This->width; + lsd.height = This->height; + lsd.packed = 0; + if (This->encoder->colors) + lsd.packed |= 0x80; /* global color table flag */ + lsd.packed |= 0x07 << 4; /* color resolution */ + lsd.packed |= 0x07; /* global color table size */ + lsd.background_color_index = 0; /* FIXME */ + lsd.pixel_aspect_ratio = 0; + hr = IStream_Write(This->encoder->stream, &lsd, sizeof(lsd), NULL); + if (hr == S_OK && This->encoder->colors) + { + UINT i; + + /* Global Color Table */ + memset(gif_palette, 0, sizeof(gif_palette)); + for (i = 0; i < This->encoder->colors; i++) + { + gif_palette[i][0] = (This->encoder->palette[i] >> 16) & 0xff; + gif_palette[i][1] = (This->encoder->palette[i] >> 8) & 0xff; + gif_palette[i][2] = This->encoder->palette[i] & 0xff; + } + hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); + } + + /* FIXME: write GCE, APE, etc. GIF extensions */ + + if (hr == S_OK) + This->encoder->info_written = TRUE; + } + + if (hr == S_OK) + { + char image_separator = 0x2c; + + hr = IStream_Write(This->encoder->stream, &image_separator, sizeof(image_separator), NULL); + if (hr == S_OK) + { + struct image_descriptor imd; + + /* Image Descriptor */ + imd.left = 0; + imd.top = 0; + imd.width = This->width; + imd.height = This->height; + imd.packed = 0; + if (This->colors) + { + imd.packed |= 0x80; /* local color table flag */ + imd.packed |= 0x07; /* local color table size */ + } + /* FIXME: interlace flag */ + hr = IStream_Write(This->encoder->stream, &imd, sizeof(imd), NULL); + if (hr == S_OK && This->colors) + { + UINT i; + + /* Local Color Table */ + memset(gif_palette, 0, sizeof(gif_palette)); + for (i = 0; i < This->colors; i++) + { + gif_palette[i][0] = (This->palette[i] >> 16) & 0xff; + gif_palette[i][1] = (This->palette[i] >> 8) & 0xff; + gif_palette[i][2] = This->palette[i] & 0xff; + } + hr = IStream_Write(This->encoder->stream, gif_palette, sizeof(gif_palette), NULL); + if (hr == S_OK) + { + /* Image Data */ + hr = gif_compress(This->encoder->stream, This->image_data, This->width * This->height); + if (hr == S_OK) + This->committed = TRUE; + } + } + } + } + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->encoder->lock); + return hr; +} + +static HRESULT WINAPI GifFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, IWICMetadataQueryWriter **writer) +{ + FIXME("%p, %p: stub\n", iface, writer); + return E_NOTIMPL; +} + +static const IWICBitmapFrameEncodeVtbl GifFrameEncode_Vtbl = +{ + GifFrameEncode_QueryInterface, + GifFrameEncode_AddRef, + GifFrameEncode_Release, + GifFrameEncode_Initialize, + GifFrameEncode_SetSize, + GifFrameEncode_SetResolution, + GifFrameEncode_SetPixelFormat, + GifFrameEncode_SetColorContexts, + GifFrameEncode_SetPalette, + GifFrameEncode_SetThumbnail, + GifFrameEncode_WritePixels, + GifFrameEncode_WriteSource, + GifFrameEncode_Commit, + GifFrameEncode_GetMetadataQueryWriter +}; + +static HRESULT WINAPI GifEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, void **ppv) +{ + TRACE("%p,%s,%p\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapEncoder, iid)) + { + IWICBitmapEncoder_AddRef(iface); + *ppv = iface; + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI GifEncoder_AddRef(IWICBitmapEncoder *iface) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("%p -> %u\n", iface, ref); + return ref; +} + +static ULONG WINAPI GifEncoder_Release(IWICBitmapEncoder *iface) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("%p -> %u\n", iface, ref); + + if (!ref) + { + if (This->stream) IStream_Release(This->stream); + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + HeapFree(GetProcessHeap(), 0, This); + } + + return ref; +} + +static HRESULT WINAPI GifEncoder_Initialize(IWICBitmapEncoder *iface, IStream *stream, WICBitmapEncoderCacheOption option) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("%p,%p,%#x\n", iface, stream, option); + + if (!stream) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->initialized) + { + IStream_AddRef(stream); + This->stream = stream; + This->initialized = TRUE; + hr = S_OK; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI GifEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format) +{ + if (!format) return E_INVALIDARG; + + *format = GUID_ContainerFormatGif; + return S_OK; +} + +static HRESULT WINAPI GifEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) +{ + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICGifEncoder, &comp_info); + if (hr == S_OK) + { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; +} + +static HRESULT WINAPI GifEncoder_SetColorContexts(IWICBitmapEncoder *iface, UINT count, IWICColorContext **context) +{ + FIXME("%p,%u,%p: stub\n", iface, count, context); + return E_NOTIMPL; +} + +static HRESULT WINAPI GifEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("%p,%p\n", iface, palette); + + if (!palette) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (This->initialized) + hr = IWICPalette_GetColors(palette, 256, This->palette, &This->colors); + else + hr = WINCODEC_ERR_NOTINITIALIZED; + + LeaveCriticalSection(&This->lock); + return hr; +} + +static HRESULT WINAPI GifEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *thumbnail) +{ + TRACE("%p,%p\n", iface, thumbnail); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI GifEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *preview) +{ + TRACE("%p,%p\n", iface, preview); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI GifEncoder_CreateNewFrame(IWICBitmapEncoder *iface, IWICBitmapFrameEncode **frame, IPropertyBag2 **options) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("%p,%p,%p\n", iface, frame, options); + + if (!frame) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (This->initialized && !This->committed) + { + GifFrameEncode *ret = HeapAlloc(GetProcessHeap(), 0, sizeof(*ret)); + if (ret) + { + This->n_frames++; + + ret->IWICBitmapFrameEncode_iface.lpVtbl = &GifFrameEncode_Vtbl; + ret->ref = 1; + ret->encoder = This; + ret->initialized = FALSE; + ret->interlace = FALSE; /* FIXME: read from the properties */ + ret->committed = FALSE; + ret->width = 0; + ret->height = 0; + ret->lines = 0; + ret->xres = 0.0; + ret->yres = 0.0; + ret->colors = 0; + ret->image_data = NULL; + IWICBitmapEncoder_AddRef(iface); + *frame = &ret->IWICBitmapFrameEncode_iface; + + hr = S_OK; + + if (options) + { + hr = CreatePropertyBag2(NULL, 0, options); + if (hr != S_OK) + { + IWICBitmapFrameEncode_Release(*frame); + *frame = NULL; + } + } + } + else + hr = E_OUTOFMEMORY; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->lock); + + return hr; + +} + +static HRESULT WINAPI GifEncoder_Commit(IWICBitmapEncoder *iface) +{ + GifEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("%p\n", iface); + + EnterCriticalSection(&This->lock); + + if (This->initialized && !This->committed) + { + char gif_trailer = 0x3b; + + /* FIXME: write text, comment GIF extensions */ + + hr = IStream_Write(This->stream, &gif_trailer, sizeof(gif_trailer), NULL); + if (hr == S_OK) + This->committed = TRUE; + } + else + hr = WINCODEC_ERR_WRONGSTATE; + + LeaveCriticalSection(&This->lock); + return hr; +} + +static HRESULT WINAPI GifEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, IWICMetadataQueryWriter **writer) +{ + FIXME("%p,%p: stub\n", iface, writer); + return E_NOTIMPL; +} + +static const IWICBitmapEncoderVtbl GifEncoder_Vtbl = +{ + GifEncoder_QueryInterface, + GifEncoder_AddRef, + GifEncoder_Release, + GifEncoder_Initialize, + GifEncoder_GetContainerFormat, + GifEncoder_GetEncoderInfo, + GifEncoder_SetColorContexts, + GifEncoder_SetPalette, + GifEncoder_SetThumbnail, + GifEncoder_SetPreview, + GifEncoder_CreateNewFrame, + GifEncoder_Commit, + GifEncoder_GetMetadataQueryWriter +}; + +HRESULT GifEncoder_CreateInstance(REFIID iid, void **ppv) +{ + GifEncoder *This; + HRESULT ret; + + TRACE("%s,%p\n", debugstr_guid(iid), ppv); + + *ppv = NULL; + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + + This->IWICBitmapEncoder_iface.lpVtbl = &GifEncoder_Vtbl; + This->ref = 1; + This->stream = NULL; + InitializeCriticalSection(&This->lock); + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": GifEncoder.lock"); + This->initialized = FALSE; + This->info_written = FALSE; + This->committed = FALSE; + This->n_frames = 0; + This->colors = 0; + + ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); + IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); + + return ret; +} diff --git a/dll/win32/windowscodecs/icnsformat.c b/dll/win32/windowscodecs/icnsformat.c index e7d6f96226d..aa9640417f5 100644 --- a/dll/win32/windowscodecs/icnsformat.c +++ b/dll/win32/windowscodecs/icnsformat.c @@ -16,6 +16,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" +#include "wine/port.h" + +#include + #ifdef HAVE_APPLICATIONSERVICES_APPLICATIONSERVICES_H #define GetCurrentProcess GetCurrentProcess_Mac #define GetCurrentThread GetCurrentThread_Mac @@ -73,8 +78,19 @@ #undef DPRINTF #endif +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.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 @@ -601,9 +617,12 @@ static HRESULT WINAPI IcnsEncoder_CreateNewFrame(IWICBitmapEncoder *iface, goto end; } - hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions); - if (FAILED(hr)) - goto end; + if (ppIEncoderOptions) + { + hr = CreatePropertyBag2(NULL, 0, ppIEncoderOptions); + if (FAILED(hr)) + goto end; + } frameEncode = HeapAlloc(GetProcessHeap(), 0, sizeof(IcnsFrameEncode)); if (frameEncode == NULL) diff --git a/dll/win32/windowscodecs/icoformat.c b/dll/win32/windowscodecs/icoformat.c index 86629568fd9..1b1c79291b0 100644 --- a/dll/win32/windowscodecs/icoformat.c +++ b/dll/win32/windowscodecs/icoformat.c @@ -16,9 +16,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "objbase.h" + #include "wincodecs_private.h" -#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +#include "pshpack1.h" typedef struct { BYTE bWidth; @@ -38,7 +53,7 @@ typedef struct WORD idCount; } ICONHEADER; -#include +#include "poppack.h" typedef struct { IWICBitmapDecoder IWICBitmapDecoder_iface; diff --git a/dll/win32/windowscodecs/imgfactory.c b/dll/win32/windowscodecs/imgfactory.c index 623265762ae..88ce00e651a 100644 --- a/dll/win32/windowscodecs/imgfactory.c +++ b/dll/win32/windowscodecs/imgfactory.c @@ -17,8 +17,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "objbase.h" +#include "shellapi.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct { IWICComponentFactory IWICComponentFactory_iface; LONG ref; @@ -104,22 +120,23 @@ static HRESULT WINAPI ComponentFactory_CreateDecoderFromFilename( return hr; } -static IWICBitmapDecoder *find_decoder(IStream *pIStream, const GUID *pguidVendor, - WICDecodeOptions metadataOptions) +static HRESULT find_decoder(IStream *pIStream, const GUID *pguidVendor, + WICDecodeOptions metadataOptions, IWICBitmapDecoder **decoder) { IEnumUnknown *enumdecoders; IUnknown *unkdecoderinfo; IWICBitmapDecoderInfo *decoderinfo; - IWICBitmapDecoder *decoder = NULL; GUID vendor; HRESULT res; ULONG num_fetched; BOOL matches; - res = CreateComponentEnumerator(WICDecoder, WICComponentEnumerateDefault, &enumdecoders); - if (FAILED(res)) return NULL; + *decoder = NULL; - while (!decoder) + res = CreateComponentEnumerator(WICDecoder, WICComponentEnumerateDefault, &enumdecoders); + if (FAILED(res)) return res; + + while (!*decoder) { res = IEnumUnknown_Next(enumdecoders, 1, &unkdecoderinfo, &num_fetched); @@ -144,18 +161,21 @@ static IWICBitmapDecoder *find_decoder(IStream *pIStream, const GUID *pguidVendo if (SUCCEEDED(res) && matches) { - res = IWICBitmapDecoderInfo_CreateInstance(decoderinfo, &decoder); + res = IWICBitmapDecoderInfo_CreateInstance(decoderinfo, decoder); /* FIXME: should use QueryCapability to choose a decoder */ if (SUCCEEDED(res)) { - res = IWICBitmapDecoder_Initialize(decoder, pIStream, metadataOptions); + res = IWICBitmapDecoder_Initialize(*decoder, pIStream, metadataOptions); if (FAILED(res)) { - IWICBitmapDecoder_Release(decoder); - decoder = NULL; + IWICBitmapDecoder_Release(*decoder); + IWICBitmapDecoderInfo_Release(decoderinfo); + IUnknown_Release(unkdecoderinfo); + *decoder = NULL; + return res; } } } @@ -171,7 +191,7 @@ static IWICBitmapDecoder *find_decoder(IStream *pIStream, const GUID *pguidVendo IEnumUnknown_Release(enumdecoders); - return decoder; + return WINCODEC_ERR_COMPONENTNOTFOUND; } static HRESULT WINAPI ComponentFactory_CreateDecoderFromStream( @@ -185,9 +205,9 @@ static HRESULT WINAPI ComponentFactory_CreateDecoderFromStream( metadataOptions, ppIDecoder); if (pguidVendor) - decoder = find_decoder(pIStream, pguidVendor, metadataOptions); + res = find_decoder(pIStream, pguidVendor, metadataOptions, &decoder); if (!decoder) - decoder = find_decoder(pIStream, NULL, metadataOptions); + res = find_decoder(pIStream, NULL, metadataOptions, &decoder); if (decoder) { @@ -202,17 +222,17 @@ static HRESULT WINAPI ComponentFactory_CreateDecoderFromStream( BYTE data[4]; ULONG bytesread; - WARN("failed to load from a stream\n"); + WARN("failed to load from a stream %#x\n", res); seek.QuadPart = 0; - res = IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL); - if (SUCCEEDED(res)) - res = IStream_Read(pIStream, data, 4, &bytesread); - if (SUCCEEDED(res)) - WARN("first %i bytes of stream=%x %x %x %x\n", bytesread, data[0], data[1], data[2], data[3]); + if (IStream_Seek(pIStream, seek, STREAM_SEEK_SET, NULL) == S_OK) + { + if (IStream_Read(pIStream, data, 4, &bytesread) == S_OK) + WARN("first %i bytes of stream=%x %x %x %x\n", bytesread, data[0], data[1], data[2], data[3]); + } } *ppIDecoder = NULL; - return WINCODEC_ERR_COMPONENTNOTFOUND; + return res; } } @@ -579,12 +599,36 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFacto UINT width, UINT height, REFWICPixelFormatGUID format, UINT stride, UINT size, BYTE *buffer, IWICBitmap **bitmap) { + HRESULT hr; + TRACE("(%p,%u,%u,%s,%u,%u,%p,%p\n", iface, width, height, debugstr_guid(format), stride, size, buffer, bitmap); if (!stride || !size || !buffer || !bitmap) return E_INVALIDARG; - return BitmapImpl_Create(width, height, stride, size, buffer, format, WICBitmapCacheOnLoad, bitmap); + hr = BitmapImpl_Create(width, height, stride, size, NULL, format, WICBitmapCacheOnLoad, bitmap); + if (SUCCEEDED(hr)) + { + IWICBitmapLock *lock; + + hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); + if (SUCCEEDED(hr)) + { + UINT buffersize; + BYTE *data; + + IWICBitmapLock_GetDataPointer(lock, &buffersize, &data); + memcpy(data, buffer, buffersize); + + IWICBitmapLock_Release(lock); + } + else + { + IWICBitmap_Release(*bitmap); + *bitmap = NULL; + } + } + return hr; } static BOOL get_16bpp_format(HBITMAP hbm, WICPixelFormatGUID *format) @@ -1160,3 +1204,50 @@ HRESULT ComponentFactory_CreateInstance(REFIID iid, void** ppv) return ret; } + +HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, UINT stride, + UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap) +{ + DWORD access; + void *buffer; + HRESULT hr; + + TRACE("%u,%u,%s,%p,%u,%#x,%#x,%p\n", width, height, debugstr_guid(format), + section, stride, offset, wicaccess, bitmap); + + if (!width || !height || !section || !bitmap) return E_INVALIDARG; + + switch (wicaccess) + { + case WICSectionAccessLevelReadWrite: + access = FILE_MAP_READ | FILE_MAP_WRITE; + break; + + case WICSectionAccessLevelRead: + access = FILE_MAP_READ; + break; + + default: + FIXME("unsupported access %#x\n", wicaccess); + return E_INVALIDARG; + } + + buffer = MapViewOfFile(section, access, 0, offset, 0); + if (!buffer) return HRESULT_FROM_WIN32(GetLastError()); + + hr = BitmapImpl_Create(width, height, stride, 0, buffer, format, WICBitmapCacheOnLoad, bitmap); + if (FAILED(hr)) UnmapViewOfFile(buffer); + return hr; +} + +HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, + UINT stride, UINT offset, IWICBitmap **bitmap) +{ + TRACE("%u,%u,%s,%p,%u,%u,%p\n", width, height, debugstr_guid(format), + section, stride, offset, bitmap); + + return WICCreateBitmapFromSectionEx(width, height, format, section, + stride, offset, WICSectionAccessLevelRead, bitmap); +} diff --git a/dll/win32/windowscodecs/info.c b/dll/win32/windowscodecs/info.c index 63cdc07dbca..22a7b83e2c2 100644 --- a/dll/win32/windowscodecs/info.c +++ b/dll/win32/windowscodecs/info.c @@ -17,9 +17,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "objbase.h" + #include "wincodecs_private.h" -#include +#include "wine/debug.h" +#include "wine/unicode.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); 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}; @@ -853,8 +868,12 @@ static HRESULT WINAPI BitmapEncoderInfo_GetMimeTypes(IWICBitmapEncoderInfo *ifac 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; + BitmapEncoderInfo *This = impl_from_IWICBitmapEncoderInfo(iface); + + TRACE("(%p,%u,%p,%p)\n", iface, cchFileExtensions, wzFileExtensions, pcchActual); + + return ComponentInfo_GetStringValue(This->classkey, fileextensions_valuename, + cchFileExtensions, wzFileExtensions, pcchActual); } static HRESULT WINAPI BitmapEncoderInfo_DoesSupportAnimation(IWICBitmapEncoderInfo *iface, @@ -2265,6 +2284,12 @@ HRESULT CreateComponentEnumerator(DWORD componentTypes, DWORD options, IEnumUnkn return hr; } +static BOOL is_1bpp_format(const WICPixelFormatGUID *format) +{ + return IsEqualGUID(format, &GUID_WICPixelFormatBlackWhite) || + IsEqualGUID(format, &GUID_WICPixelFormat1bppIndexed); +} + HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst) { HRESULT res; @@ -2277,10 +2302,12 @@ HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitma BOOL canconvert; ULONG num_fetched; + TRACE("%s,%p,%p\n", debugstr_guid(dstFormat), pISrc, ppIDst); + res = IWICBitmapSource_GetPixelFormat(pISrc, &srcFormat); if (FAILED(res)) return res; - if (IsEqualGUID(&srcFormat, dstFormat)) + if (IsEqualGUID(&srcFormat, dstFormat) || (is_1bpp_format(&srcFormat) && is_1bpp_format(dstFormat))) { IWICBitmapSource_AddRef(pISrc); *ppIDst = pISrc; @@ -2317,7 +2344,7 @@ HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitma if (SUCCEEDED(res) && canconvert) res = IWICFormatConverter_Initialize(converter, pISrc, dstFormat, WICBitmapDitherTypeNone, - NULL, 0.0, WICBitmapPaletteTypeCustom); + NULL, 0.0, WICBitmapPaletteTypeMedianCut); if (FAILED(res) || !canconvert) { diff --git a/dll/win32/windowscodecs/jpegformat.c b/dll/win32/windowscodecs/jpegformat.c index cfb84c36aaf..0069bdfd899 100644 --- a/dll/win32/windowscodecs/jpegformat.c +++ b/dll/win32/windowscodecs/jpegformat.c @@ -16,11 +16,16 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wincodecs_private.h" +#include "config.h" +#include "wine/port.h" #ifdef HAVE_UNISTD_H # include #endif +#include +#include +#include +#include #ifdef SONAME_LIBJPEG /* This is a hack, so jpeglib.h does not redefine INT32 and the like*/ @@ -37,6 +42,19 @@ #undef boolean #endif +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" +#include "wine/library.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + #ifdef SONAME_LIBJPEG WINE_DECLARE_DEBUG_CHANNEL(jpeg); @@ -405,10 +423,14 @@ static HRESULT WINAPI JpegDecoder_CopyPalette(IWICBitmapDecoder *iface, } static HRESULT WINAPI JpegDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, - IWICMetadataQueryReader **ppIMetadataQueryReader) + IWICMetadataQueryReader **reader) { - FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); - return E_NOTIMPL; + FIXME("(%p,%p): stub\n", iface, reader); + + if (!reader) return E_INVALIDARG; + + *reader = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; } static HRESULT WINAPI JpegDecoder_GetPreview(IWICBitmapDecoder *iface, @@ -662,9 +684,15 @@ static HRESULT WINAPI JpegDecoder_Frame_CopyPixels(IWICBitmapFrameDecode *iface, } if (This->cinfo.out_color_space == JCS_CMYK && This->cinfo.saw_Adobe_marker) + { + DWORD *pDwordData = (DWORD*) (This->image_data + stride * first_scanline); + DWORD *pDwordDataEnd = (DWORD*) (This->image_data + This->cinfo.output_scanline * stride); + /* Adobe JPEG's have inverted CMYK data. */ - for (i=0; iimage_data[i] ^= 0xff; + while(pDwordData < pDwordDataEnd) + *pDwordData++ ^= 0xffffffff; + } + } LeaveCriticalSection(&This->lock); @@ -1375,11 +1403,22 @@ static HRESULT WINAPI JpegEncoder_GetContainerFormat(IWICBitmapEncoder *iface, return E_NOTIMPL; } -static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, - IWICBitmapEncoderInfo **ppIEncoderInfo) +static HRESULT WINAPI JpegEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) { - FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo); - return E_NOTIMPL; + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICJpegEncoder, &comp_info); + if (hr == S_OK) + { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; } static HRESULT WINAPI JpegEncoder_SetColorContexts(IWICBitmapEncoder *iface, @@ -1422,7 +1461,15 @@ static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface, { JpegEncoder *This = impl_from_IWICBitmapEncoder(iface); HRESULT hr; - PROPBAG2 opts[6] = {{0}}; + static const PROPBAG2 opts[6] = + { + { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszImageQuality }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszBitmapTransform }, + { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszLuminance }, + { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)wszChrominance }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszJpegYCrCbSubsampling }, + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszSuppressApp0 }, + }; TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -1440,30 +1487,14 @@ static HRESULT WINAPI JpegEncoder_CreateNewFrame(IWICBitmapEncoder *iface, return WINCODEC_ERR_NOTINITIALIZED; } - opts[0].pstrName = (LPOLESTR)wszImageQuality; - opts[0].vt = VT_R4; - opts[0].dwType = PROPBAG2_TYPE_DATA; - opts[1].pstrName = (LPOLESTR)wszBitmapTransform; - opts[1].vt = VT_UI1; - opts[1].dwType = PROPBAG2_TYPE_DATA; - opts[2].pstrName = (LPOLESTR)wszLuminance; - opts[2].vt = VT_I4|VT_ARRAY; - opts[2].dwType = PROPBAG2_TYPE_DATA; - opts[3].pstrName = (LPOLESTR)wszChrominance; - opts[3].vt = VT_I4|VT_ARRAY; - opts[3].dwType = PROPBAG2_TYPE_DATA; - opts[4].pstrName = (LPOLESTR)wszJpegYCrCbSubsampling; - opts[4].vt = VT_UI1; - opts[4].dwType = PROPBAG2_TYPE_DATA; - opts[5].pstrName = (LPOLESTR)wszSuppressApp0; - opts[5].vt = VT_BOOL; - opts[5].dwType = PROPBAG2_TYPE_DATA; - - hr = CreatePropertyBag2(opts, 6, ppIEncoderOptions); - if (FAILED(hr)) + if (ppIEncoderOptions) { - LeaveCriticalSection(&This->lock); - return hr; + hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); + if (FAILED(hr)) + { + LeaveCriticalSection(&This->lock); + return hr; + } } This->frame_count = 1; diff --git a/dll/win32/windowscodecs/main.c b/dll/win32/windowscodecs/main.c index c53e330a218..3bed56536c2 100644 --- a/dll/win32/windowscodecs/main.c +++ b/dll/win32/windowscodecs/main.c @@ -16,8 +16,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ + +#define COBJMACROS +#include "config.h" + +#include + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.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) diff --git a/dll/win32/windowscodecs/metadatahandler.c b/dll/win32/windowscodecs/metadatahandler.c index dff5ed3c7f6..3d48924a444 100644 --- a/dll/win32/windowscodecs/metadatahandler.c +++ b/dll/win32/windowscodecs/metadatahandler.c @@ -17,11 +17,25 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include +#include + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "wine/winternl.h" +#include "objbase.h" +#include "propvarutil.h" + #include "wincodecs_private.h" -#include -#include -#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); typedef struct MetadataHandler { IWICMetadataWriter IWICMetadataWriter_iface; @@ -704,7 +718,7 @@ static int tag_to_vt(SHORT tag) static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, MetadataItem *item, BOOL native_byte_order) { - ULONG count, value, i, bytesread; + ULONG count, value, i; SHORT type; LARGE_INTEGER pos; HRESULT hr; @@ -746,7 +760,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, item->value.vt |= VT_VECTOR; item->value.u.caub.cElems = count; - item->value.u.caub.pElems = HeapAlloc(GetProcessHeap(), 0, count); + item->value.u.caub.pElems = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count); if (!item->value.u.caub.pElems) return E_OUTOFMEMORY; pos.QuadPart = value; @@ -756,9 +770,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.caub.pElems); return hr; } - hr = IStream_Read(input, item->value.u.caub.pElems, count, &bytesread); - if (bytesread != count) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.caub.pElems, count, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.caub.pElems); return hr; @@ -791,7 +804,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, item->value.vt |= VT_VECTOR; item->value.u.caui.cElems = count; - item->value.u.caui.pElems = HeapAlloc(GetProcessHeap(), 0, count * 2); + item->value.u.caui.pElems = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * 2); if (!item->value.u.caui.pElems) return E_OUTOFMEMORY; pos.QuadPart = value; @@ -801,9 +814,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.caui.pElems); return hr; } - hr = IStream_Read(input, item->value.u.caui.pElems, count * 2, &bytesread); - if (bytesread != count * 2) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.caui.pElems, count * 2, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.caui.pElems); return hr; @@ -824,7 +836,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, item->value.vt |= VT_VECTOR; item->value.u.caul.cElems = count; - item->value.u.caul.pElems = HeapAlloc(GetProcessHeap(), 0, count * 4); + item->value.u.caul.pElems = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * 4); if (!item->value.u.caul.pElems) return E_OUTOFMEMORY; pos.QuadPart = value; @@ -834,9 +846,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.caul.pElems); return hr; } - hr = IStream_Read(input, item->value.u.caul.pElems, count * 4, &bytesread); - if (bytesread != count * 4) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.caul.pElems, count * 4, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.caul.pElems); return hr; @@ -862,8 +873,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, hr = IStream_Seek(input, pos, SEEK_SET, NULL); if (FAILED(hr)) return hr; - hr = IStream_Read(input, &ull, sizeof(ull), &bytesread); - if (bytesread != sizeof(ull)) hr = E_FAIL; + hr = IStream_Read(input, &ull, sizeof(ull), NULL); if (hr != S_OK) return hr; item->value.u.uhVal.QuadPart = ull; @@ -881,7 +891,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, { item->value.vt |= VT_VECTOR; item->value.u.cauh.cElems = count; - item->value.u.cauh.pElems = HeapAlloc(GetProcessHeap(), 0, count * 8); + item->value.u.cauh.pElems = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count * 8); if (!item->value.u.cauh.pElems) return E_OUTOFMEMORY; pos.QuadPart = value; @@ -891,9 +901,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.cauh.pElems); return hr; } - hr = IStream_Read(input, item->value.u.cauh.pElems, count * 8, &bytesread); - if (bytesread != count * 8) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.cauh.pElems, count * 8, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.cauh.pElems); return hr; @@ -911,7 +920,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, } break; case IFD_ASCII: - item->value.u.pszVal = HeapAlloc(GetProcessHeap(), 0, count + 1); + item->value.u.pszVal = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count + 1); if (!item->value.u.pszVal) return E_OUTOFMEMORY; if (count <= 4) @@ -929,9 +938,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.pszVal); return hr; } - hr = IStream_Read(input, item->value.u.pszVal, count, &bytesread); - if (bytesread != count) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.pszVal, count, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.pszVal); return hr; @@ -946,7 +954,7 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, break; } - item->value.u.blob.pBlobData = HeapAlloc(GetProcessHeap(), 0, count); + item->value.u.blob.pBlobData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count); if (!item->value.u.blob.pBlobData) return E_OUTOFMEMORY; item->value.u.blob.cbSize = count; @@ -965,9 +973,8 @@ static HRESULT load_IFD_entry(IStream *input, const struct IFD_entry *entry, HeapFree(GetProcessHeap(), 0, item->value.u.blob.pBlobData); return hr; } - hr = IStream_Read(input, item->value.u.blob.pBlobData, count, &bytesread); - if (bytesread != count) hr = E_FAIL; - if (hr != S_OK) + hr = IStream_Read(input, item->value.u.blob.pBlobData, count, NULL); + if (FAILED(hr)) { HeapFree(GetProcessHeap(), 0, item->value.u.blob.pBlobData); return hr; diff --git a/dll/win32/windowscodecs/metadataquery.c b/dll/win32/windowscodecs/metadataquery.c index c45082b2024..e33884881b6 100644 --- a/dll/win32/windowscodecs/metadataquery.c +++ b/dll/win32/windowscodecs/metadataquery.c @@ -17,9 +17,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "propvarutil.h" + #include "wincodecs_private.h" -#include +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); static const WCHAR *map_shortname_to_schema(const GUID *format, const WCHAR *name); diff --git a/dll/win32/windowscodecs/palette.c b/dll/win32/windowscodecs/palette.c index 89b10b7ba94..a8370ff1034 100644 --- a/dll/win32/windowscodecs/palette.c +++ b/dll/win32/windowscodecs/palette.c @@ -1,6 +1,7 @@ /* * Copyright 2009 Vincent Povirk for CodeWeavers - * Copyright 2012 Dmitry Timoshkov + * Copyright 2012,2016 Dmitry Timoshkov + * Copyright 2016 Sebastian Lackner * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,8 +18,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct { IWICPalette IWICPalette_iface; LONG ref; @@ -431,11 +447,279 @@ static HRESULT WINAPI PaletteImpl_InitializeCustom(IWICPalette *iface, return S_OK; } -static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *iface, - IWICBitmapSource *pISurface, UINT colorCount, BOOL fAddTransparentColor) +#define R_COUNT (1 << 5) +#define R_SHIFT (8 - 5) +#define R_SCALE 2 + +#define G_COUNT (1 << 6) +#define G_SHIFT (8 - 6) +#define G_SCALE 3 + +#define B_COUNT (1 << 5) +#define B_SHIFT (8 - 5) +#define B_SCALE 1 + +struct histogram { - FIXME("(%p,%p,%u,%i): stub\n", iface, pISurface, colorCount, fAddTransparentColor); - return E_NOTIMPL; + unsigned int data[R_COUNT][G_COUNT][B_COUNT]; +}; + +struct box +{ + int r_min, r_max; + int g_min, g_max; + int b_min, b_max; + unsigned int count; + unsigned int score; +}; + +/* count nonzero elements in the histogram range [r_min, r_max] x [g_min, g_max] x [b_min, b_max] */ +static inline unsigned int histogram_count(struct histogram *h, int r_min, int r_max, + int g_min, int g_max, int b_min, int b_max) +{ + unsigned int count = 0; + int r, g, b; + for (r = r_min; r <= r_max; r++) + for (g = g_min; g <= g_max; g++) + for (b = b_min; b <= b_max; b++) + if (h->data[r][g][b] != 0) count++; + return count; +} + +/* compute weighted average color in the range [r_min, r_max] x [g_min, g_max] x [b_min, b_max] */ +static unsigned int histogram_color(struct histogram *h, int r_min, int r_max, + int g_min, int g_max, int b_min, int b_max) +{ + unsigned long long r_sum = 0, g_sum = 0, b_sum = 0; + unsigned int tmp, count = 0; + int r, g, b; + + for (r = r_min; r <= r_max; r++) + for (g = g_min; g <= g_max; g++) + for (b = b_min; b <= b_max; b++) + { + if (!(tmp = h->data[r][g][b])) continue; + r_sum += ((r << R_SHIFT) + ((1 << R_SHIFT) / 2)) * tmp; + g_sum += ((g << G_SHIFT) + ((1 << G_SHIFT) / 2)) * tmp; + b_sum += ((b << B_SHIFT) + ((1 << B_SHIFT) / 2)) * tmp; + count += tmp; + } + + return ((b_sum + (count / 2)) / count) | + ((g_sum + (count / 2)) / count) << 8 | + ((r_sum + (count / 2)) / count) << 16 | 0xff000000; +} + +/* same as histogram_count */ +static inline unsigned int box_count(struct histogram *h, struct box *b) +{ + return histogram_count(h, b->r_min, b->r_max, b->g_min, b->g_max, b->b_min, b->b_max); +} + +/* same as histogram_color */ +static inline unsigned int box_color(struct histogram *h, struct box *b) +{ + return histogram_color(h, b->r_min, b->r_max, b->g_min, b->g_max, b->b_min, b->b_max); +} + +/* compute score used to determine best split (also called "volume") */ +static inline unsigned int box_score(struct box *b) +{ + unsigned int tmp, sum = 0; + tmp = ((b->r_max - b->r_min) << R_SHIFT) * R_SCALE; sum += tmp * tmp; + tmp = ((b->g_max - b->g_min) << G_SHIFT) * G_SCALE; sum += tmp * tmp; + tmp = ((b->b_max - b->b_min) << B_SHIFT) * B_SCALE; sum += tmp * tmp; + return sum; +} + +/* attempt to shrink a box */ +static void shrink_box(struct histogram *h, struct box *b) +{ + int i; + for (i = b->r_min; i <= b->r_max; i++) + if (histogram_count(h, i, i, b->g_min, b->g_max, b->b_min, b->b_max)) { b->r_min = i; break; } + for (i = b->r_max; i >= b->r_min; i--) + if (histogram_count(h, i, i, b->g_min, b->g_max, b->b_min, b->b_max)) { b->r_max = i; break; } + for (i = b->g_min; i <= b->g_max; i++) + if (histogram_count(h, b->r_min, b->r_max, i, i, b->b_min, b->b_max)) { b->g_min = i; break; } + for (i = b->g_max; i >= b->g_min; i--) + if (histogram_count(h, b->r_min, b->r_max, i, i, b->b_min, b->b_max)) { b->g_max = i; break; } + for (i = b->b_min; i <= b->b_max; i++) + if (histogram_count(h, b->r_min, b->r_max, b->g_min, b->g_max, i, i)) { b->b_min = i; break; } + for (i = b->b_max; i >= b->b_min; i--) + if (histogram_count(h, b->r_min, b->r_max, b->g_min, b->g_max, i, i)) { b->b_max = i; break; } + b->count = box_count(h, b); + b->score = box_score(b); +} + +/* helper for split_box */ +static inline void set_avg(int *min, int *max) +{ + int avg = (*min + *max) / 2; + *min = avg + 1; + *max = avg; +} + +/* split a box based on the best axis */ +static void split_box(struct histogram *h, struct box *b1, struct box *b2) +{ + int r = ((b1->r_max - b1->r_min) << R_SHIFT) * R_SCALE; + int g = ((b1->g_max - b1->g_min) << G_SHIFT) * G_SCALE; + int b = ((b1->b_max - b1->b_min) << B_SHIFT) * B_SCALE; + + *b2 = *b1; + + if (r > g) + { + if (b > r) set_avg(&b1->b_min, &b2->b_max); + else set_avg(&b1->r_min, &b2->r_max); + } + else + { + if (b > g) set_avg(&b1->b_min, &b2->b_max); + else set_avg(&b1->g_min, &b2->g_max); + } + + shrink_box(h, b1); + shrink_box(h, b2); +} + +/* find box suitable for split based on count */ +static struct box *find_box_max_count(struct box *b, int count) +{ + struct box *best = NULL; + for (; count--; b++) + if (b->score && (!best || b->count > best->count)) best = b; + return best; +} + +/* find box suitable for split based on score */ +static struct box *find_box_max_score(struct box *b, int count) +{ + struct box *best = NULL; + for (; count--; b++) + if (b->score && (!best || b->score > best->score)) best = b; + return best; +} + +/* compute color map with at most 'desired' colors + * image must be in 24bpp BGR format and colors are returned in 0xAARRGGBB format */ +static int median_cut(unsigned char *image, unsigned int width, unsigned int height, + unsigned int stride, int desired, unsigned int *colors) +{ + struct box boxes[256]; + struct histogram *h; + unsigned int x, y; + unsigned char *p; + struct box *b1, *b2; + int numboxes, i; + + if (!(h = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*h)))) + return 0; + + for (y = 0; y < height; y++) + for (x = 0, p = image + y * stride; x < width; x++, p += 3) + h->data[p[2] >> R_SHIFT][p[1] >> G_SHIFT][p[0] >> B_SHIFT]++; + + numboxes = 1; + boxes[0].r_min = 0; boxes[0].r_max = R_COUNT - 1; + boxes[0].g_min = 0; boxes[0].g_max = G_COUNT - 1; + boxes[0].b_min = 0; boxes[0].b_max = B_COUNT - 1; + shrink_box(h, &boxes[0]); + + while (numboxes <= desired / 2) + { + if (!(b1 = find_box_max_count(boxes, numboxes))) break; + b2 = &boxes[numboxes++]; + split_box(h, b1, b2); + } + while (numboxes < desired) + { + if (!(b1 = find_box_max_score(boxes, numboxes))) break; + b2 = &boxes[numboxes++]; + split_box(h, b1, b2); + } + + for (i = 0; i < numboxes; i++) + colors[i] = box_color(h, &boxes[i]); + + HeapFree(GetProcessHeap(), 0, h); + return numboxes; +} + + +static HRESULT WINAPI PaletteImpl_InitializeFromBitmap(IWICPalette *palette, + IWICBitmapSource *source, UINT desired, BOOL add_transparent) +{ + IWICImagingFactory *factory = NULL; + IWICBitmap *rgb24_bitmap = NULL; + IWICBitmapSource *rgb24_source; + IWICBitmapLock *lock = NULL; + WICPixelFormatGUID format; + HRESULT hr; + UINT width, height, stride, size, actual_number_of_colors; + BYTE *src; + WICColor colors[256]; + + TRACE("(%p,%p,%u,%d)\n", palette, source, desired, add_transparent); + + if (!source || desired < 2 || desired > 256) + return E_INVALIDARG; + + hr = IWICBitmapSource_GetPixelFormat(source, &format); + if (hr != S_OK) return hr; + + /* For interoperability with gdiplus where PixelFormat24bppRGB actully stored + * as BGR (and there is no a corresponding RGB format) we have to use 24bppBGR + * to avoid format conversions. + */ + if (!IsEqualGUID(&format, &GUID_WICPixelFormat24bppBGR)) + { + hr = WICConvertBitmapSource(&GUID_WICPixelFormat24bppBGR, source, &rgb24_source); + if (hr != S_OK) return hr; + } + else + rgb24_source = source; + + hr = ComponentFactory_CreateInstance(&IID_IWICImagingFactory, (void **)&factory); + if (hr != S_OK) goto fail; + + hr = IWICImagingFactory_CreateBitmapFromSource(factory, rgb24_source, WICBitmapCacheOnLoad, &rgb24_bitmap); + if (hr != S_OK) goto fail; + + hr = IWICBitmap_Lock(rgb24_bitmap, NULL, WICBitmapLockRead, &lock); + if (hr != S_OK) goto fail; + + IWICBitmapLock_GetSize(lock, &width, &height); + IWICBitmapLock_GetStride(lock, &stride); + IWICBitmapLock_GetDataPointer(lock, &size, &src); + + actual_number_of_colors = median_cut(src, width, height, stride, add_transparent ? desired - 1 : desired, colors); + TRACE("actual number of colors: %u\n", actual_number_of_colors); + + if (actual_number_of_colors) + { + if (add_transparent) colors[actual_number_of_colors++] = 0; + + hr = IWICPalette_InitializeCustom(palette, colors, actual_number_of_colors); + } + else + hr = E_OUTOFMEMORY; + +fail: + if (lock) + IWICBitmapLock_Release(lock); + + if (rgb24_bitmap) + IWICBitmap_Release(rgb24_bitmap); + + if (factory) + IWICImagingFactory_Release(factory); + + if (rgb24_source != source) + IWICBitmapSource_Release(rgb24_source); + + return hr; } static HRESULT WINAPI PaletteImpl_InitializeFromPalette(IWICPalette *iface, diff --git a/dll/win32/windowscodecs/pngformat.c b/dll/win32/windowscodecs/pngformat.c index 6946721b77e..54be5edb45d 100644 --- a/dll/win32/windowscodecs/pngformat.c +++ b/dll/win32/windowscodecs/pngformat.c @@ -17,12 +17,29 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wincodecs_private.h" +#include "config.h" +#include "wine/port.h" + +#include #ifdef HAVE_PNG_H #include #endif +#define NONAMELESSUNION +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" +#include "wine/library.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + static inline ULONG read_ulong_be(BYTE* data) { return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]; @@ -605,7 +622,7 @@ static HRESULT WINAPI PngDecoder_Initialize(IWICBitmapDecoder *iface, IStream *p ppng_destroy_read_struct(&This->png_ptr, &This->info_ptr, &This->end_info); HeapFree(GetProcessHeap(), 0, row_pointers); This->png_ptr = NULL; - hr = E_FAIL; + hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT; goto end; } ppng_set_error_fn(This->png_ptr, jmpbuf, user_error_fn, user_warning_fn); @@ -836,10 +853,14 @@ static HRESULT WINAPI PngDecoder_CopyPalette(IWICBitmapDecoder *iface, } static HRESULT WINAPI PngDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, - IWICMetadataQueryReader **ppIMetadataQueryReader) + IWICMetadataQueryReader **reader) { - FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); - return E_NOTIMPL; + FIXME("(%p,%p): stub\n", iface, reader); + + if (!reader) return E_INVALIDARG; + + *reader = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; } static HRESULT WINAPI PngDecoder_GetPreview(IWICBitmapDecoder *iface, @@ -1969,11 +1990,22 @@ static HRESULT WINAPI PngEncoder_GetContainerFormat(IWICBitmapEncoder *iface, return E_NOTIMPL; } -static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, - IWICBitmapEncoderInfo **ppIEncoderInfo) +static HRESULT WINAPI PngEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) { - FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo); - return E_NOTIMPL; + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICPngEncoder, &comp_info); + if (hr == S_OK) + { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; } static HRESULT WINAPI PngEncoder_SetColorContexts(IWICBitmapEncoder *iface, @@ -2016,7 +2048,11 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, { PngEncoder *This = impl_from_IWICBitmapEncoder(iface); HRESULT hr; - PROPBAG2 opts[2]= {{0}}; + static const PROPBAG2 opts[2] = + { + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszPngInterlaceOption }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszPngFilterOption }, + }; TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -2034,18 +2070,14 @@ static HRESULT WINAPI PngEncoder_CreateNewFrame(IWICBitmapEncoder *iface, return WINCODEC_ERR_NOTINITIALIZED; } - opts[0].pstrName = (LPOLESTR)wszPngInterlaceOption; - opts[0].vt = VT_BOOL; - opts[0].dwType = PROPBAG2_TYPE_DATA; - opts[1].pstrName = (LPOLESTR)wszPngFilterOption; - opts[1].vt = VT_UI1; - opts[1].dwType = PROPBAG2_TYPE_DATA; - - hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); - if (FAILED(hr)) + if (ppIEncoderOptions) { - LeaveCriticalSection(&This->lock); - return hr; + hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); + if (FAILED(hr)) + { + LeaveCriticalSection(&This->lock); + return hr; + } } This->frame_count = 1; diff --git a/dll/win32/windowscodecs/precomp.h b/dll/win32/windowscodecs/precomp.h new file mode 100644 index 00000000000..7f4c241216d --- /dev/null +++ b/dll/win32/windowscodecs/precomp.h @@ -0,0 +1,30 @@ + +#ifndef WINCODECS_PRECOMP_H +#define WINCODECS_PRECOMP_H + +#include +#include + +#include + +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H + +#define COBJMACROS +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include +#include +#include +#include +#include +#include + +#include "wincodecs_private.h" + +#include +#include + +#endif /* !WINCODECS_PRECOMP_H */ diff --git a/dll/win32/windowscodecs/propertybag.c b/dll/win32/windowscodecs/propertybag.c index 29f7ac969b1..e9d1af9670d 100644 --- a/dll/win32/windowscodecs/propertybag.c +++ b/dll/win32/windowscodecs/propertybag.c @@ -17,8 +17,23 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" +#include "wine/unicode.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct PropertyBag { IPropertyBag2 IPropertyBag2_iface; LONG ref; @@ -198,7 +213,7 @@ static HRESULT WINAPI PropertyBag_CountProperties(IPropertyBag2 *iface, ULONG *p return S_OK; } -static HRESULT copy_propbag2(PROPBAG2 *dest, PROPBAG2 *src) +static HRESULT copy_propbag2(PROPBAG2 *dest, const PROPBAG2 *src) { dest->cfType = src->cfType; dest->clsid = src->clsid; @@ -263,7 +278,7 @@ static const IPropertyBag2Vtbl PropertyBag_Vtbl = { PropertyBag_LoadObject }; -HRESULT CreatePropertyBag2(PROPBAG2 *options, UINT count, +HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **ppPropertyBag2) { UINT i; diff --git a/dll/win32/windowscodecs/proxy.c b/dll/win32/windowscodecs/proxy.c index 2482d4900ec..a28b38681e1 100644 --- a/dll/win32/windowscodecs/proxy.c +++ b/dll/win32/windowscodecs/proxy.c @@ -18,8 +18,22 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + HRESULT WINAPI IPropertyBag2_Write_Proxy(IPropertyBag2 *iface, ULONG cProperties, PROPBAG2 *ppropbag, VARIANT *pvarValue) { diff --git a/dll/win32/windowscodecs/regsvr.c b/dll/win32/windowscodecs/regsvr.c index 756fb196510..328ea54c843 100644 --- a/dll/win32/windowscodecs/regsvr.c +++ b/dll/win32/windowscodecs/regsvr.c @@ -16,9 +16,26 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define COBJMACROS +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winreg.h" +#include "winerror.h" + +#include "objbase.h" +#include "ocidl.h" + +#include "wine/debug.h" +#include "wine/unicode.h" + #include "wincodecs_private.h" -#include +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); /*********************************************************************** * interface for self-registering @@ -1194,6 +1211,10 @@ static GUID const * const tiff_decode_formats[] = { &GUID_WICPixelFormatBlackWhite, &GUID_WICPixelFormat4bppGray, &GUID_WICPixelFormat8bppGray, + &GUID_WICPixelFormat16bppGray, + &GUID_WICPixelFormat32bppGrayFloat, + &GUID_WICPixelFormat1bppIndexed, + &GUID_WICPixelFormat2bppIndexed, &GUID_WICPixelFormat4bppIndexed, &GUID_WICPixelFormat8bppIndexed, &GUID_WICPixelFormat24bppBGR, @@ -1203,6 +1224,9 @@ static GUID const * const tiff_decode_formats[] = { &GUID_WICPixelFormat48bppRGB, &GUID_WICPixelFormat64bppRGBA, &GUID_WICPixelFormat64bppPRGBA, + &GUID_WICPixelFormat32bppCMYK, + &GUID_WICPixelFormat64bppCMYK, + &GUID_WICPixelFormat128bppRGBAFloat, NULL }; @@ -1328,6 +1352,11 @@ static GUID const * const bmp_encode_formats[] = { &GUID_WICPixelFormat16bppBGR565, &GUID_WICPixelFormat24bppBGR, &GUID_WICPixelFormat32bppBGR, + &GUID_WICPixelFormatBlackWhite, + &GUID_WICPixelFormat1bppIndexed, + &GUID_WICPixelFormat2bppIndexed, + &GUID_WICPixelFormat4bppIndexed, + &GUID_WICPixelFormat8bppIndexed, NULL }; @@ -1353,6 +1382,10 @@ static GUID const * const tiff_encode_formats[] = { &GUID_WICPixelFormatBlackWhite, &GUID_WICPixelFormat4bppGray, &GUID_WICPixelFormat8bppGray, + &GUID_WICPixelFormat1bppIndexed, + &GUID_WICPixelFormat2bppIndexed, + &GUID_WICPixelFormat4bppIndexed, + &GUID_WICPixelFormat8bppIndexed, &GUID_WICPixelFormat24bppBGR, &GUID_WICPixelFormat32bppBGRA, &GUID_WICPixelFormat32bppPBGRA, @@ -1378,6 +1411,16 @@ static struct regsvr_encoder const encoder_list[] = { ".bmp,.dib,.rle", bmp_encode_formats }, + { &CLSID_WICGifEncoder, + "The Wine Project", + "GIF Encoder", + "1.0.0.0", + &GUID_VendorMicrosoft, + &GUID_ContainerFormatGif, + "image/gif", + ".gif", + gif_formats + }, { &CLSID_WICJpegEncoder, "The Wine Project", "JPEG Encoder", @@ -1437,8 +1480,11 @@ static GUID const * const converter_formats[] = { &GUID_WICPixelFormat24bppBGR, &GUID_WICPixelFormat24bppRGB, &GUID_WICPixelFormat32bppBGR, + &GUID_WICPixelFormat32bppRGB, &GUID_WICPixelFormat32bppBGRA, + &GUID_WICPixelFormat32bppRGBA, &GUID_WICPixelFormat32bppPBGRA, + &GUID_WICPixelFormat32bppPRGBA, &GUID_WICPixelFormat32bppGrayFloat, &GUID_WICPixelFormat48bppRGB, &GUID_WICPixelFormat64bppRGBA, @@ -1710,6 +1756,13 @@ static BYTE const channel_mask_16bit2[] = { 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, static BYTE const channel_mask_16bit3[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00 }; static BYTE const channel_mask_16bit4[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }; +static BYTE const channel_mask_32bit[] = { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 }; + +static BYTE const channel_mask_128bit1[] = { 0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static BYTE const channel_mask_128bit2[] = { 0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; +static BYTE const channel_mask_128bit3[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00 }; +static BYTE const channel_mask_128bit4[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff }; + static BYTE const channel_mask_5bit[] = { 0x1f, 0x00 }; static BYTE const channel_mask_5bit2[] = { 0xe0, 0x03 }; static BYTE const channel_mask_5bit3[] = { 0x00, 0x7c }; @@ -1726,6 +1779,9 @@ static BYTE const * const channel_masks_8bit[] = { channel_mask_8bit, static BYTE const * const channel_masks_16bit[] = { channel_mask_16bit, channel_mask_16bit2, channel_mask_16bit3, channel_mask_16bit4}; +static BYTE const * const channel_masks_32bit[] = { channel_mask_32bit }; +static BYTE const * const channel_masks_128bit[] = { channel_mask_128bit1, channel_mask_128bit2, channel_mask_128bit3, channel_mask_128bit4 }; + static BYTE const * const channel_masks_BGRA5551[] = { channel_mask_5bit, channel_mask_5bit2, channel_mask_5bit3, channel_mask_5bit4 }; @@ -1742,7 +1798,7 @@ static struct regsvr_pixelformat const pixelformat_list[] = { 1, /* channel count */ channel_masks_1bit, WICPixelFormatNumericRepresentationIndexed, - 1 + 0 }, { &GUID_WICPixelFormat2bppIndexed, "The Wine Project", @@ -1753,7 +1809,7 @@ static struct regsvr_pixelformat const pixelformat_list[] = { 1, /* channel count */ channel_masks_2bit, WICPixelFormatNumericRepresentationIndexed, - 1 + 0 }, { &GUID_WICPixelFormat4bppIndexed, "The Wine Project", @@ -1764,7 +1820,7 @@ static struct regsvr_pixelformat const pixelformat_list[] = { 1, /* channel count */ channel_masks_4bit, WICPixelFormatNumericRepresentationIndexed, - 1 + 0 }, { &GUID_WICPixelFormat8bppIndexed, "The Wine Project", @@ -1775,7 +1831,7 @@ static struct regsvr_pixelformat const pixelformat_list[] = { 1, /* channel count */ channel_masks_8bit, WICPixelFormatNumericRepresentationIndexed, - 1 + 0 }, { &GUID_WICPixelFormatBlackWhite, "The Wine Project", @@ -1898,6 +1954,17 @@ static struct regsvr_pixelformat const pixelformat_list[] = { WICPixelFormatNumericRepresentationUnsignedInteger, 0 }, + { &GUID_WICPixelFormat32bppRGB, + "The Wine Project", + "32bpp RGB", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 32, /* bitsperpixel */ + 3, /* channel count */ + channel_masks_8bit, + WICPixelFormatNumericRepresentationUnsignedInteger, + 0 + }, { &GUID_WICPixelFormat32bppBGRA, "The Wine Project", "32bpp BGRA", @@ -1909,6 +1976,17 @@ static struct regsvr_pixelformat const pixelformat_list[] = { WICPixelFormatNumericRepresentationUnsignedInteger, 1 }, + { &GUID_WICPixelFormat32bppRGBA, + "The Wine Project", + "32bpp RGBA", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 32, /* bitsperpixel */ + 4, /* channel count */ + channel_masks_8bit, + WICPixelFormatNumericRepresentationUnsignedInteger, + 1 + }, { &GUID_WICPixelFormat32bppPBGRA, "The Wine Project", "32bpp PBGRA", @@ -1920,6 +1998,28 @@ static struct regsvr_pixelformat const pixelformat_list[] = { WICPixelFormatNumericRepresentationUnsignedInteger, 1 }, + { &GUID_WICPixelFormat32bppPRGBA, + "The Wine Project", + "32bpp PRGBA", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 32, /* bitsperpixel */ + 4, /* channel count */ + channel_masks_8bit, + WICPixelFormatNumericRepresentationUnsignedInteger, + 1 + }, + { &GUID_WICPixelFormat32bppGrayFloat, + "The Wine Project", + "32bpp GrayFloat", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 32, /* bitsperpixel */ + 1, /* channel count */ + channel_masks_32bit, + WICPixelFormatNumericRepresentationFloat, + 0 + }, { &GUID_WICPixelFormat48bppRGB, "The Wine Project", "48bpp RGB", @@ -1964,6 +2064,28 @@ static struct regsvr_pixelformat const pixelformat_list[] = { WICPixelFormatNumericRepresentationUnsignedInteger, 0 }, + { &GUID_WICPixelFormat64bppCMYK, + "The Wine Project", + "64bpp CMYK", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 64, /* bitsperpixel */ + 4, /* channel count */ + channel_masks_16bit, + WICPixelFormatNumericRepresentationUnsignedInteger, + 0 + }, + { &GUID_WICPixelFormat128bppRGBAFloat, + "The Wine Project", + "128bpp RGBAFloat", + NULL, /* no version */ + &GUID_VendorMicrosoft, + 128, /* bitsperpixel */ + 4, /* channel count */ + channel_masks_128bit, + WICPixelFormatNumericRepresentationFloat, + 1 + }, { NULL } /* list terminator */ }; diff --git a/dll/win32/windowscodecs/scaler.c b/dll/win32/windowscodecs/scaler.c index 8e267e314a2..3801ea5ecd2 100644 --- a/dll/win32/windowscodecs/scaler.c +++ b/dll/win32/windowscodecs/scaler.c @@ -16,11 +16,26 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + typedef struct BitmapScaler { IWICBitmapScaler IWICBitmapScaler_iface; LONG ref; + IMILBitmapScaler IMILBitmapScaler_iface; IWICBitmapSource *source; UINT width, height; UINT src_width, src_height; @@ -36,6 +51,11 @@ static inline BitmapScaler *impl_from_IWICBitmapScaler(IWICBitmapScaler *iface) return CONTAINING_RECORD(iface, BitmapScaler, IWICBitmapScaler_iface); } +static inline BitmapScaler *impl_from_IMILBitmapScaler(IMILBitmapScaler *iface) +{ + return CONTAINING_RECORD(iface, BitmapScaler, IMILBitmapScaler_iface); +} + static HRESULT WINAPI BitmapScaler_QueryInterface(IWICBitmapScaler *iface, REFIID iid, void **ppv) { @@ -50,8 +70,13 @@ static HRESULT WINAPI BitmapScaler_QueryInterface(IWICBitmapScaler *iface, REFII { *ppv = &This->IWICBitmapScaler_iface; } + else if (IsEqualIID(&IID_IMILBitmapScaler, iid)) + { + *ppv = &This->IMILBitmapScaler_iface; + } else { + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -360,6 +385,163 @@ static const IWICBitmapScalerVtbl BitmapScaler_Vtbl = { BitmapScaler_Initialize }; +static HRESULT WINAPI IMILBitmapScaler_QueryInterface(IMILBitmapScaler *iface, REFIID iid, + void **ppv) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IMILBitmapScaler, iid) || + IsEqualIID(&IID_IMILBitmapSource, iid)) + { + IUnknown_AddRef(&This->IMILBitmapScaler_iface); + *ppv = &This->IMILBitmapScaler_iface; + return S_OK; + } + else if (IsEqualIID(&IID_IWICBitmapScaler, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid)) + { + IUnknown_AddRef(&This->IWICBitmapScaler_iface); + *ppv = &This->IWICBitmapScaler_iface; + return S_OK; + } + + FIXME("unknown interface %s\n", debugstr_guid(iid)); + *ppv = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI IMILBitmapScaler_AddRef(IMILBitmapScaler *iface) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + return IWICBitmapScaler_AddRef(&This->IWICBitmapScaler_iface); +} + +static ULONG WINAPI IMILBitmapScaler_Release(IMILBitmapScaler *iface) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + return IWICBitmapScaler_Release(&This->IWICBitmapScaler_iface); +} + +static HRESULT WINAPI IMILBitmapScaler_GetSize(IMILBitmapScaler *iface, + UINT *width, UINT *height) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%p)\n", iface, width, height); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_GetSize(&This->IWICBitmapScaler_iface, width, height); +} + +static HRESULT WINAPI IMILBitmapScaler_GetPixelFormat(IMILBitmapScaler *iface, + int *format) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + IMILBitmapSource *source; + HRESULT hr; + + TRACE("(%p,%p)\n", iface, format); + + if (!format) return E_INVALIDARG; + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + hr = IWICBitmapSource_QueryInterface(This->source, &IID_IMILBitmapSource, (void **)&source); + if (hr == S_OK) + { + hr = source->lpVtbl->GetPixelFormat(source, format); + source->lpVtbl->Release(source); + } + return hr; +} + +static HRESULT WINAPI IMILBitmapScaler_GetResolution(IMILBitmapScaler *iface, + double *dpix, double *dpiy) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%p)\n", iface, dpix, dpiy); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_GetResolution(&This->IWICBitmapScaler_iface, dpix, dpiy); +} + +static HRESULT WINAPI IMILBitmapScaler_CopyPalette(IMILBitmapScaler *iface, + IWICPalette *palette) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p)\n", iface, palette); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_CopyPalette(&This->IWICBitmapScaler_iface, palette); +} + +static HRESULT WINAPI IMILBitmapScaler_CopyPixels(IMILBitmapScaler *iface, + const WICRect *rc, UINT stride, UINT size, BYTE *buffer) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + + TRACE("(%p,%p,%u,%u,%p)\n", iface, rc, stride, size, buffer); + + if (!This->source) + return WINCODEC_ERR_NOTINITIALIZED; + + return IWICBitmapScaler_CopyPixels(&This->IWICBitmapScaler_iface, rc, stride, size, buffer); +} + +static HRESULT WINAPI IMILBitmapScaler_unknown1(IMILBitmapScaler *iface, void **ppv) +{ + TRACE("(%p,%p)\n", iface, ppv); + return E_NOINTERFACE; +} + +static HRESULT WINAPI IMILBitmapScaler_Initialize(IMILBitmapScaler *iface, + IMILBitmapSource *mil_source, UINT width, UINT height, + WICBitmapInterpolationMode mode) +{ + BitmapScaler *This = impl_from_IMILBitmapScaler(iface); + IWICBitmapSource *wic_source; + HRESULT hr; + + TRACE("(%p,%p,%u,%u,%u)\n", iface, mil_source, width, height, mode); + + if (!mil_source) return E_INVALIDARG; + + hr = mil_source->lpVtbl->QueryInterface(mil_source, &IID_IWICBitmapSource, (void **)&wic_source); + if (hr == S_OK) + { + hr = IWICBitmapScaler_Initialize(&This->IWICBitmapScaler_iface, wic_source, width, height, mode); + IWICBitmapSource_Release(wic_source); + } + return hr; +} + +static const IMILBitmapScalerVtbl IMILBitmapScaler_Vtbl = { + IMILBitmapScaler_QueryInterface, + IMILBitmapScaler_AddRef, + IMILBitmapScaler_Release, + IMILBitmapScaler_GetSize, + IMILBitmapScaler_GetPixelFormat, + IMILBitmapScaler_GetResolution, + IMILBitmapScaler_CopyPalette, + IMILBitmapScaler_CopyPixels, + IMILBitmapScaler_unknown1, + IMILBitmapScaler_Initialize +}; + HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) { BitmapScaler *This; @@ -368,6 +550,7 @@ HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) if (!This) return E_OUTOFMEMORY; This->IWICBitmapScaler_iface.lpVtbl = &BitmapScaler_Vtbl; + This->IMILBitmapScaler_iface.lpVtbl = &IMILBitmapScaler_Vtbl; This->ref = 1; This->source = NULL; This->width = 0; diff --git a/dll/win32/windowscodecs/stream.c b/dll/win32/windowscodecs/stream.c index f585036edef..308ef8e02b4 100644 --- a/dll/win32/windowscodecs/stream.c +++ b/dll/win32/windowscodecs/stream.c @@ -16,9 +16,17 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "wine/debug.h" + +#define COBJMACROS +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "objbase.h" +#include "shlwapi.h" #include "wincodecs_private.h" -#include +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); /****************************************** * StreamOnMemory implementation diff --git a/dll/win32/windowscodecs/tgaformat.c b/dll/win32/windowscodecs/tgaformat.c index 52b5877095c..ec7fa23169b 100644 --- a/dll/win32/windowscodecs/tgaformat.c +++ b/dll/win32/windowscodecs/tgaformat.c @@ -16,8 +16,24 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include "config.h" +#include "wine/port.h" + +#include + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + #include "wincodecs_private.h" +#include "wine/debug.h" +#include "wine/library.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + #include "pshpack1.h" typedef struct { diff --git a/dll/win32/windowscodecs/tiffformat.c b/dll/win32/windowscodecs/tiffformat.c index 55423028a48..c23594f61f0 100644 --- a/dll/win32/windowscodecs/tiffformat.c +++ b/dll/win32/windowscodecs/tiffformat.c @@ -1,5 +1,6 @@ /* * Copyright 2010 Vincent Povirk for CodeWeavers + * Copyright 2016 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,8 +17,10 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "wincodecs_private.h" +#include "config.h" +#include "wine/port.h" +#include #ifdef HAVE_UNISTD_H #include #endif @@ -25,6 +28,19 @@ #include #endif +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" +#include "wine/library.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + #ifdef SONAME_LIBTIFF /* Workaround for broken libtiff 4.x headers on some 64-bit hosts which @@ -303,6 +319,8 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) } decode_info->planar = planar; + TRACE("planar %u, photometric %u, samples %u, bps %u\n", planar, photometric, samples, bps); + switch(photometric) { case 0: /* WhiteIsZero */ @@ -367,14 +385,28 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) } } break; + case 16: + if (samples != 1) + { + FIXME("unhandled 16bpp grayscale sample count %u\n", samples); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + decode_info->format = &GUID_WICPixelFormat16bppGray; + break; + case 32: + if (samples != 1) + { + FIXME("unhandled 32bpp grayscale sample count %u\n", samples); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + decode_info->format = &GUID_WICPixelFormat32bppGrayFloat; + break; default: - FIXME("unhandled greyscale bit count %u\n", bps); - return E_FAIL; + WARN("unhandled greyscale bit count %u\n", bps); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; } break; case 2: /* RGB */ - decode_info->bpp = bps * samples; - if (samples == 4) { ret = pTIFFGetField(tiff, TIFFTAG_EXTRASAMPLES, &extra_sample_count, &extra_samples); @@ -391,8 +423,12 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) return E_FAIL; } + decode_info->bpp = max(bps, 8) * samples; + decode_info->source_bpp = bps * samples; switch(bps) { + case 1: + case 4: case 8: decode_info->reverse_bgr = 1; if (samples == 3) @@ -430,9 +466,17 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) return E_FAIL; } break; + case 32: + if (samples != 4) + { + FIXME("unhandled 32bpp RGB sample count %u\n", samples); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + decode_info->format = &GUID_WICPixelFormat128bppRGBAFloat; + break; default: - FIXME("unhandled RGB bit count %u\n", bps); - return E_FAIL; + WARN("unhandled RGB bit count %u\n", bps); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; } break; case 3: /* RGB Palette */ @@ -446,6 +490,12 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) decode_info->bpp = bps; switch (bps) { + case 1: + decode_info->format = &GUID_WICPixelFormat1bppIndexed; + break; + case 2: + decode_info->format = &GUID_WICPixelFormat2bppIndexed; + break; case 4: decode_info->format = &GUID_WICPixelFormat4bppIndexed; break; @@ -457,8 +507,31 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) return E_FAIL; } break; + + case 5: /* Separated */ + if (samples != 4) + { + FIXME("unhandled Separated sample count %u\n", samples); + return E_FAIL; + } + + decode_info->bpp = bps * samples; + switch(bps) + { + case 8: + decode_info->format = &GUID_WICPixelFormat32bppCMYK; + break; + case 16: + decode_info->format = &GUID_WICPixelFormat64bppCMYK; + break; + + default: + WARN("unhandled Separated bit count %u\n", bps); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + break; + case 4: /* Transparency mask */ - case 5: /* CMYK */ case 6: /* YCbCr */ case 8: /* CIELab */ default: @@ -514,21 +587,27 @@ static HRESULT tiff_get_decode_info(TIFF *tiff, tiff_decode_info *decode_info) decode_info->resolution_unit = 0; pTIFFGetField(tiff, TIFFTAG_RESOLUTIONUNIT, &decode_info->resolution_unit); - if (decode_info->resolution_unit != 0) - { - ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &decode_info->xres); - if (!ret) - { - WARN("missing X resolution\n"); - decode_info->resolution_unit = 0; - } - ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &decode_info->yres); - if (!ret) - { - WARN("missing Y resolution\n"); - decode_info->resolution_unit = 0; - } + ret = pTIFFGetField(tiff, TIFFTAG_XRESOLUTION, &decode_info->xres); + if (!ret) + { + WARN("missing X resolution\n"); + } + /* Emulate the behavior of current libtiff versions (libtiff commit a39f6131) + * yielding 0 instead of INFINITY for IFD_RATIONAL fields with denominator 0. */ + if (!isfinite(decode_info->xres)) + { + decode_info->xres = 0.0; + } + + ret = pTIFFGetField(tiff, TIFFTAG_YRESOLUTION, &decode_info->yres); + if (!ret) + { + WARN("missing Y resolution\n"); + } + if (!isfinite(decode_info->yres)) + { + decode_info->yres = 0.0; } return S_OK; @@ -609,6 +688,7 @@ static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream * { TiffDecoder *This = impl_from_IWICBitmapDecoder(iface); TIFF *tiff; + tiff_decode_info decode_info; HRESULT hr=S_OK; TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); @@ -622,13 +702,20 @@ static HRESULT WINAPI TiffDecoder_Initialize(IWICBitmapDecoder *iface, IStream * } tiff = tiff_open_stream(pIStream, "r"); - if (!tiff) { hr = E_FAIL; goto exit; } + /* make sure that TIFF format is supported */ + hr = tiff_get_decode_info(tiff, &decode_info); + if (hr != S_OK) + { + pTIFFClose(tiff); + goto exit; + } + This->tiff = tiff; This->stream = pIStream; IStream_AddRef(pIStream); @@ -677,8 +764,12 @@ static HRESULT WINAPI TiffDecoder_CopyPalette(IWICBitmapDecoder *iface, static HRESULT WINAPI TiffDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, IWICMetadataQueryReader **ppIMetadataQueryReader) { - FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryReader); - return E_NOTIMPL; + TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); + + if (!ppIMetadataQueryReader) return E_INVALIDARG; + + *ppIMetadataQueryReader = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; } static HRESULT WINAPI TiffDecoder_GetPreview(IWICBitmapDecoder *iface, @@ -878,26 +969,28 @@ static HRESULT WINAPI TiffFrameDecode_GetResolution(IWICBitmapFrameDecode *iface { TiffFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); - switch (This->decode_info.resolution_unit) + if (This->decode_info.xres == 0 || This->decode_info.yres == 0) { - default: - FIXME("unknown resolution unit %i\n", This->decode_info.resolution_unit); - /* fall through */ - case 0: /* Not set */ *pDpiX = *pDpiY = 96.0; - break; - case 1: /* Relative measurements */ - *pDpiX = 96.0; - *pDpiY = 96.0 * This->decode_info.yres / This->decode_info.xres; - break; - case 2: /* Inch */ - *pDpiX = This->decode_info.xres; - *pDpiY = This->decode_info.yres; - break; - case 3: /* Centimeter */ - *pDpiX = This->decode_info.xres / 2.54; - *pDpiY = This->decode_info.yres / 2.54; - break; + } + else + { + switch (This->decode_info.resolution_unit) + { + default: + FIXME("unknown resolution unit %i\n", This->decode_info.resolution_unit); + /* fall through */ + case 0: /* Not set */ + case 1: /* Relative measurements */ + case 2: /* Inch */ + *pDpiX = This->decode_info.xres; + *pDpiY = This->decode_info.yres; + break; + case 3: /* Centimeter */ + *pDpiX = This->decode_info.xres * 2.54; + *pDpiY = This->decode_info.yres * 2.54; + break; + } } TRACE("(%p) <-- %f,%f unit=%i\n", iface, *pDpiX, *pDpiY, This->decode_info.resolution_unit); @@ -940,34 +1033,183 @@ static HRESULT WINAPI TiffFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT tile_y) { - HRESULT hr=S_OK; tsize_t ret; int swap_bytes; swap_bytes = pTIFFIsByteSwapped(This->parent->tiff); ret = pTIFFSetDirectory(This->parent->tiff, This->index); + if (ret == -1) + return E_FAIL; + + if (This->decode_info.tiled) + ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size); + else + ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size); if (ret == -1) - hr = E_FAIL; + return E_FAIL; - if (hr == S_OK) + /* 3bpp RGB */ + if (This->decode_info.source_bpp == 3 && This->decode_info.samples == 3 && This->decode_info.bpp == 24) { - if (This->decode_info.tiled) + BYTE *srcdata, *src, *dst; + DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 3 + 7) / 8; + + count = width_bytes * This->decode_info.tile_height; + + srcdata = HeapAlloc(GetProcessHeap(), 0, count); + if (!srcdata) return E_OUTOFMEMORY; + memcpy(srcdata, This->cached_tile, count); + + for (y = 0; y < This->decode_info.tile_height; y++) { - ret = pTIFFReadEncodedTile(This->parent->tiff, tile_x + tile_y * This->decode_info.tiles_across, This->cached_tile, This->decode_info.tile_size); - } - else - { - ret = pTIFFReadEncodedStrip(This->parent->tiff, tile_y, This->cached_tile, This->decode_info.tile_size); + src = srcdata + y * width_bytes; + dst = This->cached_tile + y * This->decode_info.tile_width * 3; + + for (x = 0; x < This->decode_info.tile_width; x += 8) + { + dst[2] = (src[0] & 0x80) ? 0xff : 0; /* R */ + dst[1] = (src[0] & 0x40) ? 0xff : 0; /* G */ + dst[0] = (src[0] & 0x20) ? 0xff : 0; /* B */ + if (x + 1 < This->decode_info.tile_width) + { + dst[5] = (src[0] & 0x10) ? 0xff : 0; /* R */ + dst[4] = (src[0] & 0x08) ? 0xff : 0; /* G */ + dst[3] = (src[0] & 0x04) ? 0xff : 0; /* B */ + } + if (x + 2 < This->decode_info.tile_width) + { + dst[8] = (src[0] & 0x02) ? 0xff : 0; /* R */ + dst[7] = (src[0] & 0x01) ? 0xff : 0; /* G */ + dst[6] = (src[1] & 0x80) ? 0xff : 0; /* B */ + } + if (x + 3 < This->decode_info.tile_width) + { + dst[11] = (src[1] & 0x40) ? 0xff : 0; /* R */ + dst[10] = (src[1] & 0x20) ? 0xff : 0; /* G */ + dst[9] = (src[1] & 0x10) ? 0xff : 0; /* B */ + } + if (x + 4 < This->decode_info.tile_width) + { + dst[14] = (src[1] & 0x08) ? 0xff : 0; /* R */ + dst[13] = (src[1] & 0x04) ? 0xff : 0; /* G */ + dst[12] = (src[1] & 0x02) ? 0xff : 0; /* B */ + } + if (x + 5 < This->decode_info.tile_width) + { + dst[17] = (src[1] & 0x01) ? 0xff : 0; /* R */ + dst[16] = (src[2] & 0x80) ? 0xff : 0; /* G */ + dst[15] = (src[2] & 0x40) ? 0xff : 0; /* B */ + } + if (x + 6 < This->decode_info.tile_width) + { + dst[20] = (src[2] & 0x20) ? 0xff : 0; /* R */ + dst[19] = (src[2] & 0x10) ? 0xff : 0; /* G */ + dst[18] = (src[2] & 0x08) ? 0xff : 0; /* B */ + } + if (x + 7 < This->decode_info.tile_width) + { + dst[23] = (src[2] & 0x04) ? 0xff : 0; /* R */ + dst[22] = (src[2] & 0x02) ? 0xff : 0; /* G */ + dst[21] = (src[2] & 0x01) ? 0xff : 0; /* B */ + } + src += 3; + dst += 24; + } } - if (ret == -1) - hr = E_FAIL; + HeapFree(GetProcessHeap(), 0, srcdata); } + /* 12bpp RGB */ + else if (This->decode_info.source_bpp == 12 && This->decode_info.samples == 3 && This->decode_info.bpp == 24) + { + BYTE *srcdata, *src, *dst; + DWORD x, y, count, width_bytes = (This->decode_info.tile_width * 12 + 7) / 8; + count = width_bytes * This->decode_info.tile_height; + + srcdata = HeapAlloc(GetProcessHeap(), 0, count); + if (!srcdata) return E_OUTOFMEMORY; + memcpy(srcdata, This->cached_tile, count); + + for (y = 0; y < This->decode_info.tile_height; y++) + { + src = srcdata + y * width_bytes; + dst = This->cached_tile + y * This->decode_info.tile_width * 3; + + for (x = 0; x < This->decode_info.tile_width; x += 2) + { + dst[0] = ((src[1] & 0xf0) >> 4) * 17; /* B */ + dst[1] = (src[0] & 0x0f) * 17; /* G */ + dst[2] = ((src[0] & 0xf0) >> 4) * 17; /* R */ + if (x + 1 < This->decode_info.tile_width) + { + dst[5] = (src[1] & 0x0f) * 17; /* B */ + dst[4] = ((src[2] & 0xf0) >> 4) * 17; /* G */ + dst[3] = (src[2] & 0x0f) * 17; /* R */ + } + src += 3; + dst += 6; + } + } + + HeapFree(GetProcessHeap(), 0, srcdata); + } + /* 4bpp RGBA */ + else if (This->decode_info.source_bpp == 4 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) + { + BYTE *src, *dst; + DWORD count; + + /* 1 source byte expands to 2 BGRA samples */ + count = (This->decode_info.tile_width * This->decode_info.tile_height + 1) / 2; + + src = This->cached_tile + count - 1; + dst = This->cached_tile + This->decode_info.tile_size; + + while (count--) + { + BYTE b = *src--; + + dst -= 8; + dst[2] = (b & 0x80) ? 0xff : 0; /* R */ + dst[1] = (b & 0x40) ? 0xff : 0; /* G */ + dst[0] = (b & 0x20) ? 0xff : 0; /* B */ + dst[3] = (b & 0x10) ? 0xff : 0; /* A */ + dst[6] = (b & 0x08) ? 0xff : 0; /* R */ + dst[5] = (b & 0x04) ? 0xff : 0; /* G */ + dst[4] = (b & 0x02) ? 0xff : 0; /* B */ + dst[7] = (b & 0x01) ? 0xff : 0; /* A */ + } + } + /* 16bpp RGBA */ + else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 4 && This->decode_info.bpp == 32) + { + BYTE *src, *dst; + DWORD count = This->decode_info.tile_width * This->decode_info.tile_height; + + src = This->cached_tile + count * 2; + dst = This->cached_tile + This->decode_info.tile_size; + + while (count--) + { + BYTE b[2]; + + src -= 2; + dst -= 4; + + b[0] = src[0]; + b[1] = src[1]; + + dst[0] = ((b[1] & 0xf0) >> 4) * 17; /* B */ + dst[1] = (b[0] & 0x0f) * 17; /* G */ + dst[2] = ((b[0] & 0xf0) >> 4) * 17; /* R */ + dst[3] = (b[1] & 0x0f) * 17; /* A */ + } + } /* 8bpp grayscale with extra alpha */ - if (hr == S_OK && This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32) + else if (This->decode_info.source_bpp == 16 && This->decode_info.samples == 2 && This->decode_info.bpp == 32) { BYTE *src; DWORD *dst, count = This->decode_info.tile_width * This->decode_info.tile_height; @@ -982,7 +1224,7 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT } } - if (hr == S_OK && This->decode_info.reverse_bgr) + if (This->decode_info.reverse_bgr) { if (This->decode_info.bps == 8) { @@ -993,7 +1235,7 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT } } - if (hr == S_OK && swap_bytes && This->decode_info.bps > 8) + if (swap_bytes && This->decode_info.bps > 8) { UINT row, i, samples_per_row; BYTE *sample, temp; @@ -1021,7 +1263,7 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT } } - if (hr == S_OK && This->decode_info.invert_grayscale) + if (This->decode_info.invert_grayscale) { BYTE *byte, *end; @@ -1037,13 +1279,10 @@ static HRESULT TiffFrameDecode_ReadTile(TiffFrameDecode *This, UINT tile_x, UINT *byte = ~(*byte); } - if (hr == S_OK) - { - This->cached_tile_x = tile_x; - This->cached_tile_y = tile_y; - } + This->cached_tile_x = tile_x; + This->cached_tile_y = tile_y; - return hr; + return S_OK; } static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, @@ -1080,7 +1319,7 @@ static HRESULT WINAPI TiffFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, if (cbStride < bytesperrow) return E_INVALIDARG; - if ((cbStride * prc->Height) > cbBufferSize) + if ((cbStride * (prc->Height-1)) + ((prc->Width * This->decode_info.bpp) + 7)/8 > cbBufferSize) return E_INVALIDARG; min_tile_x = prc->X / This->decode_info.tile_width; @@ -1394,6 +1633,10 @@ static const struct tiff_encode_format formats[] = { {&GUID_WICPixelFormat48bppRGB, 2, 16, 3, 48, 0, 0, 0}, {&GUID_WICPixelFormat64bppRGBA, 2, 16, 4, 64, 1, 2, 0}, {&GUID_WICPixelFormat64bppPRGBA, 2, 16, 4, 64, 1, 1, 0}, + {&GUID_WICPixelFormat1bppIndexed, 3, 1, 1, 1, 0, 0, 0}, + {&GUID_WICPixelFormat2bppIndexed, 3, 2, 1, 2, 0, 0, 0}, + {&GUID_WICPixelFormat4bppIndexed, 3, 4, 1, 4, 0, 0, 0}, + {&GUID_WICPixelFormat8bppIndexed, 3, 8, 1, 8, 0, 0, 0}, {0} }; @@ -1676,6 +1919,21 @@ static HRESULT WINAPI TiffFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, pTIFFSetField(This->parent->tiff, TIFFTAG_YRESOLUTION, (float)This->yres); } + if (This->format->bpp <= 8 && This->colors && !IsEqualGUID(This->format->guid, &GUID_WICPixelFormatBlackWhite)) + { + uint16 red[256], green[256], blue[256]; + UINT i; + + for (i = 0; i < This->colors; i++) + { + red[i] = (This->palette[i] >> 8) & 0xff00; + green[i] = This->palette[i] & 0xff00; + blue[i] = (This->palette[i] << 8) & 0xff00; + } + + pTIFFSetField(This->parent->tiff, TIFFTAG_COLORMAP, red, green, blue); + } + This->info_written = TRUE; } @@ -1874,11 +2132,22 @@ static HRESULT WINAPI TiffEncoder_GetContainerFormat(IWICBitmapEncoder *iface, return S_OK; } -static HRESULT WINAPI TiffEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, - IWICBitmapEncoderInfo **ppIEncoderInfo) +static HRESULT WINAPI TiffEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) { - FIXME("(%p,%p): stub\n", iface, ppIEncoderInfo); - return E_NOTIMPL; + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICTiffEncoder, &comp_info); + if (hr == S_OK) + { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; } static HRESULT WINAPI TiffEncoder_SetColorContexts(IWICBitmapEncoder *iface, @@ -1921,7 +2190,11 @@ static HRESULT WINAPI TiffEncoder_CreateNewFrame(IWICBitmapEncoder *iface, { TiffEncoder *This = impl_from_IWICBitmapEncoder(iface); TiffFrameEncode *result; - + static const PROPBAG2 opts[2] = + { + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)wszTiffCompressionMethod }, + { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)wszCompressionQuality }, + }; HRESULT hr=S_OK; TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -1938,26 +2211,16 @@ static HRESULT WINAPI TiffEncoder_CreateNewFrame(IWICBitmapEncoder *iface, hr = E_FAIL; } - if (SUCCEEDED(hr)) + if (ppIEncoderOptions && SUCCEEDED(hr)) { - PROPBAG2 opts[2]= {{0}}; - opts[0].pstrName = (LPOLESTR)wszTiffCompressionMethod; - opts[0].vt = VT_UI1; - opts[0].dwType = PROPBAG2_TYPE_DATA; - - opts[1].pstrName = (LPOLESTR)wszCompressionQuality; - opts[1].vt = VT_R4; - opts[1].dwType = PROPBAG2_TYPE_DATA; - - hr = CreatePropertyBag2(opts, 2, ppIEncoderOptions); - + hr = CreatePropertyBag2(opts, sizeof(opts)/sizeof(opts[0]), ppIEncoderOptions); if (SUCCEEDED(hr)) { VARIANT v; VariantInit(&v); V_VT(&v) = VT_UI1; - V_UNION(&v, bVal) = WICTiffCompressionDontCare; - hr = IPropertyBag2_Write(*ppIEncoderOptions, 1, opts, &v); + V_UI1(&v) = WICTiffCompressionDontCare; + hr = IPropertyBag2_Write(*ppIEncoderOptions, 1, (PROPBAG2 *)opts, &v); VariantClear(&v); if (FAILED(hr)) { diff --git a/dll/win32/windowscodecs/ungif.c b/dll/win32/windowscodecs/ungif.c index 28d76e5acef..c6711c8e24c 100644 --- a/dll/win32/windowscodecs/ungif.c +++ b/dll/win32/windowscodecs/ungif.c @@ -47,9 +47,16 @@ * 3 Sep 90 - Version 1.1 by Gershon Elber (Support for Gif89, Unique names). *****************************************************************************/ -#include "wincodecs_private.h" +#include +#include +#include +#include "windef.h" +#include "winbase.h" #include "ungif.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); static void *ungif_alloc( size_t sz ) { diff --git a/dll/win32/windowscodecs/wincodecs_private.h b/dll/win32/windowscodecs/wincodecs_private.h index 99daf093ad2..2f9f6d0b583 100644 --- a/dll/win32/windowscodecs/wincodecs_private.h +++ b/dll/win32/windowscodecs/wincodecs_private.h @@ -19,33 +19,9 @@ #ifndef WINCODECS_PRIVATE_H #define WINCODECS_PRIVATE_H -#include -#include - -#include - -#define WIN32_NO_STATUS -#define _INC_WINDOWS -#define COM_NO_WINDOWS_H - -#define COBJMACROS -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); +#include "wincodec.h" +#include "wincodecsdk.h" +#include "wine/unicode.h" DEFINE_GUID(CLSID_WineTgaDecoder, 0xb11fc79a,0x67cc,0x43e6,0xa9,0xce,0xe3,0xd5,0x49,0x45,0xd3,0x04); @@ -55,7 +31,13 @@ DEFINE_GUID(GUID_WineContainerFormatTga, 0x0c44fda1,0xa5c5,0x4298,0x96,0x85,0x47 DEFINE_GUID(GUID_VendorWine, 0xddf46da1,0x7dc1,0x404e,0x98,0xf2,0xef,0xa4,0x8d,0xfc,0x95,0x0a); +DEFINE_GUID(IID_IMILBitmap,0xb1784d3f,0x8115,0x4763,0x13,0xaa,0x32,0xed,0xdb,0x68,0x29,0x4a); DEFINE_GUID(IID_IMILBitmapSource,0x7543696a,0xbc8d,0x46b0,0x5f,0x81,0x8d,0x95,0x72,0x89,0x72,0xbe); +DEFINE_GUID(IID_IMILBitmapLock,0xa67b2b53,0x8fa1,0x4155,0x8f,0x64,0x0c,0x24,0x7a,0x8f,0x84,0xcd); +DEFINE_GUID(IID_IMILBitmapScaler,0xa767b0f0,0x1c8c,0x4aef,0x56,0x8f,0xad,0xf9,0x6d,0xcf,0xd5,0xcb); +DEFINE_GUID(IID_IMILFormatConverter,0x7e2a746f,0x25c5,0x4851,0xb3,0xaf,0x44,0x3b,0x79,0x63,0x9e,0xc0); +DEFINE_GUID(IID_IMILPalette,0xca8e206f,0xf22c,0x4af7,0x6f,0xba,0x7b,0xed,0x5e,0xb1,0xc9,0x2f); + #define INTERFACE IMILBitmapSource DECLARE_INTERFACE_(IMILBitmapSource,IUnknown) { @@ -63,16 +45,58 @@ DECLARE_INTERFACE_(IMILBitmapSource,IUnknown) STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID,void **) PURE; STDMETHOD_(ULONG,AddRef)(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IWICBitmapSource methods ***/ + STDMETHOD_(HRESULT,GetSize)(THIS_ UINT *,UINT *) PURE; + STDMETHOD_(HRESULT,GetPixelFormat)(THIS_ int *) PURE; + STDMETHOD_(HRESULT,GetResolution)(THIS_ double *,double *) PURE; + STDMETHOD_(HRESULT,CopyPalette)(THIS_ IWICPalette *) PURE; + STDMETHOD_(HRESULT,CopyPixels)(THIS_ const WICRect *,UINT,UINT,BYTE *) PURE; /*** IMILBitmapSource methods ***/ - STDMETHOD_(HRESULT,GetSize)(THIS_ UINT *,UINT *); - STDMETHOD_(HRESULT,GetPixelFormat)(THIS_ int *); - STDMETHOD_(HRESULT,GetResolution)(THIS_ double *,double *); - STDMETHOD_(HRESULT,CopyPalette)(THIS_ IWICPalette *); - STDMETHOD_(HRESULT,CopyPixels)(THIS_ const WICRect *,UINT,UINT,BYTE *); - STDMETHOD_(HRESULT,UnknownMethod1)(THIS_ void **); + STDMETHOD_(HRESULT,unknown1)(THIS_ void **) PURE; + STDMETHOD_(HRESULT,Lock)(THIS_ const WICRect *,DWORD,IWICBitmapLock **) PURE; + STDMETHOD_(HRESULT,Unlock)(THIS_ IWICBitmapLock *) PURE; + STDMETHOD_(HRESULT,SetPalette)(THIS_ IWICPalette *) PURE; + STDMETHOD_(HRESULT,SetResolution)(THIS_ double,double) PURE; + STDMETHOD_(HRESULT,AddDirtyRect)(THIS_ const WICRect *) PURE; }; #undef INTERFACE +#define INTERFACE IMILBitmapScaler +DECLARE_INTERFACE_(IMILBitmapScaler,IUnknown) +{ + /*** IUnknown methods ***/ + STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID,void **) PURE; + STDMETHOD_(ULONG,AddRef)(THIS) PURE; + STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** IWICBitmapSource methods ***/ + STDMETHOD_(HRESULT,GetSize)(THIS_ UINT *,UINT *) PURE; + STDMETHOD_(HRESULT,GetPixelFormat)(THIS_ int *) PURE; + STDMETHOD_(HRESULT,GetResolution)(THIS_ double *,double *) PURE; + STDMETHOD_(HRESULT,CopyPalette)(THIS_ IWICPalette *) PURE; + STDMETHOD_(HRESULT,CopyPixels)(THIS_ const WICRect *,UINT,UINT,BYTE *) PURE; + /*** IMILBitmapScaler methods ***/ + STDMETHOD_(HRESULT,unknown1)(THIS_ void **) PURE; + STDMETHOD_(HRESULT,Initialize)(THIS_ IMILBitmapSource *,UINT,UINT,WICBitmapInterpolationMode); +}; +#undef INTERFACE + +#ifdef __i386__ /* thiscall functions are i386-specific */ + +#define THISCALL(func) __thiscall_ ## func +#define DEFINE_THISCALL_WRAPPER(func,args) \ + extern typeof(func) THISCALL(func); \ + __ASM_STDCALL_FUNC(__thiscall_ ## func, args, \ + "popl %eax\n\t" \ + "pushl %ecx\n\t" \ + "pushl %eax\n\t" \ + "jmp " __ASM_NAME(#func) __ASM_STDCALL(args) ) +#else /* __i386__ */ + +#define THISCALL(func) func +#define DEFINE_THISCALL_WRAPPER(func,args) /* nothing */ + +#endif /* __i386__ */ + #define INTERFACE IMILUnknown1 DECLARE_INTERFACE_(IMILUnknown1,IUnknown) { @@ -80,6 +104,19 @@ DECLARE_INTERFACE_(IMILUnknown1,IUnknown) STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID,void **) PURE; STDMETHOD_(ULONG,AddRef)(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; + /*** thiscall method ***/ + STDMETHOD_(void,unknown1)(THIS_ void*) PURE; + /*** stdcall ***/ + STDMETHOD_(HRESULT,unknown2)(THIS_ void*, void*) PURE; + /*** thiscall method ***/ + STDMETHOD_(HRESULT,unknown3)(THIS_ void*) PURE; + /*** stdcall ***/ + STDMETHOD_(HRESULT,unknown4)(THIS_ void*) PURE; + STDMETHOD_(HRESULT,unknown5)(THIS_ void*) PURE; + STDMETHOD_(HRESULT,unknown6)(THIS_ DWORD64) PURE; + STDMETHOD_(HRESULT,unknown7)(THIS_ void*) PURE; + /*** thiscall method ***/ + STDMETHOD_(HRESULT,unknown8)(THIS) PURE; }; #undef INTERFACE @@ -91,7 +128,9 @@ DECLARE_INTERFACE_(IMILUnknown2,IUnknown) STDMETHOD_(ULONG,AddRef)(THIS) PURE; STDMETHOD_(ULONG,Release)(THIS) PURE; /*** unknown methods ***/ - STDMETHOD_(HRESULT,UnknownMethod1)(THIS_ void *, void *) PURE; + STDMETHOD_(HRESULT,unknown1)(THIS_ void *,void **) PURE; + STDMETHOD_(HRESULT,unknown2)(THIS_ void *,void *) PURE; + STDMETHOD_(HRESULT,unknown3)(THIS_ void *) PURE; }; #undef INTERFACE @@ -106,6 +145,7 @@ extern HRESULT PngEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN extern HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT DibDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT GifDecoder_CreateInstance(REFIID riid, void** ppv) DECLSPEC_HIDDEN; +extern HRESULT GifEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT IcoDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT JpegDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT JpegEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; @@ -144,7 +184,7 @@ extern void reverse_bgr8(UINT bytesperpixel, LPBYTE bits, UINT width, UINT heigh extern HRESULT get_pixelformat_bpp(const GUID *pixelformat, UINT *bpp) DECLSPEC_HIDDEN; -extern HRESULT CreatePropertyBag2(PROPBAG2 *options, UINT count, +extern HRESULT CreatePropertyBag2(const PROPBAG2 *options, UINT count, IPropertyBag2 **property) DECLSPEC_HIDDEN; extern HRESULT CreateComponentInfo(REFCLSID clsid, IWICComponentInfo **ppIInfo) DECLSPEC_HIDDEN; diff --git a/dll/win32/windowscodecs/windowscodecs.spec b/dll/win32/windowscodecs/windowscodecs.spec index 8fd2470f11b..424b3075cee 100644 --- a/dll/win32/windowscodecs/windowscodecs.spec +++ b/dll/win32/windowscodecs/windowscodecs.spec @@ -105,7 +105,8 @@ @ stdcall IWICStream_InitializeFromIStream_Proxy(ptr ptr) IWICStream_InitializeFromIStream_Proxy_W @ stdcall IWICStream_InitializeFromMemory_Proxy(ptr ptr long) IWICStream_InitializeFromMemory_Proxy_W @ stdcall WICConvertBitmapSource(ptr ptr ptr) -@ stdcall -stub WICCreateBitmapFromSection(long long ptr long long long ptr) +@ stdcall WICCreateBitmapFromSection(long long ptr long long long ptr) +@ stdcall WICCreateBitmapFromSectionEx(long long ptr long long long long ptr) @ stdcall WICCreateColorContext_Proxy(ptr ptr) @ stdcall WICCreateImagingFactory_Proxy(long ptr) @ stub WICGetMetadataContentSize diff --git a/dll/win32/windowscodecs/windowscodecs_wincodec.idl b/dll/win32/windowscodecs/windowscodecs_wincodec.idl index 33c0d4a5801..fec63d04e13 100644 --- a/dll/win32/windowscodecs/windowscodecs_wincodec.idl +++ b/dll/win32/windowscodecs/windowscodecs_wincodec.idl @@ -76,6 +76,13 @@ coclass WICBmpEncoder { interface IWICBitmapEncoder; } ] coclass WICGifDecoder { interface IWICBitmapDecoder; } +[ + helpstring("WIC GIF Encoder"), + threading(both), + uuid(114f5598-0b22-40a0-86a1-c83ea495adbd) +] +coclass WICGifEncoder { interface IWICBitmapEncoder; } + [ helpstring("WIC ICO Decoder"), threading(both), diff --git a/media/doc/README.WINE b/media/doc/README.WINE index f137ad18a89..d7590c28801 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -196,7 +196,7 @@ reactos/dll/win32/version # Synced to Wine-3.0 reactos/dll/win32/vssapi # Synced to WineStaging-2.9 reactos/dll/win32/wbemdisp # Synced to Wine-3.0 reactos/dll/win32/wbemprox # Synced to Wine-3.0 -reactos/dll/win32/windowscodecs # Synced to Wine-3.0 +reactos/dll/win32/windowscodecs # Synced to WineStaging-3.3 reactos/dll/win32/windowscodecsext # Synced to WineStaging-2.9 reactos/dll/win32/winemp3.acm # Synced to Wine-3.0 reactos/dll/win32/wing32 # Synced to WineStaging-2.9