https://git.reactos.org/?p=reactos.git;a=commitdiff;h=197ed01e95f242af87a390...
commit 197ed01e95f242af87a3905d83c2cd22326a7668 Author: Mikhail Tyukin mishakeys20@gmail.com AuthorDate: Sun Jan 26 12:59:50 2025 -0500 Commit: Hermès Bélusca-Maïto hermes.belusca-maito@reactos.org CommitDate: Fri Feb 7 16:57:02 2025 +0100
[WINDOWSCODECS][WINDOWSCODECSEXT] Sync to wine-10.0 (#7665) --- dll/win32/windowscodecs/CMakeLists.txt | 19 +- dll/win32/windowscodecs/bitmap.c | 55 +- dll/win32/windowscodecs/bmpdecode.c | 82 +- dll/win32/windowscodecs/bmpencode.c | 44 +- dll/win32/windowscodecs/clipper.c | 12 +- dll/win32/windowscodecs/clsfactory.c | 24 +- dll/win32/windowscodecs/colorcontext.c | 24 +- dll/win32/windowscodecs/colortransform.c | 10 +- dll/win32/windowscodecs/converter.c | 276 +- dll/win32/windowscodecs/ddsformat.c | 2162 +++++++++++++ dll/win32/windowscodecs/decoder.c | 811 +++++ dll/win32/windowscodecs/encoder.c | 903 ++++++ dll/win32/windowscodecs/fliprotate.c | 14 +- dll/win32/windowscodecs/gifformat.c | 521 ++-- dll/win32/windowscodecs/icnsformat.c | 743 ----- dll/win32/windowscodecs/icoformat.c | 40 +- dll/win32/windowscodecs/imgfactory.c | 470 ++- dll/win32/windowscodecs/info.c | 309 +- dll/win32/windowscodecs/jpegformat.c | 1562 ---------- dll/win32/windowscodecs/libjpeg.c | 662 ++++ dll/win32/windowscodecs/libpng.c | 842 +++++ dll/win32/windowscodecs/libtiff.c | 1352 +++++++++ dll/win32/windowscodecs/main.c | 230 +- dll/win32/windowscodecs/metadatahandler.c | 295 +- dll/win32/windowscodecs/metadataquery.c | 580 ++-- dll/win32/windowscodecs/palette.c | 56 +- dll/win32/windowscodecs/pngformat.c | 2093 +------------ dll/win32/windowscodecs/precomp.h | 3 +- dll/win32/windowscodecs/propertybag.c | 33 +- dll/win32/windowscodecs/proxy.c | 2 - dll/win32/windowscodecs/regsvr.c | 207 +- dll/win32/windowscodecs/scaler.c | 28 +- dll/win32/windowscodecs/stream.c | 108 +- dll/win32/windowscodecs/tgaformat.c | 34 +- dll/win32/windowscodecs/tiffformat.c | 2385 --------------- dll/win32/windowscodecs/ungif.c | 93 +- dll/win32/windowscodecs/ungif.h | 7 +- dll/win32/windowscodecs/uuid.c | 36 + dll/win32/windowscodecs/wincodecs_common.c | 211 ++ dll/win32/windowscodecs/wincodecs_common.h | 214 ++ dll/win32/windowscodecs/wincodecs_private.h | 325 +- dll/win32/windowscodecs/windowscodecs_wincodec.idl | 32 +- dll/win32/windowscodecsext/main.c | 18 - media/doc/WINESYNC.txt | 4 +- .../winetests/windowscodecs/CMakeLists.txt | 8 +- modules/rostests/winetests/windowscodecs/bitmap.c | 460 +-- .../rostests/winetests/windowscodecs/bmpformat.c | 647 +++- .../rostests/winetests/windowscodecs/converter.c | 578 ++-- .../rostests/winetests/windowscodecs/ddsformat.c | 1579 ++++++++++ .../rostests/winetests/windowscodecs/gifformat.c | 198 +- .../rostests/winetests/windowscodecs/icoformat.c | 20 +- modules/rostests/winetests/windowscodecs/info.c | 263 +- .../rostests/winetests/windowscodecs/jpegformat.c | 38 +- .../rostests/winetests/windowscodecs/metadata.c | 3204 ++++++++++++++------ modules/rostests/winetests/windowscodecs/palette.c | 154 +- .../rostests/winetests/windowscodecs/pngformat.c | 203 +- .../rostests/winetests/windowscodecs/propertybag.c | 56 +- modules/rostests/winetests/windowscodecs/stream.c | 438 +-- .../rostests/winetests/windowscodecs/testlist.c | 4 + .../rostests/winetests/windowscodecs/tiffformat.c | 344 ++- .../rostests/winetests/windowscodecs/wmpformat.c | 182 ++ .../winetests/windowscodecsext/CMakeLists.txt | 1 + .../winetests/windowscodecsext/transform.c | 12 +- sdk/include/psdk/CMakeLists.txt | 1 + sdk/include/psdk/dxgiformat.idl | 145 + sdk/include/psdk/wincodec.idl | 137 + sdk/include/psdk/wincodecsdk.idl | 82 + sdk/tools/winesync/windowscodecs.cfg | 10 + 68 files changed, 16270 insertions(+), 10425 deletions(-)
diff --git a/dll/win32/windowscodecs/CMakeLists.txt b/dll/win32/windowscodecs/CMakeLists.txt index ee7ff716e3b..c8e043b4979 100644 --- a/dll/win32/windowscodecs/CMakeLists.txt +++ b/dll/win32/windowscodecs/CMakeLists.txt @@ -1,12 +1,12 @@
add_definitions( -D__WINESRC__ - -D__ROS_LONG64__ -DENTRY_PREFIX=WIC_ -DPROXY_DELEGATION -DWINE_REGISTER_DLL)
remove_definitions(-D_WIN32_WINNT=0x502) +remove_definitions(-D_CRT_NON_CONFORMING_SWPRINTFS) add_definitions(-D_WIN32_WINNT=0x600)
include_directories( @@ -27,13 +27,17 @@ list(APPEND SOURCE colorcontext.c colortransform.c converter.c + ddsformat.c + decoder.c + encoder.c fliprotate.c gifformat.c - icnsformat.c icoformat.c imgfactory.c info.c - jpegformat.c + libjpeg.c + libpng.c + libtiff.c main.c metadatahandler.c metadataquery.c @@ -45,8 +49,9 @@ list(APPEND SOURCE scaler.c stream.c tgaformat.c - tiffformat.c - ungif.c) + ungif.c + uuid.c + wincodecs_common.c)
if(MSVC) if(ARCH STREQUAL "i386") @@ -79,7 +84,7 @@ if(MSVC) endif()
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) +target_link_libraries(windowscodecs wine uuid ${PSEH_LIB} oldnames) +add_importlibs(windowscodecs libjpeg libpng libtiff ole32 oleaut32 rpcrt4 shlwapi user32 gdi32 advapi32 advapi32_vista propsys msvcrt kernel32 ntdll) add_pch(windowscodecs precomp.h "${PCH_SKIP_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 7959da6911d..dee3f28d5d7 100644 --- a/dll/win32/windowscodecs/bitmap.c +++ b/dll/win32/windowscodecs/bitmap.c @@ -17,10 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#ifndef __REACTOS__ -#include "config.h" -#endif - #include <stdarg.h>
#define COBJMACROS @@ -34,6 +30,9 @@ #include "wine/asm.h" #include "wine/debug.h"
+#include "initguid.h" +DEFINE_GUID(IID_CMetaBitmapRenderTarget, 0x0ccd7824,0xdc16,0x4d09,0xbc,0xa8,0x6b,0x09,0xc4,0xef,0x55,0x35); + WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
/* WARNING: .NET Media Integration Layer (MIL) directly dereferences @@ -82,11 +81,6 @@ static inline BitmapImpl *impl_from_IMILUnknown1(IMILUnknown1 *iface) return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown1_iface); }
-static inline BitmapImpl *impl_from_IMILUnknown2(IMILUnknown2 *iface) -{ - return CONTAINING_RECORD(iface, BitmapImpl, IMILUnknown2_iface); -} - static inline BitmapLockImpl *impl_from_IWICBitmapLock(IWICBitmapLock *iface) { return CONTAINING_RECORD(iface, BitmapLockImpl, IWICBitmapLock_iface); @@ -155,7 +149,7 @@ static ULONG WINAPI BitmapLockImpl_AddRef(IWICBitmapLock *iface) BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -165,13 +159,13 @@ static ULONG WINAPI BitmapLockImpl_Release(IWICBitmapLock *iface) BitmapLockImpl *This = impl_from_IWICBitmapLock(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { BitmapImpl_ReleaseLock(This->parent); IWICBitmap_Release(&This->parent->IWICBitmap_iface); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -262,7 +256,10 @@ static HRESULT WINAPI BitmapImpl_QueryInterface(IWICBitmap *iface, REFIID iid, } else { - FIXME("unknown interface %s\n", debugstr_guid(iid)); + if (IsEqualIID(&IID_CMetaBitmapRenderTarget, iid)) + WARN("Ignoring interface %s\n", debugstr_guid(iid)); + else + FIXME("unknown interface %s\n", debugstr_guid(iid)); *ppv = NULL; return E_NOINTERFACE; } @@ -276,7 +273,7 @@ static ULONG WINAPI BitmapImpl_AddRef(IWICBitmap *iface) BitmapImpl *This = impl_from_IWICBitmap(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -286,7 +283,7 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) BitmapImpl *This = impl_from_IWICBitmap(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { @@ -296,8 +293,8 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) if (This->view) UnmapViewOfFile(This->view); else - HeapFree(GetProcessHeap(), 0, This->data); - HeapFree(GetProcessHeap(), 0, This); + free(This->data); + free(This); }
return ref; @@ -378,7 +375,7 @@ static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock, BitmapLockImpl *result; WICRect rc;
- TRACE("(%p,%s,%x,%p)\n", iface, debug_wic_rect(prcLock), flags, ppILock); + TRACE("(%p,%s,%lx,%p)\n", iface, debug_wic_rect(prcLock), flags, ppILock);
if (!(flags & (WICBitmapLockRead|WICBitmapLockWrite)) || !ppILock) return E_INVALIDARG; @@ -401,13 +398,13 @@ static HRESULT WINAPI BitmapImpl_Lock(IWICBitmap *iface, const WICRect *prcLock, return E_FAIL; }
- result = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapLockImpl)); + result = malloc(sizeof(BitmapLockImpl)); if (!result) return E_OUTOFMEMORY;
if (!BitmapImpl_AcquireLock(This, flags & WICBitmapLockWrite)) { - HeapFree(GetProcessHeap(), 0, result); + free(result); return WINCODEC_ERR_ALREADYLOCKED; }
@@ -605,7 +602,7 @@ static HRESULT WINAPI IMILBitmapImpl_unknown1(IMILBitmap *iface, void **ppv) static HRESULT WINAPI IMILBitmapImpl_Lock(IMILBitmap *iface, const WICRect *rc, DWORD flags, IWICBitmapLock **lock) { BitmapImpl *This = impl_from_IMILBitmap(iface); - TRACE("(%p,%p,%08x,%p)\n", iface, rc, flags, lock); + TRACE("(%p,%p,%08lx,%p)\n", iface, rc, flags, lock); return IWICBitmap_Lock(&This->IWICBitmap_iface, rc, flags, lock); }
@@ -675,7 +672,7 @@ static ULONG WINAPI IMILUnknown1Impl_Release(IMILUnknown1 *iface) return IWICBitmap_Release(&This->IWICBitmap_iface); }
-DECLSPEC_HIDDEN void WINAPI IMILUnknown1Impl_unknown1(IMILUnknown1 *iface, void *arg) +void WINAPI IMILUnknown1Impl_unknown1(IMILUnknown1 *iface, void *arg) { FIXME("(%p,%p): stub\n", iface, arg); } @@ -686,7 +683,7 @@ static HRESULT WINAPI IMILUnknown1Impl_unknown2(IMILUnknown1 *iface, void *arg1, return E_NOTIMPL; }
-DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown3(IMILUnknown1 *iface, void *arg) +HRESULT WINAPI IMILUnknown1Impl_unknown3(IMILUnknown1 *iface, void *arg) { FIXME("(%p,%p): stub\n", iface, arg); return E_NOTIMPL; @@ -716,7 +713,7 @@ static HRESULT WINAPI IMILUnknown1Impl_unknown7(IMILUnknown1 *iface, void *arg) return E_NOTIMPL; }
-DECLSPEC_HIDDEN HRESULT WINAPI IMILUnknown1Impl_unknown8(IMILUnknown1 *iface) +HRESULT WINAPI IMILUnknown1Impl_unknown8(IMILUnknown1 *iface) { FIXME("(%p): stub\n", iface); return E_NOTIMPL; @@ -808,13 +805,13 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasiz if (datasize < stride * uiHeight) return WINCODEC_ERR_INSUFFICIENTBUFFER; if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); + This = malloc(sizeof(BitmapImpl)); if (!This) return E_OUTOFMEMORY;
if (view) data = (BYTE *)view + offset; - else if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize))) + else if (!(data = calloc(1, datasize))) { - HeapFree(GetProcessHeap(), 0, This); + free(This); return E_OUTOFMEMORY; }
@@ -835,7 +832,11 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasiz This->bpp = bpp; memcpy(&This->pixelformat, pixelFormat, sizeof(GUID)); This->dpix = This->dpiy = 0.0; +#ifdef __REACTOS__ InitializeCriticalSection(&This->cs); +#else + InitializeCriticalSectionEx(&This->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif This->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapImpl.lock");
*ppIBitmap = &This->IWICBitmap_iface; diff --git a/dll/win32/windowscodecs/bmpdecode.c b/dll/win32/windowscodecs/bmpdecode.c index 5ee4ac38ccb..9eb74b3d7cc 100644 --- a/dll/win32/windowscodecs/bmpdecode.c +++ b/dll/win32/windowscodecs/bmpdecode.c @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <assert.h> #include <stdarg.h>
@@ -226,9 +224,9 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, int i;
count = 1 << bch->bcBitCount; - wiccolors = HeapAlloc(GetProcessHeap(), 0, sizeof(WICColor) * count); + wiccolors = malloc(sizeof(WICColor) * count); tablesize = sizeof(RGBTRIPLE) * count; - bgrcolors = HeapAlloc(GetProcessHeap(), 0, tablesize); + bgrcolors = malloc(tablesize); if (!wiccolors || !bgrcolors) { hr = E_OUTOFMEMORY; @@ -274,7 +272,7 @@ static HRESULT WINAPI BmpFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, count = min(This->bih.bV5ClrUsed, 1 << This->bih.bV5BitCount);
tablesize = sizeof(WICColor) * count; - wiccolors = HeapAlloc(GetProcessHeap(), 0, tablesize); + wiccolors = malloc(tablesize); if (!wiccolors) { hr = E_OUTOFMEMORY; @@ -310,8 +308,8 @@ end: if (SUCCEEDED(hr)) hr = IWICPalette_InitializeCustom(pIPalette, wiccolors, count);
- HeapFree(GetProcessHeap(), 0, wiccolors); - HeapFree(GetProcessHeap(), 0, bgrcolors); + free(wiccolors); + free(bgrcolors); return hr; }
@@ -388,7 +386,7 @@ static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This) bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; datasize = bytesperrow * height;
- This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); + This->imagedata = malloc(datasize); if (!This->imagedata) return E_OUTOFMEMORY;
offbits.QuadPart = This->image_offset; @@ -411,12 +409,45 @@ static HRESULT BmpFrameDecode_ReadUncompressed(BmpDecoder* This) return S_OK;
fail: - HeapFree(GetProcessHeap(), 0, This->imagedata); + free(This->imagedata); This->imagedata = NULL; if (SUCCEEDED(hr)) hr = E_FAIL; return hr; }
+static HRESULT BmpFrameDecode_ReadABGRasBGR(BmpDecoder* This) +{ + UINT x, y, width, height; + BYTE *pixel; + HRESULT hr; + + hr = IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height); + + if (SUCCEEDED(hr)) + { + hr = BmpFrameDecode_ReadUncompressed(This); + } + + if (SUCCEEDED(hr)) + { + for (y = 0; y < height; y++) + { + pixel = This->imagedatastart + This->stride * (INT)y; + + for (x = 0; x < width; x++) + { + pixel[0] = pixel[1]; + pixel[1] = pixel[2]; + pixel[2] = pixel[3]; + pixel[3] = 0; + pixel += 4; + } + } + } + + return hr; +} + static HRESULT BmpFrameDecode_ReadRGB8(BmpDecoder* This) { HRESULT hr; @@ -482,7 +513,7 @@ static HRESULT BmpFrameDecode_ReadRLE8(BmpDecoder* This) else palettesize = 4 * 256;
- This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); + This->imagedata = malloc(datasize); if (!This->imagedata) { hr = E_OUTOFMEMORY; @@ -578,7 +609,7 @@ end: return S_OK;
fail: - HeapFree(GetProcessHeap(), 0, This->imagedata); + free(This->imagedata); This->imagedata = NULL; if (SUCCEEDED(hr)) hr = E_FAIL; return hr; @@ -606,7 +637,7 @@ static HRESULT BmpFrameDecode_ReadRLE4(BmpDecoder* This) else palettesize = 4 * 16;
- This->imagedata = HeapAlloc(GetProcessHeap(), 0, datasize); + This->imagedata = malloc(datasize); if (!This->imagedata) { hr = E_OUTOFMEMORY; @@ -718,7 +749,7 @@ end: return S_OK;
fail: - HeapFree(GetProcessHeap(), 0, This->imagedata); + free(This->imagedata); This->imagedata = NULL; if (SUCCEEDED(hr)) hr = E_FAIL; return hr; @@ -744,7 +775,7 @@ static const struct bitfields_format bitfields_formats[] = { {16,0xf800,0x7e0,0x1f,0,&GUID_WICPixelFormat16bppBGR565,BmpFrameDecode_ReadUncompressed}, {32,0xff0000,0xff00,0xff,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadUncompressed}, {32,0xff0000,0xff00,0xff,0xff000000,&GUID_WICPixelFormat32bppBGRA,BmpFrameDecode_ReadUncompressed}, - {32,0xff000000,0xff0000,0xff00,0xff,&GUID_WICPixelFormat32bppRGBA,BmpFrameDecode_ReadUncompressed}, + {32,0xff000000,0xff0000,0xff00,0xff,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadABGRasBGR}, {32,0xff,0xff00,0xff0000,0,&GUID_WICPixelFormat32bppBGR,BmpFrameDecode_ReadRGB8}, {0} }; @@ -861,7 +892,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) } else /* struct is compatible with BITMAPINFOHEADER */ { - TRACE("bitmap header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); + TRACE("bitmap header=%li compression=%li depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); switch(This->bih.bV5Compression) { case BI_RGB: @@ -935,7 +966,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) { This->read_data_func = BmpFrameDecode_ReadUncompressed; This->pixelformat = &GUID_WICPixelFormatUndefined; - FIXME("unsupported bitfields type depth=%i red=%x green=%x blue=%x alpha=%x\n", + FIXME("unsupported bitfields type depth=%i red=%lx green=%lx blue=%lx alpha=%lx\n", This->bih.bV5BitCount, This->bih.bV5RedMask, This->bih.bV5GreenMask, This->bih.bV5BlueMask, This->bih.bV5AlphaMask); } break; @@ -944,7 +975,7 @@ static HRESULT BmpDecoder_ReadHeaders(BmpDecoder* This, IStream *stream) This->bitsperpixel = 0; This->read_data_func = BmpFrameDecode_ReadUnsupported; This->pixelformat = &GUID_WICPixelFormatUndefined; - FIXME("unsupported bitmap type header=%i compression=%i depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); + FIXME("unsupported bitmap type header=%li compression=%li depth=%i\n", This->bih.bV5Size, This->bih.bV5Compression, This->bih.bV5BitCount); break; } } @@ -999,7 +1030,7 @@ static ULONG WINAPI BmpDecoder_AddRef(IWICBitmapDecoder *iface) BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -1009,15 +1040,15 @@ static ULONG WINAPI BmpDecoder_Release(IWICBitmapDecoder *iface) BmpDecoder *This = impl_from_IWICBitmapDecoder(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { if (This->stream) IStream_Release(This->stream); - HeapFree(GetProcessHeap(), 0, This->imagedata); + free(This->imagedata); This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -1155,7 +1186,7 @@ static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecode { BmpDecoder *This;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpDecoder)); + This = malloc(sizeof(BmpDecoder)); if (!This) return E_OUTOFMEMORY;
This->IWICBitmapDecoder_iface.lpVtbl = &BmpDecoder_Vtbl; @@ -1164,7 +1195,11 @@ static HRESULT BmpDecoder_Create(int packed, int icoframe, BmpDecoder **ppDecode This->initialized = FALSE; This->stream = NULL; This->imagedata = NULL; +#ifdef __REACTOS__ InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BmpDecoder.lock"); This->packed = packed; This->icoframe = icoframe; @@ -1220,7 +1255,8 @@ void BmpDecoder_FindIconMask(BmpDecoder *This, ULONG *mask_offset, int *topdown) if (This->read_data_func == BmpFrameDecode_ReadUncompressed) { /* RGB or BITFIELDS data */ - ULONG width, height, bytesperrow, datasize; + UINT width, height; + ULONG bytesperrow, datasize; IWICBitmapFrameDecode_GetSize(&This->IWICBitmapFrameDecode_iface, &width, &height); bytesperrow = (((width * This->bitsperpixel)+31)/32)*4; datasize = bytesperrow * height; diff --git a/dll/win32/windowscodecs/bmpencode.c b/dll/win32/windowscodecs/bmpencode.c index 3b77517a8d9..28da4a5e6d2 100644 --- a/dll/win32/windowscodecs/bmpencode.c +++ b/dll/win32/windowscodecs/bmpencode.c @@ -17,8 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <stdarg.h>
#define COBJMACROS @@ -56,10 +54,7 @@ static const struct bmp_pixelformat formats[] = { {&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, 0, BI_BITFIELDS, 0xff0000, 0xff00, 0xff, 0xff000000}, -#endif {NULL} };
@@ -79,8 +74,6 @@ 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); @@ -114,7 +107,7 @@ static ULONG WINAPI BmpFrameEncode_AddRef(IWICBitmapFrameEncode *iface) BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -124,13 +117,13 @@ static ULONG WINAPI BmpFrameEncode_Release(IWICBitmapFrameEncode *iface) BmpFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { if (This->stream) IStream_Release(This->stream); - HeapFree(GetProcessHeap(), 0, This->bits); - HeapFree(GetProcessHeap(), 0, This); + free(This->bits); + free(This); }
return ref; @@ -253,7 +246,7 @@ static HRESULT BmpFrameEncode_AllocateBits(BmpFrameEncode *This) return WINCODEC_ERR_WRONGSTATE;
This->stride = (((This->width * This->format->bpp)+31)/32)*4; - This->bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->stride * This->height); + This->bits = calloc(This->stride, This->height); if (!This->bits) return E_OUTOFMEMORY; }
@@ -316,7 +309,8 @@ static HRESULT WINAPI BmpFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, if (SUCCEEDED(hr)) { hr = write_source(iface, pIBitmapSource, prc, - This->format->guid, This->format->bpp, This->width, This->height); + This->format->guid, This->format->bpp, !This->colors && This->format->colors, + This->width, This->height); }
return hr; @@ -400,10 +394,16 @@ static HRESULT WINAPI BmpFrameEncode_Commit(IWICBitmapFrameEncode *iface) }
static HRESULT WINAPI BmpFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, - IWICMetadataQueryWriter **ppIMetadataQueryWriter) + IWICMetadataQueryWriter **query_writer) { - FIXME("(%p, %p): stub\n", iface, ppIMetadataQueryWriter); - return E_NOTIMPL; + BmpFrameEncode *encoder = impl_from_IWICBitmapFrameEncode(iface); + + TRACE("iface %p, query_writer %p.\n", iface, query_writer); + + if (!encoder->initialized) + return WINCODEC_ERR_NOTINITIALIZED; + + return WINCODEC_ERR_UNSUPPORTEDOPERATION; }
static const IWICBitmapFrameEncodeVtbl BmpFrameEncode_Vtbl = { @@ -463,7 +463,7 @@ static ULONG WINAPI BmpEncoder_AddRef(IWICBitmapEncoder *iface) BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -473,13 +473,13 @@ static ULONG WINAPI BmpEncoder_Release(IWICBitmapEncoder *iface) BmpEncoder *This = impl_from_IWICBitmapEncoder(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { if (This->stream) IStream_Release(This->stream); if (This->frame) IWICBitmapFrameEncode_Release(&This->frame->IWICBitmapFrameEncode_iface); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -563,7 +563,7 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface, HRESULT hr; static const PROPBAG2 opts[1] = { - { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)wszEnableV5Header32bppBGRA }, + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"EnableV5Header32bppBGRA" }, };
TRACE("(%p,%p,%p)\n", iface, ppIFrameEncode, ppIEncoderOptions); @@ -578,7 +578,7 @@ static HRESULT WINAPI BmpEncoder_CreateNewFrame(IWICBitmapEncoder *iface, if (FAILED(hr)) return hr; }
- encode = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpFrameEncode)); + encode = malloc(sizeof(BmpFrameEncode)); if (!encode) { IPropertyBag2_Release(*ppIEncoderOptions); @@ -648,7 +648,7 @@ HRESULT BmpEncoder_CreateInstance(REFIID iid, void** ppv)
*ppv = NULL;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(BmpEncoder)); + This = malloc(sizeof(BmpEncoder)); if (!This) return E_OUTOFMEMORY;
This->IWICBitmapEncoder_iface.lpVtbl = &BmpEncoder_Vtbl; diff --git a/dll/win32/windowscodecs/clipper.c b/dll/win32/windowscodecs/clipper.c index 02e0d967f52..b4b2c23ee45 100644 --- a/dll/win32/windowscodecs/clipper.c +++ b/dll/win32/windowscodecs/clipper.c @@ -72,7 +72,7 @@ static ULONG WINAPI BitmapClipper_AddRef(IWICBitmapClipper *iface) BitmapClipper *This = impl_from_IWICBitmapClipper(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -82,14 +82,14 @@ static ULONG WINAPI BitmapClipper_Release(IWICBitmapClipper *iface) BitmapClipper *This = impl_from_IWICBitmapClipper(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { This->lock.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->lock); if (This->source) IWICBitmapSource_Release(This->source); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -244,13 +244,17 @@ HRESULT BitmapClipper_Create(IWICBitmapClipper **clipper) { BitmapClipper *This;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapClipper)); + This = malloc(sizeof(BitmapClipper)); if (!This) return E_OUTOFMEMORY;
This->IWICBitmapClipper_iface.lpVtbl = &BitmapClipper_Vtbl; This->ref = 1; This->source = NULL; +#ifdef __REACTOS__ InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BitmapClipper.lock");
*clipper = &This->IWICBitmapClipper_iface; diff --git a/dll/win32/windowscodecs/clsfactory.c b/dll/win32/windowscodecs/clsfactory.c index 2de518a00c1..87b77c9c089 100644 --- a/dll/win32/windowscodecs/clsfactory.c +++ b/dll/win32/windowscodecs/clsfactory.c @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <stdarg.h>
#define COBJMACROS @@ -27,6 +25,8 @@ #include "winreg.h" #include "objbase.h" #include "ocidl.h" +#include "wincodec.h" +#include "wincodecsdk.h" #include "initguid.h"
#include "wincodecs_private.h" @@ -35,7 +35,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs);
-extern HRESULT WINAPI WIC_DllGetClassObject(REFCLSID, REFIID, LPVOID *) DECLSPEC_HIDDEN; +extern HRESULT WINAPI WIC_DllGetClassObject(REFCLSID, REFIID, LPVOID *);
typedef struct { REFCLSID classid; @@ -47,6 +47,7 @@ static const classinfo wic_classes[] = { {&CLSID_WICImagingFactory2, ImagingFactory_CreateInstance}, {&CLSID_WICBmpDecoder, BmpDecoder_CreateInstance}, {&CLSID_WICPngDecoder, PngDecoder_CreateInstance}, + {&CLSID_WICPngDecoder2, PngDecoder_CreateInstance}, {&CLSID_WICPngEncoder, PngEncoder_CreateInstance}, {&CLSID_WICBmpEncoder, BmpEncoder_CreateInstance}, {&CLSID_WICGifDecoder, GifDecoder_CreateInstance}, @@ -56,14 +57,17 @@ static const classinfo wic_classes[] = { {&CLSID_WICJpegEncoder, JpegEncoder_CreateInstance}, {&CLSID_WICTiffDecoder, TiffDecoder_CreateInstance}, {&CLSID_WICTiffEncoder, TiffEncoder_CreateInstance}, - {&CLSID_WICIcnsEncoder, IcnsEncoder_CreateInstance}, + {&CLSID_WICDdsDecoder, DdsDecoder_CreateInstance}, + {&CLSID_WICDdsEncoder, DdsEncoder_CreateInstance}, {&CLSID_WICDefaultFormatConverter, FormatConverter_CreateInstance}, {&CLSID_WineTgaDecoder, TgaDecoder_CreateInstance}, {&CLSID_WICUnknownMetadataReader, UnknownMetadataReader_CreateInstance}, {&CLSID_WICIfdMetadataReader, IfdMetadataReader_CreateInstance}, {&CLSID_WICPngChrmMetadataReader, PngChrmReader_CreateInstance}, {&CLSID_WICPngGamaMetadataReader, PngGamaReader_CreateInstance}, + {&CLSID_WICPngHistMetadataReader, PngHistReader_CreateInstance}, {&CLSID_WICPngTextMetadataReader, PngTextReader_CreateInstance}, + {&CLSID_WICPngTimeMetadataReader, PngTimeReader_CreateInstance}, {&CLSID_WICLSDMetadataReader, LSDReader_CreateInstance}, {&CLSID_WICIMDMetadataReader, IMDReader_CreateInstance}, {&CLSID_WICGCEMetadataReader, GCEReader_CreateInstance}, @@ -110,7 +114,7 @@ static ULONG WINAPI ClassFactoryImpl_AddRef(IClassFactory *iface) ClassFactoryImpl *This = impl_from_IClassFactory(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -120,10 +124,10 @@ static ULONG WINAPI ClassFactoryImpl_Release(IClassFactory *iface) ClassFactoryImpl *This = impl_from_IClassFactory(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) - HeapFree(GetProcessHeap(), 0, This); + free(This);
return ref; } @@ -161,7 +165,7 @@ static HRESULT ClassFactoryImpl_Constructor(const classinfo *info, REFIID riid,
*ppv = NULL;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(ClassFactoryImpl)); + This = malloc(sizeof(ClassFactoryImpl)); if (!This) return E_OUTOFMEMORY;
This->IClassFactory_iface.lpVtbl = &ClassFactoryImpl_Vtbl; @@ -201,11 +205,11 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) else ret = WIC_DllGetClassObject(rclsid, iid, ppv);
- TRACE("<-- %08X\n", ret); + TRACE("<-- %08lX\n", ret); return ret; }
-HRESULT create_instance(CLSID *clsid, const IID *iid, void **ppv) +HRESULT create_instance(const CLSID *clsid, const IID *iid, void **ppv) { int i;
diff --git a/dll/win32/windowscodecs/colorcontext.c b/dll/win32/windowscodecs/colorcontext.c index eb13482cf43..a52e4e06eb7 100644 --- a/dll/win32/windowscodecs/colorcontext.c +++ b/dll/win32/windowscodecs/colorcontext.c @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <stdarg.h>
#define COBJMACROS @@ -74,7 +72,7 @@ static ULONG WINAPI ColorContext_AddRef(IWICColorContext *iface) ColorContext *This = impl_from_IWICColorContext(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -84,12 +82,12 @@ static ULONG WINAPI ColorContext_Release(IWICColorContext *iface) ColorContext *This = impl_from_IWICColorContext(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { - HeapFree(GetProcessHeap(), 0, This->profile); - HeapFree(GetProcessHeap(), 0, This); + free(This->profile); + free(This); }
return ref; @@ -118,7 +116,7 @@ static HRESULT load_profile(const WCHAR *filename, BYTE **profile, UINT *len) CloseHandle(handle); return E_FAIL; } - if (!(*profile = HeapAlloc(GetProcessHeap(), 0, size.u.LowPart))) + if (!(*profile = malloc(size.u.LowPart))) { CloseHandle(handle); return E_OUTOFMEMORY; @@ -126,12 +124,12 @@ static HRESULT load_profile(const WCHAR *filename, BYTE **profile, UINT *len) ret = ReadFile(handle, *profile, size.u.LowPart, &count, NULL); CloseHandle(handle); if (!ret) { - HeapFree (GetProcessHeap(),0,*profile); + free(*profile); *profile = NULL; return HRESULT_FROM_WIN32(GetLastError()); } if (count != size.u.LowPart) { - HeapFree (GetProcessHeap(),0,*profile); + free(*profile); *profile = NULL; return E_FAIL; } @@ -156,7 +154,7 @@ static HRESULT WINAPI ColorContext_InitializeFromFilename(IWICColorContext *ifac hr = load_profile(wzFilename, &profile, &len); if (FAILED(hr)) return hr;
- HeapFree(GetProcessHeap(), 0, This->profile); + free(This->profile); This->profile = profile; This->profile_len = len; This->type = WICColorContextProfile; @@ -174,10 +172,10 @@ static HRESULT WINAPI ColorContext_InitializeFromMemory(IWICColorContext *iface, if (This->type != WICColorContextUninitialized && This->type != WICColorContextProfile) return WINCODEC_ERR_WRONGSTATE;
- if (!(profile = HeapAlloc(GetProcessHeap(), 0, cbBufferSize))) return E_OUTOFMEMORY; + if (!(profile = malloc(cbBufferSize))) return E_OUTOFMEMORY; memcpy(profile, pbBuffer, cbBufferSize);
- HeapFree(GetProcessHeap(), 0, This->profile); + free(This->profile); This->profile = profile; This->profile_len = cbBufferSize; This->type = WICColorContextProfile; @@ -261,7 +259,7 @@ HRESULT ColorContext_Create(IWICColorContext **colorcontext)
if (!colorcontext) return E_INVALIDARG;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(ColorContext)); + This = malloc(sizeof(ColorContext)); if (!This) return E_OUTOFMEMORY;
This->IWICColorContext_iface.lpVtbl = &ColorContext_Vtbl; diff --git a/dll/win32/windowscodecs/colortransform.c b/dll/win32/windowscodecs/colortransform.c index af66c67443d..9a392d6dc0c 100644 --- a/dll/win32/windowscodecs/colortransform.c +++ b/dll/win32/windowscodecs/colortransform.c @@ -16,8 +16,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <stdarg.h>
#define COBJMACROS @@ -72,7 +70,7 @@ static ULONG WINAPI ColorTransform_AddRef(IWICColorTransform *iface) ColorTransform *This = impl_from_IWICColorTransform(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -82,12 +80,12 @@ static ULONG WINAPI ColorTransform_Release(IWICColorTransform *iface) ColorTransform *This = impl_from_IWICColorTransform(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { if (This->dst) IWICBitmapSource_Release(This->dst); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -177,7 +175,7 @@ HRESULT ColorTransform_Create(IWICColorTransform **colortransform)
if (!colortransform) return E_INVALIDARG;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(ColorTransform)); + This = malloc(sizeof(ColorTransform)); if (!This) return E_OUTOFMEMORY;
This->IWICColorTransform_iface.lpVtbl = &ColorTransform_Vtbl; diff --git a/dll/win32/windowscodecs/converter.c b/dll/win32/windowscodecs/converter.c index cac2ac1aa5a..2156e0aec8f 100644 --- a/dll/win32/windowscodecs/converter.c +++ b/dll/win32/windowscodecs/converter.c @@ -17,8 +17,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
-#include "config.h" - #include <stdarg.h> #include <math.h>
@@ -30,7 +28,6 @@
#include "wincodecs_private.h"
-#include "wine/heap.h" #include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); @@ -71,6 +68,7 @@ struct pixelformatinfo { enum pixelformat format; const WICPixelFormatGUID *guid; copyfunc copy_function; + BOOL is_indexed_format; };
typedef struct FormatConverter { @@ -176,7 +174,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = (prc->Width+7)/8; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -205,7 +203,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -243,7 +241,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = (prc->Width+3)/4; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -268,7 +266,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -306,7 +304,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = (prc->Width+1)/2; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -329,7 +327,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -349,7 +347,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -371,7 +369,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -405,7 +403,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -424,7 +422,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -444,7 +442,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = prc->Width * 2; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -467,7 +465,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -487,7 +485,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 2 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -515,7 +513,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -535,7 +533,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 2 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -563,7 +561,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -583,7 +581,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 2 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -611,7 +609,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -631,7 +629,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 3 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -654,7 +652,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -675,7 +673,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 3 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -702,7 +700,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -728,7 +726,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe HRESULT res; res = IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); if (FAILED(res)) return res; - convert_rgba_to_bgra(4, pbBuffer, prc->Width, prc->Height, cbStride); + reverse_bgr8(4, pbBuffer, prc->Width, prc->Height, cbStride); } return S_OK; case format_32bppBGRA: @@ -772,7 +770,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 6 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -796,7 +794,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -816,7 +814,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe srcstride = 8 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -841,7 +839,7 @@ static HRESULT copypixels_to_32bppBGRA(struct FormatConverter *This, const WICRe } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -985,9 +983,9 @@ static HRESULT copypixels_to_32bppPBGRA(struct FormatConverter *This, const WICR 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; + pbBuffer[cbStride*y+4*x] = (pbBuffer[cbStride*y+4*x] * alpha + 127) / 255; + pbBuffer[cbStride*y+4*x+1] = (pbBuffer[cbStride*y+4*x+1] * alpha + 127) / 255; + pbBuffer[cbStride*y+4*x+2] = (pbBuffer[cbStride*y+4*x+2] * alpha + 127) / 255; } } } @@ -1018,9 +1016,9 @@ static HRESULT copypixels_to_32bppPRGBA(struct FormatConverter *This, const WICR 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; + pbBuffer[cbStride*y+4*x] = (pbBuffer[cbStride*y+4*x] * alpha + 127) / 255; + pbBuffer[cbStride*y+4*x+1] = (pbBuffer[cbStride*y+4*x+1] * alpha + 127) / 255; + pbBuffer[cbStride*y+4*x+2] = (pbBuffer[cbStride*y+4*x+2] * alpha + 127) / 255; } } } @@ -1063,7 +1061,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec srcstride = 4 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -1107,7 +1105,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -1122,7 +1120,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec srcstride = 4 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -1149,7 +1147,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return hr; } @@ -1164,7 +1162,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec srcstride = 4 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = heap_alloc(srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -1192,7 +1190,7 @@ static HRESULT copypixels_to_24bppBGR(struct FormatConverter *This, const WICRec } }
- heap_free(srcdata); + free(srcdata); return hr; } return S_OK; @@ -1238,7 +1236,7 @@ static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRec srcstride = 4 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -1265,7 +1263,7 @@ static HRESULT copypixels_to_24bppRGB(struct FormatConverter *This, const WICRec } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata);
return res; } @@ -1343,7 +1341,7 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec srcstride = 4 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); @@ -1365,7 +1363,7 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata); }
return hr; @@ -1377,7 +1375,7 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec srcstride = 3 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); @@ -1403,7 +1401,7 @@ static HRESULT copypixels_to_8bppGray(struct FormatConverter *This, const WICRec } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata); return hr; }
@@ -1467,7 +1465,7 @@ static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WIC srcstride = 3 * prc->Width; srcdatasize = srcstride * prc->Height;
- srcdata = HeapAlloc(GetProcessHeap(), 0, srcdatasize); + srcdata = malloc(srcdatasize); if (!srcdata) return E_OUTOFMEMORY;
hr = copypixels_to_24bppBGR(This, prc, srcstride, srcdatasize, srcdata, source_format); @@ -1490,15 +1488,138 @@ static HRESULT copypixels_to_8bppIndexed(struct FormatConverter *This, const WIC } }
- HeapFree(GetProcessHeap(), 0, srcdata); + free(srcdata); return hr; }
+static HRESULT copypixels_to_16bppBGRA5551(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + switch (source_format) + { + case format_16bppBGRA5551: + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + return S_OK; + case format_32bppBGRA: + if(prc) + { + HRESULT res; + INT x, y; + BYTE *srcdata; + UINT srcstride, srcdatasize; + const BYTE *srcrow; + const DWORD *srcpixel; + BYTE *dstrow; + DWORD srcval = 0; + WORD *dstpixel; + + int a, r, g, b; + + srcstride = 4 * prc->Width; + srcdatasize = srcstride * prc->Height; + + srcdata = malloc(srcdatasize); + if (!srcdata) return E_OUTOFMEMORY; + + res = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); + if(SUCCEEDED(res)) + { + srcrow = srcdata; + dstrow = pbBuffer; + for(y=0; y< prc->Height; y++) { + srcpixel = (const DWORD*)srcrow; + dstpixel = (WORD *)dstrow; + for(x=0; x<prc->Width; x++) { + srcval=*srcpixel++; + a = (srcval & 0xff000000) >> 24; + r = (srcval & 0x00ff0000) >> 16; + g = (srcval & 0x0000ff00) >> 8; + b = (srcval & 0x000000ff); + a = (a >> 7) << 15; + r = (r >> 3) << 10; + g = (g >> 3) << 5; + b = (b >> 3); + *dstpixel++ = (a|r|g|b); + } + srcrow += srcstride; + dstrow += cbStride; + } + } + free(srcdata); + } + return S_OK; + default: + FIXME("Unimplemented conversion path! %d\n", source_format); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; + } +} + +static HRESULT copypixels_to_64bppRGBA(struct FormatConverter *This, const WICRect *prc, + UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer, enum pixelformat source_format) +{ + HRESULT hr; + + switch (source_format) + { + case format_64bppRGBA: + if (prc) + return IWICBitmapSource_CopyPixels(This->source, prc, cbStride, cbBufferSize, pbBuffer); + return S_OK; + + case format_48bppRGB: + { + UINT srcstride, srcdatasize; + const USHORT *srcpixel; + const BYTE *srcrow; + USHORT *dstpixel; + BYTE *srcdata; + BYTE *dstrow; + INT x, y; + + if (!prc) + return S_OK; + + srcstride = 6 * prc->Width; + srcdatasize = srcstride * prc->Height; + + srcdata = malloc(srcdatasize); + if (!srcdata) return E_OUTOFMEMORY; + + hr = IWICBitmapSource_CopyPixels(This->source, prc, srcstride, srcdatasize, srcdata); + if (SUCCEEDED(hr)) + { + srcrow = srcdata; + dstrow = pbBuffer; + for (y = 0; y < prc->Height; y++) + { + srcpixel = (USHORT *)srcrow; + dstpixel= (USHORT *)dstrow; + for (x = 0; x < prc->Width; x++) + { + *dstpixel++ = *srcpixel++; + *dstpixel++ = *srcpixel++; + *dstpixel++ = *srcpixel++; + *dstpixel++ = 65535; + } + srcrow += srcstride; + dstrow += cbStride; + } + } + free(srcdata); + return hr; + } + default: + FIXME("Unimplemented conversion path %d.\n", source_format); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; + } +} + 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, copypixels_to_8bppIndexed}, + {format_1bppIndexed, &GUID_WICPixelFormat1bppIndexed, NULL, TRUE}, + {format_2bppIndexed, &GUID_WICPixelFormat2bppIndexed, NULL, TRUE}, + {format_4bppIndexed, &GUID_WICPixelFormat4bppIndexed, NULL, TRUE}, + {format_8bppIndexed, &GUID_WICPixelFormat8bppIndexed, copypixels_to_8bppIndexed, TRUE}, {format_BlackWhite, &GUID_WICPixelFormatBlackWhite, NULL}, {format_2bppGray, &GUID_WICPixelFormat2bppGray, NULL}, {format_4bppGray, &GUID_WICPixelFormat4bppGray, NULL}, @@ -1506,7 +1627,7 @@ static const struct pixelformatinfo supported_formats[] = { {format_16bppGray, &GUID_WICPixelFormat16bppGray, NULL}, {format_16bppBGR555, &GUID_WICPixelFormat16bppBGR555, NULL}, {format_16bppBGR565, &GUID_WICPixelFormat16bppBGR565, NULL}, - {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, NULL}, + {format_16bppBGRA5551, &GUID_WICPixelFormat16bppBGRA5551, copypixels_to_16bppBGRA5551}, {format_24bppBGR, &GUID_WICPixelFormat24bppBGR, copypixels_to_24bppBGR}, {format_24bppRGB, &GUID_WICPixelFormat24bppRGB, copypixels_to_24bppRGB}, {format_32bppGrayFloat, &GUID_WICPixelFormat32bppGrayFloat, copypixels_to_32bppGrayFloat}, @@ -1517,7 +1638,7 @@ static const struct pixelformatinfo supported_formats[] = { {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_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, copypixels_to_64bppRGBA}, {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL}, {0} }; @@ -1561,7 +1682,7 @@ static ULONG WINAPI FormatConverter_AddRef(IWICFormatConverter *iface) FormatConverter *This = impl_from_IWICFormatConverter(iface); ULONG ref = InterlockedIncrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
return ref; } @@ -1571,7 +1692,7 @@ static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface) FormatConverter *This = impl_from_IWICFormatConverter(iface); ULONG ref = InterlockedDecrement(&This->ref);
- TRACE("(%p) refcount=%u\n", iface, ref); + TRACE("(%p) refcount=%lu\n", iface, ref);
if (ref == 0) { @@ -1579,7 +1700,7 @@ static ULONG WINAPI FormatConverter_Release(IWICFormatConverter *iface) DeleteCriticalSection(&This->lock); if (This->source) IWICBitmapSource_Release(This->source); if (This->palette) IWICPalette_Release(This->palette); - HeapFree(GetProcessHeap(), 0, This); + free(This); }
return ref; @@ -1638,12 +1759,7 @@ static HRESULT WINAPI FormatConverter_CopyPalette(IWICFormatConverter *iface,
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; + if (This->dst_format->is_indexed_format) return WINCODEC_ERR_WRONGSTATE; return IWICBitmapSource_CopyPalette(This->source, palette); }
@@ -1691,6 +1807,13 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, TRACE("(%p,%p,%s,%u,%p,%0.3f,%u)\n", iface, source, debugstr_guid(dstFormat), dither, palette, alpha_threshold, palette_type);
+ dstinfo = get_formatinfo(dstFormat); + if (!dstinfo) + { + FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat)); + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + if (!palette) { UINT bpp; @@ -1705,18 +1828,21 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, case WICBitmapPaletteTypeCustom: IWICPalette_Release(palette); palette = NULL; - if (bpp <= 8) return E_INVALIDARG; + + /* Indexed types require a palette */ + if (dstinfo->is_indexed_format) + return E_INVALIDARG; break;
case WICBitmapPaletteTypeMedianCut: { - if (bpp <= 8) + if (dstinfo->is_indexed_format) res = IWICPalette_InitializeFromBitmap(palette, source, 1 << bpp, FALSE); break; }
default: - if (bpp <= 8) + if (dstinfo->is_indexed_format) res = IWICPalette_InitializePredefined(palette, palette_type, FALSE); break; } @@ -1749,14 +1875,6 @@ static HRESULT WINAPI FormatConverter_Initialize(IWICFormatConverter *iface, goto end; }
- dstinfo = get_formatinfo(dstFormat); - if (!dstinfo) - { - res = WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; - FIXME("Unsupported destination format %s\n", debugstr_guid(dstFormat)); - goto end; - } - if (dstinfo->copy_function) { IWICBitmapSource_AddRef(source); @@ -1841,14 +1959,18 @@ HRESULT FormatConverter_CreateInstance(REFIID iid, void** ppv)
*ppv = NULL;
- This = HeapAlloc(GetProcessHeap(), 0, sizeof(FormatConverter)); + This = malloc(sizeof(FormatConverter)); if (!This) return E_OUTOFMEMORY;
This->IWICFormatConverter_iface.lpVtbl = &FormatConverter_Vtbl; This->ref = 1; This->source = NULL; This->palette = NULL; +#ifdef __REACTOS__ InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": FormatConverter.lock");
ret = IWICFormatConverter_QueryInterface(&This->IWICFormatConverter_iface, iid, ppv); diff --git a/dll/win32/windowscodecs/ddsformat.c b/dll/win32/windowscodecs/ddsformat.c new file mode 100644 index 00000000000..680febb0d93 --- /dev/null +++ b/dll/win32/windowscodecs/ddsformat.c @@ -0,0 +1,2162 @@ +/* + * Copyright 2020 Ziqing Hui + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * + * Note: + * + * Uncompressed image: + * For uncompressed formats, a block is equivalent to a pixel. + * + * Cube map: + * A cube map is equivalent to a 2D texture array which has 6 textures. + * A cube map array is equivalent to a 2D texture array which has cubeCount*6 textures. + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +#define DDS_MAGIC 0x20534444 +#ifndef MAKEFOURCC +#define MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((DWORD)(BYTE)(ch0) | ((DWORD)(BYTE)(ch1) << 8) | \ + ((DWORD)(BYTE)(ch2) << 16) | ((DWORD)(BYTE)(ch3) << 24 )) +#endif + +#define GET_RGB565_R(color) ((BYTE)(((color) >> 11) & 0x1F)) +#define GET_RGB565_G(color) ((BYTE)(((color) >> 5) & 0x3F)) +#define GET_RGB565_B(color) ((BYTE)(((color) >> 0) & 0x1F)) +#define MAKE_RGB565(r, g, b) ((WORD)(((BYTE)(r) << 11) | ((BYTE)(g) << 5) | (BYTE)(b))) +#define MAKE_ARGB(a, r, g, b) (((DWORD)(a) << 24) | ((DWORD)(r) << 16) | ((DWORD)(g) << 8) | (DWORD)(b)) + +#define DDPF_ALPHAPIXELS 0x00000001 +#define DDPF_ALPHA 0x00000002 +#define DDPF_FOURCC 0x00000004 +#define DDPF_PALETTEINDEXED8 0x00000020 +#define DDPF_RGB 0x00000040 +#define DDPF_LUMINANCE 0x00020000 +#define DDPF_BUMPDUDV 0x00080000 + +#define DDSCAPS2_CUBEMAP 0x00000200 +#define DDSCAPS2_VOLUME 0x00200000 + +#define DDS_DIMENSION_TEXTURE1D 2 +#define DDS_DIMENSION_TEXTURE2D 3 +#define DDS_DIMENSION_TEXTURE3D 4 + +#define DDS_RESOURCE_MISC_TEXTURECUBE 0x00000004 + +#define DDS_BLOCK_WIDTH 4 +#define DDS_BLOCK_HEIGHT 4 + +typedef struct { + DWORD size; + DWORD flags; + DWORD fourCC; + DWORD rgbBitCount; + DWORD rBitMask; + DWORD gBitMask; + DWORD bBitMask; + DWORD aBitMask; +} DDS_PIXELFORMAT; + +typedef struct { + DWORD size; + DWORD flags; + DWORD height; + DWORD width; + DWORD pitchOrLinearSize; + DWORD depth; + DWORD mipMapCount; + DWORD reserved1[11]; + DDS_PIXELFORMAT ddspf; + DWORD caps; + DWORD caps2; + DWORD caps3; + DWORD caps4; + DWORD reserved2; +} DDS_HEADER; + +typedef struct { + DWORD dxgiFormat; + DWORD resourceDimension; + DWORD miscFlag; + DWORD arraySize; + DWORD miscFlags2; +} DDS_HEADER_DXT10; + +typedef struct dds_info { + UINT width; + UINT height; + UINT depth; + UINT mip_levels; + UINT array_size; + UINT frame_count; + UINT data_offset; + UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/ + DXGI_FORMAT format; + WICDdsDimension dimension; + WICDdsAlphaMode alpha_mode; + const GUID *pixel_format; + UINT pixel_format_bpp; +} dds_info; + +typedef struct dds_frame_info { + UINT width; + UINT height; + DXGI_FORMAT format; + UINT bytes_per_block; /* for uncompressed format, this means bytes per pixel*/ + UINT block_width; + UINT block_height; + UINT width_in_blocks; + UINT height_in_blocks; + const GUID *pixel_format; + UINT pixel_format_bpp; +} dds_frame_info; + +typedef struct DdsDecoder { + IWICBitmapDecoder IWICBitmapDecoder_iface; + IWICDdsDecoder IWICDdsDecoder_iface; + IWICWineDecoder IWICWineDecoder_iface; + LONG ref; + BOOL initialized; + IStream *stream; + CRITICAL_SECTION lock; + dds_info info; +} DdsDecoder; + +typedef struct DdsFrameDecode { + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + IWICDdsFrameDecode IWICDdsFrameDecode_iface; + LONG ref; + BYTE *block_data; + BYTE *pixel_data; + CRITICAL_SECTION lock; + dds_frame_info info; +} DdsFrameDecode; + +typedef struct DdsEncoder { + IWICBitmapEncoder IWICBitmapEncoder_iface; + IWICDdsEncoder IWICDdsEncoder_iface; + LONG ref; + CRITICAL_SECTION lock; + IStream *stream; + UINT frame_count; + UINT frame_index; + BOOL uncommitted_frame; + BOOL committed; + dds_info info; +} DdsEncoder; + +typedef struct DdsFrameEncode { + IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; + LONG ref; + DdsEncoder *parent; + BOOL initialized; + BOOL frame_created; + UINT width; + UINT height; + double dpi_x; + double dpi_y; +} DdsFrameEncode; + +static struct dds_format { + DDS_PIXELFORMAT pixel_format; + const GUID *wic_format; + UINT wic_format_bpp; + DXGI_FORMAT dxgi_format; +} dds_format_table[] = { + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC1_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC2_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC2_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppPBGRA, 32, DXGI_FORMAT_BC3_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC3_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_SNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_SNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC4_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_BC5_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_R8G8_B8G8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bpp4Channels, 32, DXGI_FORMAT_G8R8_G8B8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, MAKEFOURCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x24, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6E, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_SNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x6F, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x70, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x71, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x72, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x73, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormatUndefined, 32, DXGI_FORMAT_R32G32_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_FOURCC, 0x74, 0, 0, 0, 0, 0 }, + &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0xFF000000 }, + &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF,0xFF00,0xFF0000,0 }, + &GUID_WICPixelFormat32bppRGB, 32, DXGI_FORMAT_UNKNOWN }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0xFF000000 }, + &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000,0xFF00,0xFF,0 }, + &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM }, + /* The red and blue masks are swapped for DXGI_FORMAT_R10G10B10A2_UNORM. + * For "correct" one, the RGB masks should be 0x3FF,0xFFC00,0x3FF00000. + * see: https://walbourn.github.io/dds-update-and-1010102-problems */ + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF00000,0xFFC00,0x3FF,0xC0000000 }, + &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 32, 0x3FF,0xFFC00,0x3FF00000,0xC0000000 }, + &GUID_WICPixelFormat32bppRGBA1010102, 32, DXGI_FORMAT_R10G10B10A2_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFF,0xFFFF0000,0,0 }, + &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R16G16_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 32, 0xFFFFFFFF,0,0,0 }, + &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0xFF0000,0x00FF00,0x0000FF,0 }, + &GUID_WICPixelFormat24bppBGR, 24, DXGI_FORMAT_UNKNOWN }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB , 0, 24, 0x0000FF,0x00FF00,0xFF0000,0 }, + &GUID_WICPixelFormat24bppRGB, 24, DXGI_FORMAT_UNKNOWN }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF800,0x7E0,0x1F,0 }, + &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0 }, + &GUID_WICPixelFormat16bppBGR555, 16, DXGI_FORMAT_UNKNOWN }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00,0x3E0,0x1F,0x8000 }, + &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_RGB, 0, 16, 0xF00,0xF0,0xF,0xF000 }, + &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_B4G4R4A4_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_ALPHA, 0, 8, 0,0,0,0xFF }, + &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFFFF,0,0,0 }, + &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 16, 0xFF,0,0,0xFF00 }, + &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_R8G8_UNORM }, + { { sizeof(DDS_PIXELFORMAT), DDPF_LUMINANCE, 0, 8, 0xFF,0,0,0 }, + &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM }, + { { 0 }, &GUID_WICPixelFormat8bppAlpha, 8, DXGI_FORMAT_A8_UNORM }, + { { 0 }, &GUID_WICPixelFormat8bppGray, 8, DXGI_FORMAT_R8_UNORM }, + { { 0 }, &GUID_WICPixelFormat16bppGray, 16, DXGI_FORMAT_R16_UNORM }, + { { 0 }, &GUID_WICPixelFormat16bppGrayHalf, 16, DXGI_FORMAT_R16_FLOAT }, + { { 0 }, &GUID_WICPixelFormat16bppBGR565, 16, DXGI_FORMAT_B5G6R5_UNORM }, + { { 0 }, &GUID_WICPixelFormat16bppBGRA5551, 16, DXGI_FORMAT_B5G5R5A1_UNORM }, + { { 0 }, &GUID_WICPixelFormat32bppGrayFloat, 32, DXGI_FORMAT_R32_FLOAT }, + { { 0 }, &GUID_WICPixelFormat32bppRGBA, 32, DXGI_FORMAT_R8G8B8A8_UNORM }, + { { 0 }, &GUID_WICPixelFormat32bppBGRA, 32, DXGI_FORMAT_B8G8R8A8_UNORM }, + { { 0 }, &GUID_WICPixelFormat32bppBGR, 32, DXGI_FORMAT_B8G8R8X8_UNORM }, + { { 0 }, &GUID_WICPixelFormat32bppR10G10B10A2, 32, DXGI_FORMAT_R10G10B10A2_UNORM }, + { { 0 }, &GUID_WICPixelFormat32bppRGBE, 32, DXGI_FORMAT_R9G9B9E5_SHAREDEXP }, + { { 0 }, &GUID_WICPixelFormat32bppRGBA1010102XR, 32, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, + { { 0 }, &GUID_WICPixelFormat64bppRGBA, 64, DXGI_FORMAT_R16G16B16A16_UNORM }, + { { 0 }, &GUID_WICPixelFormat64bppRGBAHalf, 64, DXGI_FORMAT_R16G16B16A16_FLOAT }, + { { 0 }, &GUID_WICPixelFormat96bppRGBFloat, 96, DXGI_FORMAT_R32G32B32_FLOAT }, + { { 0 }, &GUID_WICPixelFormat128bppRGBAFloat, 128, DXGI_FORMAT_R32G32B32A32_FLOAT }, + { { 0 }, &GUID_WICPixelFormatUndefined, 0, DXGI_FORMAT_UNKNOWN } +}; + +static DXGI_FORMAT compressed_formats[] = { + DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB, + DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB, + DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB, + DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM, + DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM, + DXGI_FORMAT_BC6H_TYPELESS, DXGI_FORMAT_BC6H_UF16, DXGI_FORMAT_BC6H_SF16, + DXGI_FORMAT_BC7_TYPELESS, DXGI_FORMAT_BC7_UNORM, DXGI_FORMAT_BC7_UNORM_SRGB +}; + +static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *, UINT, UINT, UINT, IWICBitmapFrameDecode **); + +static DWORD rgb565_to_argb(WORD color, BYTE alpha) +{ + return MAKE_ARGB(alpha, (GET_RGB565_R(color) * 0xFF + 0x0F) / 0x1F, + (GET_RGB565_G(color) * 0xFF + 0x1F) / 0x3F, + (GET_RGB565_B(color) * 0xFF + 0x0F) / 0x1F); +} + +static inline BOOL has_extended_header(DDS_HEADER *header) +{ + return (header->ddspf.flags & DDPF_FOURCC) && + (header->ddspf.fourCC == MAKEFOURCC('D', 'X', '1', '0')); +} + +static WICDdsDimension get_dimension(DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10) +{ + if (header_dxt10) { + if (header_dxt10->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE) return WICDdsTextureCube; + switch (header_dxt10->resourceDimension) + { + case DDS_DIMENSION_TEXTURE1D: return WICDdsTexture1D; + case DDS_DIMENSION_TEXTURE2D: return WICDdsTexture2D; + case DDS_DIMENSION_TEXTURE3D: return WICDdsTexture3D; + default: return WICDdsTexture2D; + } + } else { + if (header->caps2 & DDSCAPS2_CUBEMAP) { + return WICDdsTextureCube; + } else if (header->caps2 & DDSCAPS2_VOLUME) { + return WICDdsTexture3D; + } else { + return WICDdsTexture2D; + } + } +} + +static struct dds_format *get_dds_format(DDS_PIXELFORMAT *pixel_format) +{ + UINT i; + + for (i = 0; i < ARRAY_SIZE(dds_format_table); i++) + { + if ((pixel_format->flags & dds_format_table[i].pixel_format.flags) && + (pixel_format->fourCC == dds_format_table[i].pixel_format.fourCC) && + (pixel_format->rgbBitCount == dds_format_table[i].pixel_format.rgbBitCount) && + (pixel_format->rBitMask == dds_format_table[i].pixel_format.rBitMask) && + (pixel_format->gBitMask == dds_format_table[i].pixel_format.gBitMask) && + (pixel_format->bBitMask == dds_format_table[i].pixel_format.bBitMask) && + (pixel_format->aBitMask == dds_format_table[i].pixel_format.aBitMask)) + return dds_format_table + i; + } + + return dds_format_table + ARRAY_SIZE(dds_format_table) - 1; +} + +static WICDdsAlphaMode get_alpha_mode_from_fourcc(DWORD fourcc) +{ + switch (fourcc) + { + case MAKEFOURCC('D', 'X', 'T', '1'): + case MAKEFOURCC('D', 'X', 'T', '2'): + case MAKEFOURCC('D', 'X', 'T', '4'): + return WICDdsAlphaModePremultiplied; + default: + return WICDdsAlphaModeUnknown; + } +} + +static UINT get_bytes_per_block_from_format(DXGI_FORMAT format) +{ + /* for uncompressed format, return bytes per pixel*/ + switch (format) + { + case DXGI_FORMAT_R8_TYPELESS: + case DXGI_FORMAT_R8_UNORM: + case DXGI_FORMAT_R8_UINT: + case DXGI_FORMAT_R8_SNORM: + case DXGI_FORMAT_R8_SINT: + case DXGI_FORMAT_A8_UNORM: + return 1; + case DXGI_FORMAT_R8G8_TYPELESS: + case DXGI_FORMAT_R8G8_UNORM: + case DXGI_FORMAT_R8G8_UINT: + case DXGI_FORMAT_R8G8_SNORM: + case DXGI_FORMAT_R8G8_SINT: + case DXGI_FORMAT_R16_TYPELESS: + case DXGI_FORMAT_R16_FLOAT: + case DXGI_FORMAT_D16_UNORM: + case DXGI_FORMAT_R16_UNORM: + case DXGI_FORMAT_R16_UINT: + case DXGI_FORMAT_R16_SNORM: + case DXGI_FORMAT_R16_SINT: + case DXGI_FORMAT_B5G6R5_UNORM: + case DXGI_FORMAT_B5G5R5A1_UNORM: + case DXGI_FORMAT_B4G4R4A4_UNORM: + return 2; + case DXGI_FORMAT_R10G10B10A2_TYPELESS: + case DXGI_FORMAT_R10G10B10A2_UNORM: + case DXGI_FORMAT_R10G10B10A2_UINT: + case DXGI_FORMAT_R11G11B10_FLOAT: + case DXGI_FORMAT_R8G8B8A8_TYPELESS: + case DXGI_FORMAT_R8G8B8A8_UNORM: + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + case DXGI_FORMAT_R8G8B8A8_UINT: + case DXGI_FORMAT_R8G8B8A8_SNORM: + case DXGI_FORMAT_R8G8B8A8_SINT: + case DXGI_FORMAT_R16G16_TYPELESS: + case DXGI_FORMAT_R16G16_FLOAT: + case DXGI_FORMAT_R16G16_UNORM: + case DXGI_FORMAT_R16G16_UINT: + case DXGI_FORMAT_R16G16_SNORM: + case DXGI_FORMAT_R16G16_SINT: + case DXGI_FORMAT_R32_TYPELESS: + case DXGI_FORMAT_D32_FLOAT: + case DXGI_FORMAT_R32_FLOAT: + case DXGI_FORMAT_R32_UINT: + case DXGI_FORMAT_R32_SINT: + case DXGI_FORMAT_R24G8_TYPELESS: + case DXGI_FORMAT_D24_UNORM_S8_UINT: + case DXGI_FORMAT_R24_UNORM_X8_TYPELESS: + case DXGI_FORMAT_X24_TYPELESS_G8_UINT: + case DXGI_FORMAT_R9G9B9E5_SHAREDEXP: + case DXGI_FORMAT_R8G8_B8G8_UNORM: + case DXGI_FORMAT_G8R8_G8B8_UNORM: + case DXGI_FORMAT_B8G8R8A8_UNORM: + case DXGI_FORMAT_B8G8R8X8_UNORM: + case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: + case DXGI_FORMAT_B8G8R8A8_TYPELESS: + case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: + case DXGI_FORMAT_B8G8R8X8_TYPELESS: + case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: + return 4; + case DXGI_FORMAT_BC1_UNORM: + case DXGI_FORMAT_BC1_TYPELESS: + case DXGI_FORMAT_BC1_UNORM_SRGB: + case DXGI_FORMAT_BC4_TYPELESS: + case DXGI_FORMAT_BC4_UNORM: + case DXGI_FORMAT_BC4_SNORM: + case DXGI_FORMAT_R16G16B16A16_TYPELESS: + case DXGI_FORMAT_R16G16B16A16_FLOAT: + case DXGI_FORMAT_R16G16B16A16_UNORM: + case DXGI_FORMAT_R16G16B16A16_UINT: + case DXGI_FORMAT_R16G16B16A16_SNORM: + case DXGI_FORMAT_R16G16B16A16_SINT: + case DXGI_FORMAT_R32G32_TYPELESS: + case DXGI_FORMAT_R32G32_FLOAT: + case DXGI_FORMAT_R32G32_UINT: + case DXGI_FORMAT_R32G32_SINT: + case DXGI_FORMAT_R32G8X24_TYPELESS: + case DXGI_FORMAT_D32_FLOAT_S8X24_UINT: + case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: + case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: + return 8; + case DXGI_FORMAT_R32G32B32_TYPELESS: + case DXGI_FORMAT_R32G32B32_FLOAT: + case DXGI_FORMAT_R32G32B32_UINT: + case DXGI_FORMAT_R32G32B32_SINT: + return 12; + case DXGI_FORMAT_BC2_UNORM: + case DXGI_FORMAT_BC2_TYPELESS: + case DXGI_FORMAT_BC2_UNORM_SRGB: + case DXGI_FORMAT_BC3_UNORM: + case DXGI_FORMAT_BC3_TYPELESS: + case DXGI_FORMAT_BC3_UNORM_SRGB: + case DXGI_FORMAT_BC5_TYPELESS: + case DXGI_FORMAT_BC5_UNORM: + case DXGI_FORMAT_BC5_SNORM: + case DXGI_FORMAT_BC6H_TYPELESS: + case DXGI_FORMAT_BC6H_UF16: + case DXGI_FORMAT_BC6H_SF16: + case DXGI_FORMAT_BC7_TYPELESS: + case DXGI_FORMAT_BC7_UNORM: + case DXGI_FORMAT_BC7_UNORM_SRGB: + case DXGI_FORMAT_R32G32B32A32_TYPELESS: + case DXGI_FORMAT_R32G32B32A32_FLOAT: + case DXGI_FORMAT_R32G32B32A32_UINT: + case DXGI_FORMAT_R32G32B32A32_SINT: + return 16; + default: + WARN("DXGI format 0x%x is not supported in DDS decoder\n", format); + return 0; + } +} + +static UINT get_frame_count(UINT depth, UINT mip_levels, UINT array_size, WICDdsDimension dimension) +{ + UINT frame_count, i; + + if (depth == 1) + { + frame_count = mip_levels; + } + else + { + frame_count = 0; + for (i = 0; i < mip_levels; i++) + { + frame_count += depth; + if (depth > 1) depth /= 2; + } + } + + frame_count *= array_size; + if (dimension == WICDdsTextureCube) frame_count *= 6; + + return frame_count; +} + +static void get_frame_dds_index(UINT index, dds_info *info, UINT *array_index, UINT *mip_level, UINT *slice_index) +{ + UINT frame_per_texture, depth; + + if (info->dimension == WICDdsTextureCube) + frame_per_texture = info->mip_levels; + else + frame_per_texture = info->frame_count / info->array_size; + + *array_index = index / frame_per_texture; + *slice_index = index % frame_per_texture; + depth = info->depth; + *mip_level = 0; + while (*slice_index >= depth) + { + *slice_index -= depth; + (*mip_level)++; + if (depth > 1) depth /= 2; + } +} + +static const GUID *dxgi_format_to_wic_format(DXGI_FORMAT dxgi_format) +{ + UINT i; + for (i = 0; i < ARRAY_SIZE(dds_format_table); i++) + { + if (dds_format_table[i].pixel_format.size == 0 && + dds_format_table[i].dxgi_format == dxgi_format) + return dds_format_table[i].wic_format; + } + return &GUID_WICPixelFormatUndefined; +} + +static BOOL is_compressed(DXGI_FORMAT format) +{ + UINT i; + + for (i = 0; i < ARRAY_SIZE(compressed_formats); i++) + { + if (format == compressed_formats[i]) return TRUE; + } + return FALSE; +} + +static void get_dds_info(dds_info* info, DDS_HEADER *header, DDS_HEADER_DXT10 *header_dxt10) +{ + struct dds_format *format_info; + + info->width = header->width; + info->height = header->height; + info->depth = 1; + info->mip_levels = 1; + info->array_size = 1; + if (header->depth) info->depth = header->depth; + if (header->mipMapCount) info->mip_levels = header->mipMapCount; + + if (has_extended_header(header)) { + if (header_dxt10->arraySize) info->array_size = header_dxt10->arraySize; + info->format = header_dxt10->dxgiFormat; + info->dimension = get_dimension(NULL, header_dxt10); + info->alpha_mode = header_dxt10->miscFlags2 & 0x00000008; + info->data_offset = sizeof(DWORD) + sizeof(*header) + sizeof(*header_dxt10); + if (is_compressed(info->format)) { + info->pixel_format = (info->alpha_mode == WICDdsAlphaModePremultiplied) ? + &GUID_WICPixelFormat32bppPBGRA : &GUID_WICPixelFormat32bppBGRA; + info->pixel_format_bpp = 32; + } else { + info->pixel_format = dxgi_format_to_wic_format(info->format); + info->pixel_format_bpp = get_bytes_per_block_from_format(info->format) * 8; + } + } else { + format_info = get_dds_format(&header->ddspf); + info->format = format_info->dxgi_format; + info->dimension = get_dimension(header, NULL); + info->alpha_mode = get_alpha_mode_from_fourcc(header->ddspf.fourCC); + info->data_offset = sizeof(DWORD) + sizeof(*header); + info->pixel_format = format_info->wic_format; + info->pixel_format_bpp = format_info->wic_format_bpp; + } + + if (header->ddspf.flags & (DDPF_RGB | DDPF_ALPHA | DDPF_LUMINANCE)) { + info->bytes_per_block = header->ddspf.rgbBitCount / 8; + } else { + info->bytes_per_block = get_bytes_per_block_from_format(info->format); + } + + info->frame_count = get_frame_count(info->depth, info->mip_levels, info->array_size, info->dimension); +} + +static void decode_block(const BYTE *block_data, UINT block_count, DXGI_FORMAT format, + UINT width, UINT height, DWORD *buffer) +{ + const BYTE *block, *color_indices, *alpha_indices, *alpha_table; + int i, j, x, y, block_x, block_y, color_index, alpha_index; + int block_size, color_offset, color_indices_offset; + WORD color[4], color_value = 0; + BYTE alpha[8], alpha_value = 0; + + if (format == DXGI_FORMAT_BC1_UNORM) { + block_size = 8; + color_offset = 0; + color_indices_offset = 4; + } else { + block_size = 16; + color_offset = 8; + color_indices_offset = 12; + } + block_x = 0; + block_y = 0; + + for (i = 0; i < block_count; i++) + { + block = block_data + i * block_size; + + color[0] = *((WORD *)(block + color_offset)); + color[1] = *((WORD *)(block + color_offset + 2)); + color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) * 2 + GET_RGB565_R(color[1]) + 1) / 3), + ((GET_RGB565_G(color[0]) * 2 + GET_RGB565_G(color[1]) + 1) / 3), + ((GET_RGB565_B(color[0]) * 2 + GET_RGB565_B(color[1]) + 1) / 3)); + color[3] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) * 2 + 1) / 3), + ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) * 2 + 1) / 3), + ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) * 2 + 1) / 3)); + + switch (format) + { + case DXGI_FORMAT_BC1_UNORM: + if (color[0] <= color[1]) { + color[2] = MAKE_RGB565(((GET_RGB565_R(color[0]) + GET_RGB565_R(color[1]) + 1) / 2), + ((GET_RGB565_G(color[0]) + GET_RGB565_G(color[1]) + 1) / 2), + ((GET_RGB565_B(color[0]) + GET_RGB565_B(color[1]) + 1) / 2)); + color[3] = 0; + } + break; + case DXGI_FORMAT_BC2_UNORM: + alpha_table = block; + break; + case DXGI_FORMAT_BC3_UNORM: + alpha[0] = *block; + alpha[1] = *(block + 1); + if (alpha[0] > alpha[1]) { + for (j = 2; j < 8; j++) + { + alpha[j] = (BYTE)((alpha[0] * (8 - j) + alpha[1] * (j - 1) + 3) / 7); + } + } else { + for (j = 2; j < 6; j++) + { + alpha[j] = (BYTE)((alpha[0] * (6 - j) + alpha[1] * (j - 1) + 2) / 5); + } + alpha[6] = 0; + alpha[7] = 0xFF; + } + alpha_indices = block + 2; + break; + default: + break; + } + + color_indices = block + color_indices_offset; + for (j = 0; j < 16; j++) + { + x = block_x + j % 4; + y = block_y + j / 4; + if (x >= width || y >= height) continue; + + color_index = (color_indices[j / 4] >> ((j % 4) * 2)) & 0x3; + color_value = color[color_index]; + + switch (format) + { + case DXGI_FORMAT_BC1_UNORM: + if ((color[0] <= color[1]) && !color_value) { + color_value = 0; + alpha_value = 0; + } else { + alpha_value = 0xFF; + } + break; + case DXGI_FORMAT_BC2_UNORM: + alpha_value = (alpha_table[j / 2] >> (j % 2) * 4) & 0xF; + alpha_value = (BYTE)((alpha_value * 0xFF + 0x7)/ 0xF); + break; + case DXGI_FORMAT_BC3_UNORM: + alpha_index = (*((DWORD *)(alpha_indices + (j / 8) * 3)) >> ((j % 8) * 3)) & 0x7; + alpha_value = alpha[alpha_index]; + break; + default: + break; + } + buffer[x + y * width] = rgb565_to_argb(color_value, alpha_value); + } + + block_x += DDS_BLOCK_WIDTH; + if (block_x >= width) { + block_x = 0; + block_y += DDS_BLOCK_HEIGHT; + } + } +} + +static inline DdsDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) +{ + return CONTAINING_RECORD(iface, DdsDecoder, IWICBitmapDecoder_iface); +} + +static inline DdsDecoder *impl_from_IWICDdsDecoder(IWICDdsDecoder *iface) +{ + return CONTAINING_RECORD(iface, DdsDecoder, IWICDdsDecoder_iface); +} + +static inline DdsDecoder *impl_from_IWICWineDecoder(IWICWineDecoder *iface) +{ + return CONTAINING_RECORD(iface, DdsDecoder, IWICWineDecoder_iface); +} + +static inline DdsFrameDecode *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) +{ + return CONTAINING_RECORD(iface, DdsFrameDecode, IWICBitmapFrameDecode_iface); +} + +static inline DdsFrameDecode *impl_from_IWICDdsFrameDecode(IWICDdsFrameDecode *iface) +{ + return CONTAINING_RECORD(iface, DdsFrameDecode, IWICDdsFrameDecode_iface); +} + +static inline DdsEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) +{ + return CONTAINING_RECORD(iface, DdsEncoder, IWICBitmapEncoder_iface); +} + +static inline DdsEncoder *impl_from_IWICDdsEncoder(IWICDdsEncoder *iface) +{ + return CONTAINING_RECORD(iface, DdsEncoder, IWICDdsEncoder_iface); +} + +static inline DdsFrameEncode *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) +{ + return CONTAINING_RECORD(iface, DdsFrameEncode, IWICBitmapFrameEncode_iface); +} + +static HRESULT WINAPI DdsFrameDecode_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, + void **ppv) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid) || + IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) { + *ppv = &This->IWICBitmapFrameDecode_iface; + } else if (IsEqualGUID(&IID_IWICDdsFrameDecode, iid)) { + *ppv = &This->IWICDdsFrameDecode_iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI DdsFrameDecode_AddRef(IWICBitmapFrameDecode *iface) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI DdsFrameDecode_Release(IWICBitmapFrameDecode *iface) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) { + if (This->pixel_data != This->block_data) free(This->pixel_data); + free(This->block_data); + free(This); + } + + return ref; +} + +static HRESULT WINAPI DdsFrameDecode_GetSize(IWICBitmapFrameDecode *iface, + UINT *puiWidth, UINT *puiHeight) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + + if (!puiWidth || !puiHeight) return E_INVALIDARG; + + *puiWidth = This->info.width; + *puiHeight = This->info.height; + + TRACE("(%p) -> (%d,%d)\n", iface, *puiWidth, *puiHeight); + + return S_OK; +} + +static HRESULT WINAPI DdsFrameDecode_GetPixelFormat(IWICBitmapFrameDecode *iface, + WICPixelFormatGUID *pPixelFormat) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + + if (!pPixelFormat) return E_INVALIDARG; + + *pPixelFormat = *This->info.pixel_format; + + TRACE("(%p) -> %s\n", iface, debugstr_guid(pPixelFormat)); + + return S_OK; +} + +static HRESULT WINAPI DdsFrameDecode_GetResolution(IWICBitmapFrameDecode *iface, + double *pDpiX, double *pDpiY) +{ + FIXME("(%p,%p,%p): stub.\n", iface, pDpiX, pDpiY); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameDecode_CopyPalette(IWICBitmapFrameDecode *iface, + IWICPalette *pIPalette) +{ + FIXME("(%p,%p): stub.\n", iface, pIPalette); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameDecode_CopyPixels(IWICBitmapFrameDecode *iface, + const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) +{ + DdsFrameDecode *This = impl_from_IWICBitmapFrameDecode(iface); + UINT bpp, frame_stride, frame_size; + INT x, y, width, height; + HRESULT hr; + + TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); + + if (!pbBuffer) return E_INVALIDARG; + + bpp = This->info.pixel_format_bpp; + if (!bpp) return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + + frame_stride = This->info.width * bpp / 8; + frame_size = frame_stride * This->info.height; + if (!prc) { + if (cbStride < frame_stride) return E_INVALIDARG; + if (cbBufferSize < frame_size) return WINCODEC_ERR_INSUFFICIENTBUFFER; + } else { + x = prc->X; + y = prc->Y; + width = prc->Width; + height = prc->Height; + if (x < 0 || y < 0 || width <= 0 || height <= 0 || + x + width > This->info.width || + y + height > This->info.height) { + return E_INVALIDARG; + } + if (cbStride < width * bpp / 8) return E_INVALIDARG; + if (cbBufferSize < cbStride * height) return WINCODEC_ERR_INSUFFICIENTBUFFER; + } + + EnterCriticalSection(&This->lock); + + if (!This->pixel_data) { + if (is_compressed(This->info.format)) { + This->pixel_data = malloc(frame_size); + if (!This->pixel_data) { + hr = E_OUTOFMEMORY; + goto end; + } + decode_block(This->block_data, This->info.width_in_blocks * This->info.height_in_blocks, This->info.format, + This->info.width, This->info.height, (DWORD *)This->pixel_data); + } else { + This->pixel_data = This->block_data; + } + } + + hr = copy_pixels(bpp, This->pixel_data, This->info.width, This->info.height, frame_stride, + prc, cbStride, cbBufferSize, pbBuffer); + +end: + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI DdsFrameDecode_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, + IWICMetadataQueryReader **ppIMetadataQueryReader) +{ + FIXME("(%p,%p): stub.\n", iface, ppIMetadataQueryReader); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameDecode_GetColorContexts(IWICBitmapFrameDecode *iface, + UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +{ + FIXME("(%p,%u,%p,%p): stub.\n", iface, cCount, ppIColorContexts, pcActualCount); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameDecode_GetThumbnail(IWICBitmapFrameDecode *iface, + IWICBitmapSource **ppIThumbnail) +{ + FIXME("(%p,%p): stub.\n", iface, ppIThumbnail); + + return E_NOTIMPL; +} + +static const IWICBitmapFrameDecodeVtbl DdsFrameDecode_Vtbl = { + DdsFrameDecode_QueryInterface, + DdsFrameDecode_AddRef, + DdsFrameDecode_Release, + DdsFrameDecode_GetSize, + DdsFrameDecode_GetPixelFormat, + DdsFrameDecode_GetResolution, + DdsFrameDecode_CopyPalette, + DdsFrameDecode_CopyPixels, + DdsFrameDecode_GetMetadataQueryReader, + DdsFrameDecode_GetColorContexts, + DdsFrameDecode_GetThumbnail +}; + +static HRESULT WINAPI DdsFrameDecode_Dds_QueryInterface(IWICDdsFrameDecode *iface, + REFIID iid, void **ppv) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + return DdsFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); +} + +static ULONG WINAPI DdsFrameDecode_Dds_AddRef(IWICDdsFrameDecode *iface) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + return DdsFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); +} + +static ULONG WINAPI DdsFrameDecode_Dds_Release(IWICDdsFrameDecode *iface) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + return DdsFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); +} + +static HRESULT WINAPI DdsFrameDecode_Dds_GetSizeInBlocks(IWICDdsFrameDecode *iface, + UINT *widthInBlocks, UINT *heightInBlocks) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + + if (!widthInBlocks || !heightInBlocks) return E_INVALIDARG; + + *widthInBlocks = This->info.width_in_blocks; + *heightInBlocks = This->info.height_in_blocks; + + TRACE("(%p,%p,%p) -> (%d,%d)\n", iface, widthInBlocks, heightInBlocks, *widthInBlocks, *heightInBlocks); + + return S_OK; +} + +static HRESULT WINAPI DdsFrameDecode_Dds_GetFormatInfo(IWICDdsFrameDecode *iface, + WICDdsFormatInfo *formatInfo) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + + if (!formatInfo) return E_INVALIDARG; + + formatInfo->DxgiFormat = This->info.format; + formatInfo->BytesPerBlock = This->info.bytes_per_block; + formatInfo->BlockWidth = This->info.block_width; + formatInfo->BlockHeight = This->info.block_height; + + TRACE("(%p,%p) -> (0x%x,%d,%d,%d)\n", iface, formatInfo, + formatInfo->DxgiFormat, formatInfo->BytesPerBlock, formatInfo->BlockWidth, formatInfo->BlockHeight); + + return S_OK; +} + +static HRESULT WINAPI DdsFrameDecode_Dds_CopyBlocks(IWICDdsFrameDecode *iface, + const WICRect *boundsInBlocks, UINT stride, UINT bufferSize, + BYTE *buffer) +{ + DdsFrameDecode *This = impl_from_IWICDdsFrameDecode(iface); + int x, y, width, height; + UINT bytes_per_block, frame_stride, frame_size; + + TRACE("(%p,%p,%u,%u,%p)\n", iface, boundsInBlocks, stride, bufferSize, buffer); + + if (!buffer) return E_INVALIDARG; + + bytes_per_block = This->info.bytes_per_block; + frame_stride = This->info.width_in_blocks * bytes_per_block; + frame_size = frame_stride * This->info.height_in_blocks; + + if (!boundsInBlocks) { + if (stride < frame_stride) return E_INVALIDARG; + if (bufferSize < frame_size) return E_INVALIDARG; + } else { + x = boundsInBlocks->X; + y = boundsInBlocks->Y; + width = boundsInBlocks->Width; + height = boundsInBlocks->Height; + if (x < 0 || y < 0 || width <= 0 || height <= 0 || + x + width > This->info.width_in_blocks || + y + height > This->info.height_in_blocks) { + return E_INVALIDARG; + } + if (stride < width * bytes_per_block) return E_INVALIDARG; + if (bufferSize < stride * height) return E_INVALIDARG; + } + + return copy_pixels(This->info.bytes_per_block * 8, This->block_data, This->info.width_in_blocks, + This->info.height_in_blocks, frame_stride, boundsInBlocks, stride, bufferSize, buffer); +} + +static const IWICDdsFrameDecodeVtbl DdsFrameDecode_Dds_Vtbl = { + DdsFrameDecode_Dds_QueryInterface, + DdsFrameDecode_Dds_AddRef, + DdsFrameDecode_Dds_Release, + DdsFrameDecode_Dds_GetSizeInBlocks, + DdsFrameDecode_Dds_GetFormatInfo, + DdsFrameDecode_Dds_CopyBlocks +}; + +static HRESULT DdsFrameDecode_CreateInstance(DdsFrameDecode **frame_decode) +{ + DdsFrameDecode *result; + + result = malloc(sizeof(*result)); + if (!result) return E_OUTOFMEMORY; + + result->IWICBitmapFrameDecode_iface.lpVtbl = &DdsFrameDecode_Vtbl; + result->IWICDdsFrameDecode_iface.lpVtbl = &DdsFrameDecode_Dds_Vtbl; + result->ref = 1; +#ifdef __REACTOS__ + InitializeCriticalSection(&result->lock); +#else + InitializeCriticalSectionEx(&result->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif + result->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsFrameDecode.lock"); + + *frame_decode = result; + return S_OK; +} + +static HRESULT WINAPI DdsDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, + void **ppv) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapDecoder, iid)) { + *ppv = &This->IWICBitmapDecoder_iface; + } else if (IsEqualIID(&IID_IWICDdsDecoder, iid)) { + *ppv = &This->IWICDdsDecoder_iface; + } else if (IsEqualIID(&IID_IWICWineDecoder, iid)) { + *ppv = &This->IWICWineDecoder_iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI DdsDecoder_AddRef(IWICBitmapDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI DdsDecoder_Release(IWICBitmapDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) + { + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + if (This->stream) IStream_Release(This->stream); + free(This); + } + + return ref; +} + +static HRESULT WINAPI DdsDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, + DWORD *capability) +{ + FIXME("(%p,%p,%p): stub.\n", iface, stream, capability); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, + WICDecodeOptions cacheOptions) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr; + + TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); + + EnterCriticalSection(&This->lock); + + hr = IWICWineDecoder_Initialize(&This->IWICWineDecoder_iface, pIStream, cacheOptions); + if (FAILED(hr)) goto end; + + if (This->info.dimension == WICDdsTextureCube || + (This->info.format != DXGI_FORMAT_BC1_UNORM && + This->info.format != DXGI_FORMAT_BC2_UNORM && + This->info.format != DXGI_FORMAT_BC3_UNORM)) { + IStream_Release(pIStream); + This->stream = NULL; + This->initialized = FALSE; + hr = WINCODEC_ERR_BADHEADER; + } + +end: + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI DdsDecoder_GetContainerFormat(IWICBitmapDecoder *iface, + GUID *pguidContainerFormat) +{ + TRACE("(%p,%p)\n", iface, pguidContainerFormat); + + memcpy(pguidContainerFormat, &GUID_ContainerFormatDds, sizeof(GUID)); + + return S_OK; +} + +static HRESULT WINAPI DdsDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, + IWICBitmapDecoderInfo **ppIDecoderInfo) +{ + TRACE("(%p,%p)\n", iface, ppIDecoderInfo); + + return get_decoder_info(&CLSID_WICDdsDecoder, ppIDecoderInfo); +} + +static HRESULT WINAPI DdsDecoder_CopyPalette(IWICBitmapDecoder *iface, + IWICPalette *pIPalette) +{ + TRACE("(%p,%p)\n", iface, pIPalette); + + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + +static HRESULT WINAPI DdsDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, + IWICMetadataQueryReader **ppIMetadataQueryReader) +{ + if (!ppIMetadataQueryReader) return E_INVALIDARG; + + FIXME("(%p,%p)\n", iface, ppIMetadataQueryReader); + + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsDecoder_GetPreview(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIBitmapSource) +{ + TRACE("(%p,%p)\n", iface, ppIBitmapSource); + + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI DdsDecoder_GetColorContexts(IWICBitmapDecoder *iface, + UINT cCount, IWICColorContext **ppDdslorContexts, UINT *pcActualCount) +{ + TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppDdslorContexts, pcActualCount); + + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI DdsDecoder_GetThumbnail(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIThumbnail) +{ + TRACE("(%p,%p)\n", iface, ppIThumbnail); + + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static HRESULT WINAPI DdsDecoder_GetFrameCount(IWICBitmapDecoder *iface, + UINT *pCount) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + + if (!pCount) return E_INVALIDARG; + if (!This->initialized) return WINCODEC_ERR_WRONGSTATE; + + EnterCriticalSection(&This->lock); + + *pCount = This->info.frame_count; + + LeaveCriticalSection(&This->lock); + + TRACE("(%p) -> %d\n", iface, *pCount); + + return S_OK; +} + +static HRESULT WINAPI DdsDecoder_GetFrame(IWICBitmapDecoder *iface, + UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) +{ + DdsDecoder *This = impl_from_IWICBitmapDecoder(iface); + UINT array_index, mip_level, slice_index; + + TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); + + if (!ppIBitmapFrame) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->initialized) { + LeaveCriticalSection(&This->lock); + return WINCODEC_ERR_WRONGSTATE; + } + + get_frame_dds_index(index, &This->info, &array_index, &mip_level, &slice_index); + + LeaveCriticalSection(&This->lock); + + return DdsDecoder_Dds_GetFrame(&This->IWICDdsDecoder_iface, array_index, mip_level, slice_index, ppIBitmapFrame); +} + +static const IWICBitmapDecoderVtbl DdsDecoder_Vtbl = { + DdsDecoder_QueryInterface, + DdsDecoder_AddRef, + DdsDecoder_Release, + DdsDecoder_QueryCapability, + DdsDecoder_Initialize, + DdsDecoder_GetContainerFormat, + DdsDecoder_GetDecoderInfo, + DdsDecoder_CopyPalette, + DdsDecoder_GetMetadataQueryReader, + DdsDecoder_GetPreview, + DdsDecoder_GetColorContexts, + DdsDecoder_GetThumbnail, + DdsDecoder_GetFrameCount, + DdsDecoder_GetFrame +}; + +static HRESULT WINAPI DdsDecoder_Dds_QueryInterface(IWICDdsDecoder *iface, + REFIID iid, void **ppv) +{ + DdsDecoder *This = impl_from_IWICDdsDecoder(iface); + return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); +} + +static ULONG WINAPI DdsDecoder_Dds_AddRef(IWICDdsDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICDdsDecoder(iface); + return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface); +} + +static ULONG WINAPI DdsDecoder_Dds_Release(IWICDdsDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICDdsDecoder(iface); + return DdsDecoder_Release(&This->IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI DdsDecoder_Dds_GetParameters(IWICDdsDecoder *iface, + WICDdsParameters *parameters) +{ + DdsDecoder *This = impl_from_IWICDdsDecoder(iface); + HRESULT hr; + + if (!parameters) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->initialized) { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + parameters->Width = This->info.width; + parameters->Height = This->info.height; + parameters->Depth = This->info.depth; + parameters->MipLevels = This->info.mip_levels; + parameters->ArraySize = This->info.array_size; + parameters->DxgiFormat = This->info.format; + parameters->Dimension = This->info.dimension; + parameters->AlphaMode = This->info.alpha_mode; + + TRACE("(%p) -> (%dx%d depth=%d mipLevels=%d arraySize=%d dxgiFormat=0x%x dimension=0x%x alphaMode=0x%x)\n", + iface, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels, + parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode); + + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI DdsDecoder_Dds_GetFrame(IWICDdsDecoder *iface, + UINT arrayIndex, UINT mipLevel, UINT sliceIndex, + IWICBitmapFrameDecode **bitmapFrame) +{ + DdsDecoder *This = impl_from_IWICDdsDecoder(iface); + HRESULT hr; + LARGE_INTEGER seek; + UINT width, height, depth, block_width, block_height, width_in_blocks, height_in_blocks, size; + UINT frame_width = 0, frame_height = 0, frame_width_in_blocks = 0, frame_height_in_blocks = 0, frame_size = 0; + UINT bytes_per_block, i; + DWORD bytesread; + DdsFrameDecode *frame_decode = NULL; + + TRACE("(%p,%u,%u,%u,%p)\n", iface, arrayIndex, mipLevel, sliceIndex, bitmapFrame); + + if (!bitmapFrame) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->initialized) { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + if ((arrayIndex >= This->info.array_size && This->info.dimension != WICDdsTextureCube) || + (arrayIndex >= This->info.array_size * 6) || + (mipLevel >= This->info.mip_levels) || + (sliceIndex >= This->info.depth)) { + hr = E_INVALIDARG; + goto end; + } + + if (is_compressed(This->info.format)) { + block_width = DDS_BLOCK_WIDTH; + block_height = DDS_BLOCK_HEIGHT; + } else { + block_width = 1; + block_height = 1; + } + bytes_per_block = This->info.bytes_per_block; + seek.QuadPart = This->info.data_offset; + + width = This->info.width; + height = This->info.height; + depth = This->info.depth; + for (i = 0; i < This->info.mip_levels; i++) + { + width_in_blocks = (width + block_width - 1) / block_width; + height_in_blocks = (height + block_height - 1) / block_height; + size = width_in_blocks * height_in_blocks * bytes_per_block; + + if (i < mipLevel) { + seek.QuadPart += size * depth; + } else if (i == mipLevel){ + seek.QuadPart += size * sliceIndex; + frame_width = width; + frame_height = height; + frame_width_in_blocks = width_in_blocks; + frame_height_in_blocks = height_in_blocks; + frame_size = frame_width_in_blocks * frame_height_in_blocks * bytes_per_block; + if (arrayIndex == 0) break; + } + seek.QuadPart += arrayIndex * size * depth; + + if (width > 1) width /= 2; + if (height > 1) height /= 2; + if (depth > 1) depth /= 2; + } + + hr = DdsFrameDecode_CreateInstance(&frame_decode); + if (hr != S_OK) goto end; + frame_decode->info.width = frame_width; + frame_decode->info.height = frame_height; + frame_decode->info.format = This->info.format; + frame_decode->info.bytes_per_block = bytes_per_block; + frame_decode->info.block_width = block_width; + frame_decode->info.block_height = block_height; + frame_decode->info.width_in_blocks = frame_width_in_blocks; + frame_decode->info.height_in_blocks = frame_height_in_blocks; + frame_decode->info.pixel_format = This->info.pixel_format; + frame_decode->info.pixel_format_bpp = This->info.pixel_format_bpp; + frame_decode->block_data = malloc(frame_size); + frame_decode->pixel_data = NULL; + hr = IStream_Seek(This->stream, seek, SEEK_SET, NULL); + if (hr != S_OK) goto end; + hr = IStream_Read(This->stream, frame_decode->block_data, frame_size, &bytesread); + if (hr != S_OK || bytesread != frame_size) { + hr = WINCODEC_ERR_STREAMREAD; + goto end; + } + *bitmapFrame = &frame_decode->IWICBitmapFrameDecode_iface; + + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + + if (hr != S_OK && frame_decode) DdsFrameDecode_Release(&frame_decode->IWICBitmapFrameDecode_iface); + + return hr; +} + +static const IWICDdsDecoderVtbl DdsDecoder_Dds_Vtbl = { + DdsDecoder_Dds_QueryInterface, + DdsDecoder_Dds_AddRef, + DdsDecoder_Dds_Release, + DdsDecoder_Dds_GetParameters, + DdsDecoder_Dds_GetFrame +}; + +static HRESULT WINAPI DdsDecoder_Wine_QueryInterface(IWICWineDecoder *iface, REFIID iid, void **ppv) +{ + DdsDecoder *This = impl_from_IWICWineDecoder(iface); + return DdsDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); +} + +static ULONG WINAPI DdsDecoder_Wine_AddRef(IWICWineDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICWineDecoder(iface); + return DdsDecoder_AddRef(&This->IWICBitmapDecoder_iface); +} + +static ULONG WINAPI DdsDecoder_Wine_Release(IWICWineDecoder *iface) +{ + DdsDecoder *This = impl_from_IWICWineDecoder(iface); + return DdsDecoder_Release(&This->IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI DdsDecoder_Wine_Initialize(IWICWineDecoder *iface, IStream *stream, WICDecodeOptions options) +{ + DdsDecoder *This = impl_from_IWICWineDecoder(iface); + DDS_HEADER_DXT10 header_dxt10; + LARGE_INTEGER seek; + DDS_HEADER header; + ULONG bytesread; + DWORD magic; + HRESULT hr; + + TRACE("(This %p, stream %p, options %#x)\n", iface, stream, options); + + EnterCriticalSection(&This->lock); + + if (This->initialized) { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + seek.QuadPart = 0; + hr = IStream_Seek(stream, seek, SEEK_SET, NULL); + if (FAILED(hr)) goto end; + + hr = IStream_Read(stream, &magic, sizeof(magic), &bytesread); + if (FAILED(hr)) goto end; + if (bytesread != sizeof(magic)) { + hr = WINCODEC_ERR_STREAMREAD; + goto end; + } + if (magic != DDS_MAGIC) { + hr = WINCODEC_ERR_UNKNOWNIMAGEFORMAT; + goto end; + } + + hr = IStream_Read(stream, &header, sizeof(header), &bytesread); + if (FAILED(hr)) goto end; + if (bytesread != sizeof(header)) { + hr = WINCODEC_ERR_STREAMREAD; + goto end; + } + if (header.size != sizeof(header)) { + hr = WINCODEC_ERR_BADHEADER; + goto end; + } + + if (has_extended_header(&header)) { + hr = IStream_Read(stream, &header_dxt10, sizeof(header_dxt10), &bytesread); + if (FAILED(hr)) goto end; + if (bytesread != sizeof(header_dxt10)) { + hr = WINCODEC_ERR_STREAMREAD; + goto end; + } + } + + get_dds_info(&This->info, &header, &header_dxt10); + + This->initialized = TRUE; + This->stream = stream; + IStream_AddRef(stream); + +end: + LeaveCriticalSection(&This->lock); + + return hr; +} + +static const IWICWineDecoderVtbl DdsDecoder_Wine_Vtbl = { + DdsDecoder_Wine_QueryInterface, + DdsDecoder_Wine_AddRef, + DdsDecoder_Wine_Release, + DdsDecoder_Wine_Initialize +}; + +static HRESULT WINAPI DdsFrameEncode_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, void **ppv) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) + { + *ppv = &This->IWICBitmapFrameEncode_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI DdsFrameEncode_AddRef(IWICBitmapFrameEncode *iface) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI DdsFrameEncode_Release(IWICBitmapFrameEncode *iface) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) + { + IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface); + free(This); + } + + return ref; +} + +static HRESULT WINAPI DdsFrameEncode_Initialize(IWICBitmapFrameEncode *iface, + IPropertyBag2 *encoderOptions) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%p)\n", iface, encoderOptions); + if (encoderOptions) FIXME("encoder options are not supported for DDS.\n"); + + EnterCriticalSection(&This->parent->lock); + + if (This->initialized) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + This->initialized = TRUE; + hr = S_OK; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI DdsFrameEncode_SetSize(IWICBitmapFrameEncode *iface, + UINT width, UINT height) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%u,%u)\n", iface, width, height); + + EnterCriticalSection(&This->parent->lock); + + if (!This->initialized || This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + This->width = width; + This->height = height; + hr = S_OK; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI DdsFrameEncode_SetResolution(IWICBitmapFrameEncode *iface, + double dpiX, double dpiY) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); + + EnterCriticalSection(&This->parent->lock); + + if (!This->initialized || This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + This->dpi_x = dpiX; + This->dpi_y = dpiY; + hr = S_OK; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI DdsFrameEncode_SetPixelFormat(IWICBitmapFrameEncode *iface, + WICPixelFormatGUID *pixelFormat) +{ + DdsFrameEncode *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%s)\n", iface, debugstr_guid(pixelFormat)); + + EnterCriticalSection(&This->parent->lock); + + if (!This->initialized) + { + hr = WINCODEC_ERR_NOTINITIALIZED; + } + else if (This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + *pixelFormat = GUID_WICPixelFormat32bppBGRA; + hr = S_OK; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI DdsFrameEncode_SetColorContexts(IWICBitmapFrameEncode *iface, + UINT count, IWICColorContext **colorContext) +{ + FIXME("(%p,%u,%p): stub\n", iface, count, colorContext); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameEncode_SetPalette(IWICBitmapFrameEncode *iface, + IWICPalette *palette) +{ + FIXME("(%p,%p): stub\n", iface, palette); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameEncode_SetThumbnail(IWICBitmapFrameEncode *iface, + IWICBitmapSource *thumbnail) +{ + TRACE("(%p,%p)\n", iface, thumbnail); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI DdsFrameEncode_WritePixels(IWICBitmapFrameEncode *iface, + UINT lineCount, UINT stride, UINT bufferSize, BYTE *pixels) +{ + FIXME("(%p,%u,%u,%u,%p): stub\n", iface, lineCount, stride, bufferSize, pixels); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameEncode_WriteSource(IWICBitmapFrameEncode *iface, + IWICBitmapSource *bitmapSource, WICRect *rc) +{ + FIXME("(%p,%p,%s): stub\n", iface, bitmapSource, debug_wic_rect(rc)); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameEncode_Commit(IWICBitmapFrameEncode *iface) +{ + FIXME("(%p): stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsFrameEncode_GetMetadataQueryWriter(IWICBitmapFrameEncode *iface, + IWICMetadataQueryWriter **metadataQueryWriter) +{ + FIXME("(%p,%p): stub\n", iface, metadataQueryWriter); + return E_NOTIMPL; +} + +static const IWICBitmapFrameEncodeVtbl DdsFrameEncode_Vtbl = { + DdsFrameEncode_QueryInterface, + DdsFrameEncode_AddRef, + DdsFrameEncode_Release, + DdsFrameEncode_Initialize, + DdsFrameEncode_SetSize, + DdsFrameEncode_SetResolution, + DdsFrameEncode_SetPixelFormat, + DdsFrameEncode_SetColorContexts, + DdsFrameEncode_SetPalette, + DdsFrameEncode_SetThumbnail, + DdsFrameEncode_WritePixels, + DdsFrameEncode_WriteSource, + DdsFrameEncode_Commit, + DdsFrameEncode_GetMetadataQueryWriter +}; + +HRESULT DdsDecoder_CreateInstance(REFIID iid, void** ppv) +{ + DdsDecoder *This; + HRESULT ret; + + TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); + + *ppv = NULL; + + This = malloc(sizeof(DdsDecoder)); + if (!This) return E_OUTOFMEMORY; + + This->IWICBitmapDecoder_iface.lpVtbl = &DdsDecoder_Vtbl; + This->IWICDdsDecoder_iface.lpVtbl = &DdsDecoder_Dds_Vtbl; + This->IWICWineDecoder_iface.lpVtbl = &DdsDecoder_Wine_Vtbl; + This->ref = 1; + This->initialized = FALSE; + This->stream = NULL; +#ifdef __REACTOS__ + InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsDecoder.lock"); + + ret = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); + IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); + + return ret; +} + +static HRESULT WINAPI DdsEncoder_Dds_QueryInterface(IWICDdsEncoder *iface, REFIID iid, + void **ppv) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + return IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); +} + +static ULONG WINAPI DdsEncoder_Dds_AddRef(IWICDdsEncoder *iface) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + return IWICBitmapEncoder_AddRef(&This->IWICBitmapEncoder_iface); +} + +static ULONG WINAPI DdsEncoder_Dds_Release(IWICDdsEncoder *iface) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + return IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); +} + +static HRESULT WINAPI DdsEncoder_Dds_SetParameters(IWICDdsEncoder *iface, + WICDdsParameters *parameters) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + HRESULT hr; + + TRACE("(%p,%p)\n", iface, parameters); + + if (!parameters) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->stream) + { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + This->info.width = parameters->Width; + This->info.height = parameters->Height; + This->info.depth = parameters->Depth; + This->info.mip_levels = parameters->MipLevels; + This->info.array_size = parameters->ArraySize; + This->info.format = parameters->DxgiFormat; + This->info.dimension = parameters->Dimension; + This->info.alpha_mode = parameters->AlphaMode; + + This->info.bytes_per_block = get_bytes_per_block_from_format(This->info.format); + This->info.frame_count = get_frame_count(This->info.depth, This->info.mip_levels, + This->info.array_size, This->info.dimension); + + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + return hr; +} + +static HRESULT WINAPI DdsEncoder_Dds_GetParameters(IWICDdsEncoder *iface, + WICDdsParameters *parameters) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + HRESULT hr; + + TRACE("(%p,%p)\n", iface, parameters); + + if (!parameters) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->stream) + { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + parameters->Width = This->info.width; + parameters->Height = This->info.height; + parameters->Depth = This->info.depth; + parameters->MipLevels = This->info.mip_levels; + parameters->ArraySize = This->info.array_size; + parameters->DxgiFormat = This->info.format; + parameters->Dimension = This->info.dimension; + parameters->AlphaMode = This->info.alpha_mode; + + TRACE("(%p,%p) -> (%dx%d depth=%u mipLevels=%u arraySize=%u dxgiFormat=%#x dimension=%#x alphaMode=%#x)\n", + iface, parameters, parameters->Width, parameters->Height, parameters->Depth, parameters->MipLevels, + parameters->ArraySize, parameters->DxgiFormat, parameters->Dimension, parameters->AlphaMode); + + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + return hr; +} + +static HRESULT WINAPI DdsEncoder_Dds_CreateNewFrame(IWICDdsEncoder *iface, + IWICBitmapFrameEncode **frameEncode, + UINT *arrayIndex, UINT *mipLevel, UINT *sliceIndex) +{ + DdsEncoder *This = impl_from_IWICDdsEncoder(iface); + UINT array_index, mip_level, slice_index; + DdsFrameEncode *result; + HRESULT hr; + + TRACE("(%p,%p,%p,%p,%p)\n", iface, frameEncode, arrayIndex, mipLevel, sliceIndex); + + EnterCriticalSection(&This->lock); + + if (!This->stream || This->committed || This->uncommitted_frame) + { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + result = malloc(sizeof(*result)); + if (!result) + { + hr = E_OUTOFMEMORY; + goto end; + } + + get_frame_dds_index(This->frame_index, &This->info, &array_index, &mip_level, &slice_index); + if (arrayIndex) *arrayIndex = array_index; + if (mipLevel) *mipLevel = mip_level; + if (sliceIndex) *sliceIndex = slice_index; + + This->frame_index++; + result->IWICBitmapFrameEncode_iface.lpVtbl = &DdsFrameEncode_Vtbl; + result->ref = 1; + result->parent = This; + result->parent->uncommitted_frame = TRUE; + result->initialized = FALSE; + result->frame_created = FALSE; + IWICDdsEncoder_AddRef(iface); + + *frameEncode = &result->IWICBitmapFrameEncode_iface; + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + return hr; +} + +static const IWICDdsEncoderVtbl DdsEncoder_Dds_Vtbl = +{ + DdsEncoder_Dds_QueryInterface, + DdsEncoder_Dds_AddRef, + DdsEncoder_Dds_Release, + DdsEncoder_Dds_SetParameters, + DdsEncoder_Dds_GetParameters, + DdsEncoder_Dds_CreateNewFrame +}; + +static HRESULT WINAPI DdsEncoder_QueryInterface(IWICBitmapEncoder *iface, REFIID iid, + void **ppv) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + FIXME("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapEncoder, iid)) { + *ppv = &This->IWICBitmapEncoder_iface; + } else if (IsEqualIID(&IID_IWICDdsEncoder, iid)) { + *ppv = &This->IWICDdsEncoder_iface; + } else { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI DdsEncoder_AddRef(IWICBitmapEncoder *iface) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI DdsEncoder_Release(IWICBitmapEncoder *iface) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) { + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + if (This->stream) IStream_Release(This->stream); + free(This); + } + + return ref; +} + +static HRESULT WINAPI DdsEncoder_Initialize(IWICBitmapEncoder *iface, + IStream *stream, WICBitmapEncoderCacheOption cacheOption) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("(%p,%p,%u)\n", iface, stream, cacheOption); + + if (cacheOption != WICBitmapEncoderNoCache) + FIXME("Cache option %#x is not supported.\n", cacheOption); + + if (!stream) return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (This->stream) + { + hr = WINCODEC_ERR_WRONGSTATE; + goto end; + } + + This->stream = stream; + IStream_AddRef(stream); + + This->info.width = 1; + This->info.height = 1; + This->info.depth = 1; + This->info.mip_levels = 1; + This->info.array_size = 1; + This->info.frame_count = 1; + This->info.data_offset = 0; + This->info.bytes_per_block = get_bytes_per_block_from_format(DXGI_FORMAT_BC3_UNORM); + This->info.format = DXGI_FORMAT_BC3_UNORM; + This->info.dimension = WICDdsTexture2D; + This->info.alpha_mode = WICDdsAlphaModeUnknown; + This->info.pixel_format = &GUID_WICPixelFormatUndefined; + This->info.pixel_format_bpp = 0; + + hr = S_OK; + +end: + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI DdsEncoder_GetContainerFormat(IWICBitmapEncoder *iface, GUID *format) +{ + TRACE("(%p,%p)\n", iface, format); + + if (!format) + return E_INVALIDARG; + + memcpy(format, &GUID_ContainerFormatDds, sizeof(*format)); + return S_OK; +} + +static HRESULT WINAPI DdsEncoder_GetEncoderInfo(IWICBitmapEncoder *iface, IWICBitmapEncoderInfo **info) +{ + IWICComponentInfo *comp_info; + HRESULT hr; + + TRACE("%p,%p\n", iface, info); + + if (!info) return E_INVALIDARG; + + hr = CreateComponentInfo(&CLSID_WICDdsEncoder, &comp_info); + if (hr == S_OK) { + hr = IWICComponentInfo_QueryInterface(comp_info, &IID_IWICBitmapEncoderInfo, (void **)info); + IWICComponentInfo_Release(comp_info); + } + return hr; +} + +static HRESULT WINAPI DdsEncoder_SetColorContexts(IWICBitmapEncoder *iface, + UINT cCount, IWICColorContext **ppIColorContext) +{ + FIXME("(%p,%u,%p): stub\n", iface, cCount, ppIColorContext); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsEncoder_SetPalette(IWICBitmapEncoder *iface, IWICPalette *palette) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + HRESULT hr; + + TRACE("(%p,%p)\n", iface, palette); + + EnterCriticalSection(&This->lock); + + hr = This->stream ? WINCODEC_ERR_UNSUPPORTEDOPERATION : WINCODEC_ERR_NOTINITIALIZED; + + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI DdsEncoder_SetThumbnail(IWICBitmapEncoder *iface, IWICBitmapSource *pIThumbnail) +{ + TRACE("(%p,%p)\n", iface, pIThumbnail); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI DdsEncoder_SetPreview(IWICBitmapEncoder *iface, IWICBitmapSource *pIPreview) +{ + TRACE("(%p,%p)\n", iface, pIPreview); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI DdsEncoder_CreateNewFrame(IWICBitmapEncoder *iface, + IWICBitmapFrameEncode **frameEncode, IPropertyBag2 **encoderOptions) +{ + DdsEncoder *This = impl_from_IWICBitmapEncoder(iface); + + TRACE("(%p,%p,%p)\n", iface, frameEncode, encoderOptions); + + return IWICDdsEncoder_CreateNewFrame(&This->IWICDdsEncoder_iface, frameEncode, NULL, NULL, NULL); +} + +static HRESULT WINAPI DdsEncoder_Commit(IWICBitmapEncoder *iface) +{ + FIXME("(%p): stub\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI DdsEncoder_GetMetadataQueryWriter(IWICBitmapEncoder *iface, + IWICMetadataQueryWriter **ppIMetadataQueryWriter) +{ + FIXME("(%p,%p): stub\n", iface, ppIMetadataQueryWriter); + return E_NOTIMPL; +} + +static const IWICBitmapEncoderVtbl DdsEncoder_Vtbl = { + DdsEncoder_QueryInterface, + DdsEncoder_AddRef, + DdsEncoder_Release, + DdsEncoder_Initialize, + DdsEncoder_GetContainerFormat, + DdsEncoder_GetEncoderInfo, + DdsEncoder_SetColorContexts, + DdsEncoder_SetPalette, + DdsEncoder_SetThumbnail, + DdsEncoder_SetPreview, + DdsEncoder_CreateNewFrame, + DdsEncoder_Commit, + DdsEncoder_GetMetadataQueryWriter +}; + +HRESULT DdsEncoder_CreateInstance( REFIID iid, void **ppv) +{ + DdsEncoder *This; + HRESULT ret; + + TRACE("(%s,%p)\n", debugstr_guid(iid), ppv); + + *ppv = NULL; + + This = malloc(sizeof(DdsEncoder)); + if (!This) return E_OUTOFMEMORY; + + This->IWICBitmapEncoder_iface.lpVtbl = &DdsEncoder_Vtbl; + This->IWICDdsEncoder_iface.lpVtbl = &DdsEncoder_Dds_Vtbl; + This->ref = 1; + This->stream = NULL; + This->frame_count = 0; + This->frame_index = 0; + This->uncommitted_frame = FALSE; + This->committed = FALSE; +#ifdef __REACTOS__ + InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": DdsEncoder.lock"); + + ret = IWICBitmapEncoder_QueryInterface(&This->IWICBitmapEncoder_iface, iid, ppv); + IWICBitmapEncoder_Release(&This->IWICBitmapEncoder_iface); + + return ret; +} diff --git a/dll/win32/windowscodecs/decoder.c b/dll/win32/windowscodecs/decoder.c new file mode 100644 index 00000000000..08fe23e1bf0 --- /dev/null +++ b/dll/win32/windowscodecs/decoder.c @@ -0,0 +1,811 @@ +/* + * Copyright 2020 Esme Povirk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +typedef struct { + IWICBitmapDecoder IWICBitmapDecoder_iface; + LONG ref; + CRITICAL_SECTION lock; /* must be held when stream or decoder is accessed */ + IStream *stream; + struct decoder *decoder; + struct decoder_info decoder_info; + struct decoder_stat file_info; + WICDecodeOptions cache_options; +} CommonDecoder; + +static inline CommonDecoder *impl_from_IWICBitmapDecoder(IWICBitmapDecoder *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoder, IWICBitmapDecoder_iface); +} + +static HRESULT WINAPI CommonDecoder_QueryInterface(IWICBitmapDecoder *iface, REFIID iid, + void **ppv) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || IsEqualIID(&IID_IWICBitmapDecoder, iid)) + { + *ppv = &This->IWICBitmapDecoder_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CommonDecoder_AddRef(IWICBitmapDecoder *iface) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI CommonDecoder_Release(IWICBitmapDecoder *iface) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) + { + if (This->stream) + IStream_Release(This->stream); + This->lock.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->lock); + decoder_destroy(This->decoder); + free(This); + } + + return ref; +} + +static HRESULT WINAPI CommonDecoder_QueryCapability(IWICBitmapDecoder *iface, IStream *stream, + DWORD *capability) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr; + + TRACE("(%p,%p,%p)\n", iface, stream, capability); + + if (!stream || !capability) return E_INVALIDARG; + + hr = IWICBitmapDecoder_Initialize(iface, stream, WICDecodeMetadataCacheOnDemand); + if (hr != S_OK) return hr; + + *capability = (This->file_info.flags & DECODER_FLAGS_CAPABILITY_MASK); + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_Initialize(IWICBitmapDecoder *iface, IStream *pIStream, + WICDecodeOptions cacheOptions) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr=S_OK; + + TRACE("(%p,%p,%x)\n", iface, pIStream, cacheOptions); + + EnterCriticalSection(&This->lock); + + if (This->stream) + hr = WINCODEC_ERR_WRONGSTATE; + + if (SUCCEEDED(hr)) + hr = decoder_initialize(This->decoder, pIStream, &This->file_info); + + if (SUCCEEDED(hr)) + { + This->cache_options = cacheOptions; + This->stream = pIStream; + IStream_AddRef(This->stream); + } + + LeaveCriticalSection(&This->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoder_GetContainerFormat(IWICBitmapDecoder *iface, + GUID *pguidContainerFormat) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + memcpy(pguidContainerFormat, &This->decoder_info.container_format, sizeof(GUID)); + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_GetDecoderInfo(IWICBitmapDecoder *iface, + IWICBitmapDecoderInfo **ppIDecoderInfo) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + TRACE("(%p,%p)\n", iface, ppIDecoderInfo); + + return get_decoder_info(&This->decoder_info.clsid, ppIDecoderInfo); +} + +static HRESULT WINAPI CommonDecoder_CopyPalette(IWICBitmapDecoder *iface, + IWICPalette *palette) +{ + TRACE("(%p,%p)\n", iface, palette); + return WINCODEC_ERR_PALETTEUNAVAILABLE; +} + +static HRESULT WINAPI CommonDecoder_GetMetadataQueryReader(IWICBitmapDecoder *iface, + IWICMetadataQueryReader **reader) +{ + TRACE("(%p,%p)\n", iface, reader); + + if (!reader) return E_INVALIDARG; + + *reader = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetPreview(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIBitmapSource) +{ + TRACE("(%p,%p)\n", iface, ppIBitmapSource); + + if (!ppIBitmapSource) return E_INVALIDARG; + + *ppIBitmapSource = NULL; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetColorContexts(IWICBitmapDecoder *iface, + UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +{ + TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); + return WINCODEC_ERR_UNSUPPORTEDOPERATION; +} + +static HRESULT WINAPI CommonDecoder_GetThumbnail(IWICBitmapDecoder *iface, + IWICBitmapSource **ppIThumbnail) +{ + TRACE("(%p,%p)\n", iface, ppIThumbnail); + + if (!ppIThumbnail) return E_INVALIDARG; + + *ppIThumbnail = NULL; + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static HRESULT WINAPI CommonDecoder_GetFrameCount(IWICBitmapDecoder *iface, + UINT *pCount) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + if (!pCount) return E_INVALIDARG; + + if (This->stream) + *pCount = This->file_info.frame_count; + else + *pCount = 0; + + return S_OK; +} + +static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, + UINT index, IWICBitmapFrameDecode **ppIBitmapFrame); + +static const IWICBitmapDecoderVtbl CommonDecoder_Vtbl = { + CommonDecoder_QueryInterface, + CommonDecoder_AddRef, + CommonDecoder_Release, + CommonDecoder_QueryCapability, + CommonDecoder_Initialize, + CommonDecoder_GetContainerFormat, + CommonDecoder_GetDecoderInfo, + CommonDecoder_CopyPalette, + CommonDecoder_GetMetadataQueryReader, + CommonDecoder_GetPreview, + CommonDecoder_GetColorContexts, + CommonDecoder_GetThumbnail, + CommonDecoder_GetFrameCount, + CommonDecoder_GetFrame +}; + +typedef struct { + IWICBitmapFrameDecode IWICBitmapFrameDecode_iface; + IWICMetadataBlockReader IWICMetadataBlockReader_iface; + LONG ref; + CommonDecoder *parent; + DWORD frame; + struct decoder_frame decoder_frame; + BOOL metadata_initialized; + UINT metadata_count; + struct decoder_block* metadata_blocks; +} CommonDecoderFrame; + +static inline CommonDecoderFrame *impl_from_IWICBitmapFrameDecode(IWICBitmapFrameDecode *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICBitmapFrameDecode_iface); +} + +static inline CommonDecoderFrame *impl_from_IWICMetadataBlockReader(IWICMetadataBlockReader *iface) +{ + return CONTAINING_RECORD(iface, CommonDecoderFrame, IWICMetadataBlockReader_iface); +} + +static HRESULT WINAPI CommonDecoderFrame_QueryInterface(IWICBitmapFrameDecode *iface, REFIID iid, + void **ppv) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapSource, iid) || + IsEqualIID(&IID_IWICBitmapFrameDecode, iid)) + { + *ppv = &This->IWICBitmapFrameDecode_iface; + } + else if (IsEqualIID(&IID_IWICMetadataBlockReader, iid) && + (This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata)) + { + *ppv = &This->IWICMetadataBlockReader_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CommonDecoderFrame_AddRef(IWICBitmapFrameDecode *iface) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI CommonDecoderFrame_Release(IWICBitmapFrameDecode *iface) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) + { + IWICBitmapDecoder_Release(&This->parent->IWICBitmapDecoder_iface); + free(This->metadata_blocks); + free(This); + } + + return ref; +} + +static HRESULT WINAPI CommonDecoderFrame_GetSize(IWICBitmapFrameDecode *iface, + UINT *puiWidth, UINT *puiHeight) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p,%p)\n", This, puiWidth, puiHeight); + + if (!puiWidth || !puiHeight) + return E_POINTER; + + *puiWidth = This->decoder_frame.width; + *puiHeight = This->decoder_frame.height; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_GetPixelFormat(IWICBitmapFrameDecode *iface, + WICPixelFormatGUID *pPixelFormat) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p)\n", This, pPixelFormat); + + if (!pPixelFormat) + return E_POINTER; + + *pPixelFormat = This->decoder_frame.pixel_format; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_GetResolution(IWICBitmapFrameDecode *iface, + double *pDpiX, double *pDpiY) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + + TRACE("(%p,%p,%p)\n", This, pDpiX, pDpiY); + + if (!pDpiX || !pDpiY) + return E_POINTER; + + *pDpiX = This->decoder_frame.dpix; + *pDpiY = This->decoder_frame.dpiy; + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_CopyPalette(IWICBitmapFrameDecode *iface, + IWICPalette *pIPalette) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr=S_OK; + + TRACE("(%p,%p)\n", iface, pIPalette); + + if (This->decoder_frame.num_colors) + { + hr = IWICPalette_InitializeCustom(pIPalette, This->decoder_frame.palette, This->decoder_frame.num_colors); + } + else + { + hr = WINCODEC_ERR_PALETTEUNAVAILABLE; + } + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_CopyPixels(IWICBitmapFrameDecode *iface, + const WICRect *prc, UINT cbStride, UINT cbBufferSize, BYTE *pbBuffer) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr; + UINT bytesperrow; + WICRect rect; + + TRACE("(%p,%s,%u,%u,%p)\n", iface, debug_wic_rect(prc), cbStride, cbBufferSize, pbBuffer); + + if (!pbBuffer) + return E_POINTER; + + if (!prc) + { + rect.X = 0; + rect.Y = 0; + rect.Width = This->decoder_frame.width; + rect.Height = This->decoder_frame.height; + prc = ▭ + } + else + { + if (prc->X < 0 || prc->Y < 0 || + prc->X+prc->Width > This->decoder_frame.width || + prc->Y+prc->Height > This->decoder_frame.height) + return E_INVALIDARG; + } + + bytesperrow = ((This->decoder_frame.bpp * prc->Width)+7)/8; + + if (cbStride < bytesperrow) + return E_INVALIDARG; + + if ((cbStride * (prc->Height-1)) + bytesperrow > cbBufferSize) + return E_INVALIDARG; + + EnterCriticalSection(&This->parent->lock); + + hr = decoder_copy_pixels(This->parent->decoder, This->frame, + prc, cbStride, cbBufferSize, pbBuffer); + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_GetMetadataQueryReader(IWICBitmapFrameDecode *iface, + IWICMetadataQueryReader **ppIMetadataQueryReader) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + IWICComponentFactory* factory; + HRESULT hr; + + TRACE("(%p,%p)\n", iface, ppIMetadataQueryReader); + + if (!ppIMetadataQueryReader) + return E_INVALIDARG; + + if (!(This->parent->file_info.flags & WICBitmapDecoderCapabilityCanEnumerateMetadata)) + return WINCODEC_ERR_UNSUPPORTEDOPERATION; + + hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory); + + if (SUCCEEDED(hr)) + { + hr = IWICComponentFactory_CreateQueryReaderFromBlockReader(factory, &This->IWICMetadataBlockReader_iface, ppIMetadataQueryReader); + IWICComponentFactory_Release(factory); + } + + if (FAILED(hr)) + *ppIMetadataQueryReader = NULL; + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_GetColorContexts(IWICBitmapFrameDecode *iface, + UINT cCount, IWICColorContext **ppIColorContexts, UINT *pcActualCount) +{ + CommonDecoderFrame *This = impl_from_IWICBitmapFrameDecode(iface); + HRESULT hr=S_OK; + UINT i; + BYTE *profile; + DWORD profile_len; + + TRACE("(%p,%u,%p,%p)\n", iface, cCount, ppIColorContexts, pcActualCount); + + if (!pcActualCount) return E_INVALIDARG; + + if (This->parent->file_info.flags & DECODER_FLAGS_UNSUPPORTED_COLOR_CONTEXT) + { + FIXME("not supported for %s\n", wine_dbgstr_guid(&This->parent->decoder_info.clsid)); + *pcActualCount = 0; + return WINCODEC_ERR_UNSUPPORTEDOPERATION; + } + + *pcActualCount = This->decoder_frame.num_color_contexts; + + if (This->decoder_frame.num_color_contexts && cCount && ppIColorContexts) + { + if (cCount >= This->decoder_frame.num_color_contexts) + { + EnterCriticalSection(&This->parent->lock); + + for (i=0; i<This->decoder_frame.num_color_contexts; i++) + { + hr = decoder_get_color_context(This->parent->decoder, This->frame, i, + &profile, &profile_len); + if (SUCCEEDED(hr)) + { + hr = IWICColorContext_InitializeFromMemory(ppIColorContexts[i], profile, profile_len); + + free(profile); + } + + if (FAILED(hr)) + break; + } + + LeaveCriticalSection(&This->parent->lock); + } + else + { + hr = E_INVALIDARG; + } + } + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_GetThumbnail(IWICBitmapFrameDecode *iface, + IWICBitmapSource **ppIThumbnail) +{ + TRACE("(%p,%p)\n", iface, ppIThumbnail); + + if (!ppIThumbnail) return E_INVALIDARG; + + *ppIThumbnail = NULL; + return WINCODEC_ERR_CODECNOTHUMBNAIL; +} + +static const IWICBitmapFrameDecodeVtbl CommonDecoderFrameVtbl = { + CommonDecoderFrame_QueryInterface, + CommonDecoderFrame_AddRef, + CommonDecoderFrame_Release, + CommonDecoderFrame_GetSize, + CommonDecoderFrame_GetPixelFormat, + CommonDecoderFrame_GetResolution, + CommonDecoderFrame_CopyPalette, + CommonDecoderFrame_CopyPixels, + CommonDecoderFrame_GetMetadataQueryReader, + CommonDecoderFrame_GetColorContexts, + CommonDecoderFrame_GetThumbnail +}; + +static HRESULT WINAPI CommonDecoderFrame_Block_QueryInterface(IWICMetadataBlockReader *iface, REFIID iid, + void **ppv) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_QueryInterface(&This->IWICBitmapFrameDecode_iface, iid, ppv); +} + +static ULONG WINAPI CommonDecoderFrame_Block_AddRef(IWICMetadataBlockReader *iface) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_AddRef(&This->IWICBitmapFrameDecode_iface); +} + +static ULONG WINAPI CommonDecoderFrame_Block_Release(IWICMetadataBlockReader *iface) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + return IWICBitmapFrameDecode_Release(&This->IWICBitmapFrameDecode_iface); +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetContainerFormat(IWICMetadataBlockReader *iface, + GUID *pguidContainerFormat) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + if (!pguidContainerFormat) return E_INVALIDARG; + *pguidContainerFormat = This->parent->decoder_info.block_format; + return S_OK; +} + +static HRESULT CommonDecoderFrame_InitializeMetadata(CommonDecoderFrame *This) +{ + HRESULT hr=S_OK; + + if (This->metadata_initialized) + return S_OK; + + EnterCriticalSection(&This->parent->lock); + + if (!This->metadata_initialized) + { + hr = decoder_get_metadata_blocks(This->parent->decoder, This->frame, &This->metadata_count, &This->metadata_blocks); + if (SUCCEEDED(hr)) + This->metadata_initialized = TRUE; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetCount(IWICMetadataBlockReader *iface, + UINT *pcCount) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + HRESULT hr; + + TRACE("%p,%p\n", iface, pcCount); + + if (!pcCount) return E_INVALIDARG; + + hr = CommonDecoderFrame_InitializeMetadata(This); + if (SUCCEEDED(hr)) + *pcCount = This->metadata_count; + + return hr; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetReaderByIndex(IWICMetadataBlockReader *iface, + UINT nIndex, IWICMetadataReader **ppIMetadataReader) +{ + CommonDecoderFrame *This = impl_from_IWICMetadataBlockReader(iface); + HRESULT hr; + IWICComponentFactory* factory = NULL; + IWICStream* stream; + + TRACE("%p,%d,%p\n", iface, nIndex, ppIMetadataReader); + + if (!ppIMetadataReader) + return E_INVALIDARG; + + hr = CommonDecoderFrame_InitializeMetadata(This); + + if (SUCCEEDED(hr) && nIndex >= This->metadata_count) + hr = E_INVALIDARG; + + if (SUCCEEDED(hr)) + hr = create_instance(&CLSID_WICImagingFactory, &IID_IWICComponentFactory, (void**)&factory); + + if (SUCCEEDED(hr)) + hr = IWICComponentFactory_CreateStream(factory, &stream); + + if (SUCCEEDED(hr)) + { + if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_FULL_STREAM) + { + LARGE_INTEGER offset; + offset.QuadPart = This->metadata_blocks[nIndex].offset; + + hr = IWICStream_InitializeFromIStream(stream, This->parent->stream); + + if (SUCCEEDED(hr)) + hr = IWICStream_Seek(stream, offset, STREAM_SEEK_SET, NULL); + } + else + { + ULARGE_INTEGER offset, length; + + offset.QuadPart = This->metadata_blocks[nIndex].offset; + length.QuadPart = This->metadata_blocks[nIndex].length; + + hr = IWICStream_InitializeFromIStreamRegion(stream, This->parent->stream, + offset, length); + } + + if (This->metadata_blocks[nIndex].options & DECODER_BLOCK_READER_CLSID) + { + IWICMetadataReader *reader; + IWICPersistStream *persist; + if (SUCCEEDED(hr)) + { + hr = create_instance(&This->metadata_blocks[nIndex].reader_clsid, + &IID_IWICMetadataReader, (void**)&reader); + } + + if (SUCCEEDED(hr)) + { + hr = IWICMetadataReader_QueryInterface(reader, &IID_IWICPersistStream, (void**)&persist); + + if (SUCCEEDED(hr)) + { + hr = IWICPersistStream_LoadEx(persist, (IStream*)stream, NULL, + This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK); + + IWICPersistStream_Release(persist); + } + + if (SUCCEEDED(hr)) + *ppIMetadataReader = reader; + else + IWICMetadataReader_Release(reader); + } + } + else + { + hr = IWICComponentFactory_CreateMetadataReaderFromContainer(factory, + &This->parent->decoder_info.block_format, NULL, + This->metadata_blocks[nIndex].options & DECODER_BLOCK_OPTION_MASK, + (IStream*)stream, ppIMetadataReader); + } + + IWICStream_Release(stream); + } + + if (factory) IWICComponentFactory_Release(factory); + + if (FAILED(hr)) + *ppIMetadataReader = NULL; + + return S_OK; +} + +static HRESULT WINAPI CommonDecoderFrame_Block_GetEnumerator(IWICMetadataBlockReader *iface, + IEnumUnknown **ppIEnumMetadata) +{ + FIXME("%p,%p\n", iface, ppIEnumMetadata); + return E_NOTIMPL; +} + +static const IWICMetadataBlockReaderVtbl CommonDecoderFrame_BlockVtbl = { + CommonDecoderFrame_Block_QueryInterface, + CommonDecoderFrame_Block_AddRef, + CommonDecoderFrame_Block_Release, + CommonDecoderFrame_Block_GetContainerFormat, + CommonDecoderFrame_Block_GetCount, + CommonDecoderFrame_Block_GetReaderByIndex, + CommonDecoderFrame_Block_GetEnumerator, +}; + +static HRESULT WINAPI CommonDecoder_GetFrame(IWICBitmapDecoder *iface, + UINT index, IWICBitmapFrameDecode **ppIBitmapFrame) +{ + CommonDecoder *This = impl_from_IWICBitmapDecoder(iface); + HRESULT hr=S_OK; + CommonDecoderFrame *result; + + TRACE("(%p,%u,%p)\n", iface, index, ppIBitmapFrame); + + if (!ppIBitmapFrame) + return E_INVALIDARG; + + EnterCriticalSection(&This->lock); + + if (!This->stream || index >= This->file_info.frame_count) + hr = WINCODEC_ERR_FRAMEMISSING; + + if (SUCCEEDED(hr)) + { + result = malloc(sizeof(*result)); + if (!result) + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + { + result->IWICBitmapFrameDecode_iface.lpVtbl = &CommonDecoderFrameVtbl; + result->IWICMetadataBlockReader_iface.lpVtbl = &CommonDecoderFrame_BlockVtbl; + result->ref = 1; + result->parent = This; + result->frame = index; + result->metadata_initialized = FALSE; + result->metadata_count = 0; + result->metadata_blocks = NULL; + + hr = decoder_get_frame_info(This->decoder, index, &result->decoder_frame); + + if (SUCCEEDED(hr) && This->cache_options == WICDecodeMetadataCacheOnLoad) + hr = CommonDecoderFrame_InitializeMetadata(result); + + if (FAILED(hr)) + free(result); + } + + LeaveCriticalSection(&This->lock); + + if (SUCCEEDED(hr)) + { + TRACE("-> %ux%u, %u-bit pixelformat=%s res=%f,%f colors=%lu contexts=%lu\n", + result->decoder_frame.width, result->decoder_frame.height, + result->decoder_frame.bpp, wine_dbgstr_guid(&result->decoder_frame.pixel_format), + result->decoder_frame.dpix, result->decoder_frame.dpiy, + result->decoder_frame.num_colors, result->decoder_frame.num_color_contexts); + IWICBitmapDecoder_AddRef(&This->IWICBitmapDecoder_iface); + *ppIBitmapFrame = &result->IWICBitmapFrameDecode_iface; + } + else + { + *ppIBitmapFrame = NULL; + } + + return hr; +} + +HRESULT CommonDecoder_CreateInstance(struct decoder *decoder, + const struct decoder_info *decoder_info, REFIID iid, void** ppv) +{ + CommonDecoder *This; + HRESULT hr; + + TRACE("(%s,%s,%p)\n", debugstr_guid(&decoder_info->clsid), debugstr_guid(iid), ppv); + + This = malloc(sizeof(*This)); + if (!This) + { + decoder_destroy(decoder); + return E_OUTOFMEMORY; + } + + This->IWICBitmapDecoder_iface.lpVtbl = &CommonDecoder_Vtbl; + This->ref = 1; + This->stream = NULL; + This->decoder = decoder; + This->decoder_info = *decoder_info; +#ifdef __REACTOS__ + InitializeCriticalSection(&This->lock); +#else + InitializeCriticalSectionEx(&This->lock, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); +#endif + This->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": CommonDecoder.lock"); + + hr = IWICBitmapDecoder_QueryInterface(&This->IWICBitmapDecoder_iface, iid, ppv); + IWICBitmapDecoder_Release(&This->IWICBitmapDecoder_iface); + + return hr; +} diff --git a/dll/win32/windowscodecs/encoder.c b/dll/win32/windowscodecs/encoder.c new file mode 100644 index 00000000000..b2be1f12e1c --- /dev/null +++ b/dll/win32/windowscodecs/encoder.c @@ -0,0 +1,903 @@ +/* + * Copyright 2020 Esme Povirk + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> + +#define COBJMACROS + +#include "windef.h" +#include "winbase.h" +#include "objbase.h" + +#include "wincodecs_private.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wincodecs); + +static const PROPBAG2 encoder_option_properties[ENCODER_OPTION_END] = { + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"InterlaceOption" }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"FilterOption" }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"TiffCompressionMethod" }, + { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)L"CompressionQuality" }, + { PROPBAG2_TYPE_DATA, VT_R4, 0, 0, (LPOLESTR)L"ImageQuality" }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"BitmapTransform" }, + { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Luminance" }, + { PROPBAG2_TYPE_DATA, VT_I4 | VT_ARRAY, 0, 0, (LPOLESTR)L"Chrominance" }, + { PROPBAG2_TYPE_DATA, VT_UI1, 0, 0, (LPOLESTR)L"JpegYCrCbSubsampling" }, + { PROPBAG2_TYPE_DATA, VT_BOOL, 0, 0, (LPOLESTR)L"SuppressApp0" } +}; + +typedef struct CommonEncoder { + IWICBitmapEncoder IWICBitmapEncoder_iface; + LONG ref; + CRITICAL_SECTION lock; /* must be held when stream or encoder is accessed */ + IStream *stream; + struct encoder *encoder; + struct encoder_info encoder_info; + UINT frame_count; + BOOL uncommitted_frame; + BOOL committed; +} CommonEncoder; + +typedef struct CommonEncoderFrame { + IWICBitmapFrameEncode IWICBitmapFrameEncode_iface; + IWICMetadataBlockWriter IWICMetadataBlockWriter_iface; + LONG ref; + CommonEncoder *parent; + struct encoder_frame encoder_frame; + BOOL initialized; + BOOL frame_created; + UINT lines_written; + BOOL committed; +} CommonEncoderFrame; + +static inline CommonEncoder *impl_from_IWICBitmapEncoder(IWICBitmapEncoder *iface) +{ + return CONTAINING_RECORD(iface, CommonEncoder, IWICBitmapEncoder_iface); +} + +static inline CommonEncoderFrame *impl_from_IWICBitmapFrameEncode(IWICBitmapFrameEncode *iface) +{ + return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICBitmapFrameEncode_iface); +} + +static inline CommonEncoderFrame *impl_from_IWICMetadataBlockWriter(IWICMetadataBlockWriter *iface) +{ + return CONTAINING_RECORD(iface, CommonEncoderFrame, IWICMetadataBlockWriter_iface); +} + +static HRESULT WINAPI CommonEncoderFrame_QueryInterface(IWICBitmapFrameEncode *iface, REFIID iid, + void **ppv) +{ + CommonEncoderFrame *object = impl_from_IWICBitmapFrameEncode(iface); + TRACE("(%p,%s,%p)\n", iface, debugstr_guid(iid), ppv); + + if (!ppv) return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, iid) || + IsEqualIID(&IID_IWICBitmapFrameEncode, iid)) + { + *ppv = &object->IWICBitmapFrameEncode_iface; + } + else if (object->parent->encoder_info.flags & ENCODER_FLAGS_SUPPORTS_METADATA + && IsEqualIID(&IID_IWICMetadataBlockWriter, iid)) + { + *ppv = &object->IWICMetadataBlockWriter_iface; + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI CommonEncoderFrame_AddRef(IWICBitmapFrameEncode *iface) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + return ref; +} + +static ULONG WINAPI CommonEncoderFrame_Release(IWICBitmapFrameEncode *iface) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + ULONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) refcount=%lu\n", iface, ref); + + if (ref == 0) + { + IWICBitmapEncoder_Release(&This->parent->IWICBitmapEncoder_iface); + free(This); + } + + return ref; +} + +static HRESULT WINAPI CommonEncoderFrame_Initialize(IWICBitmapFrameEncode *iface, + IPropertyBag2 *pIEncoderOptions) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr=S_OK; + struct encoder_frame options = {{0}}; + PROPBAG2 opts[7]= {{0}}; + VARIANT opt_values[7]; + HRESULT opt_hres[7]; + DWORD num_opts, i; + + TRACE("(%p,%p)\n", iface, pIEncoderOptions); + + if (pIEncoderOptions) + { + for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++) + opts[i] = encoder_option_properties[This->parent->encoder_info.encoder_options[i]]; + num_opts = i; + + hr = IPropertyBag2_Read(pIEncoderOptions, num_opts, opts, NULL, opt_values, opt_hres); + + if (FAILED(hr)) + return hr; + + for (i=0; This->parent->encoder_info.encoder_options[i] != ENCODER_OPTION_END; i++) + { + VARIANT *val = &opt_values[i]; + + switch (This->parent->encoder_info.encoder_options[i]) + { + case ENCODER_OPTION_INTERLACE: + if (V_VT(val) == VT_EMPTY) + options.interlace = FALSE; + else + options.interlace = (V_BOOL(val) != 0); + break; + case ENCODER_OPTION_FILTER: + options.filter = V_UI1(val); + if (options.filter > WICPngFilterAdaptive) + { + WARN("Unrecognized filter option value %lu.\n", options.filter); + options.filter = WICPngFilterUnspecified; + } + break; + default: + break; + } + } + } + else + { + options.interlace = FALSE; + options.filter = WICPngFilterUnspecified; + } + + EnterCriticalSection(&This->parent->lock); + + if (This->initialized) + hr = WINCODEC_ERR_WRONGSTATE; + else + { + This->encoder_frame = options; + This->initialized = TRUE; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonEncoderFrame_SetSize(IWICBitmapFrameEncode *iface, + UINT uiWidth, UINT uiHeight) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%u,%u)\n", iface, uiWidth, uiHeight); + + EnterCriticalSection(&This->parent->lock); + + if (This->parent->encoder_info.flags & ENCODER_FLAGS_ICNS_SIZE) + { + if (uiWidth != uiHeight) + { + WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight); + hr = E_INVALIDARG; + goto end; + } + + switch (uiWidth) + { + case 16: + case 32: + case 48: + case 128: + case 256: + case 512: + break; + default: + WARN("cannot generate ICNS icon from %dx%d image\n", uiWidth, uiHeight); + hr = E_INVALIDARG; + goto end; + } + } + + if (!This->initialized || This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + This->encoder_frame.width = uiWidth; + This->encoder_frame.height = uiHeight; + hr = S_OK; + } + +end: + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonEncoderFrame_SetResolution(IWICBitmapFrameEncode *iface, + double dpiX, double dpiY) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + + TRACE("(%p,%0.2f,%0.2f)\n", iface, dpiX, dpiY); + + EnterCriticalSection(&This->parent->lock); + + if (!This->initialized || This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + This->encoder_frame.dpix = dpiX; + This->encoder_frame.dpiy = dpiY; + hr = S_OK; + } + + LeaveCriticalSection(&This->parent->lock); + + return hr; +} + +static HRESULT WINAPI CommonEncoderFrame_SetPixelFormat(IWICBitmapFrameEncode *iface, + WICPixelFormatGUID *pPixelFormat) +{ + CommonEncoderFrame *This = impl_from_IWICBitmapFrameEncode(iface); + HRESULT hr; + GUID pixel_format; + DWORD bpp; + BOOL indexed; + + TRACE("(%p,%s)\n", iface, debugstr_guid(pPixelFormat)); + + EnterCriticalSection(&This->parent->lock); + + if (!This->initialized || This->frame_created) + { + hr = WINCODEC_ERR_WRONGSTATE; + } + else + { + pixel_format = *pPixelFormat; + hr = encoder_get_supported_format(This->parent->encoder, &pixel_format, &bpp, &indexed); + } + + if (SUCCEEDED(hr)) + { + TRACE("<-- %s bpp=%li indexed=%i\n", wine_dbgstr_guid(&pixel_format), bpp, indexed); + *pPixelFormat = pixel_format; ... 33002 lines suppressed ...