diff --git a/dlls/windowscodecs/bitmap.c b/dlls/windowscodecs/bitmap.c index 6adaab0aea1..f8414962f2d 100644 --- a/dlls/windowscodecs/bitmap.c +++ b/dlls/windowscodecs/bitmap.c @@ -45,6 +45,8 @@ typedef struct BitmapImpl { int palette_set; LONG lock; /* 0 if not locked, -1 if locked for writing, count if locked for reading */ BYTE *data; + void *view; /* used if data is a section created by an application */ + UINT offset; /* offset into view */ UINT width, height; UINT stride; UINT bpp; @@ -284,7 +286,10 @@ static ULONG WINAPI BitmapImpl_Release(IWICBitmap *iface) if (This->palette) IWICPalette_Release(This->palette); This->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&This->cs); - HeapFree(GetProcessHeap(), 0, This->data); + if (This->view) + UnmapViewOfFile(This->view); + else + HeapFree(GetProcessHeap(), 0, This->data); HeapFree(GetProcessHeap(), 0, This); } @@ -693,9 +698,8 @@ static const IMILUnknown2Vtbl IMILUnknown2Impl_Vtbl = IMILUnknown2Impl_UnknownMethod1, }; -HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, - UINT stride, UINT datasize, BYTE *bits, - REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, +HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, UINT stride, UINT datasize, void *view, + UINT offset, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap) { HRESULT hr; @@ -713,14 +717,14 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, if (stride < ((bpp*uiWidth)+7)/8) return E_INVALIDARG; This = HeapAlloc(GetProcessHeap(), 0, sizeof(BitmapImpl)); - data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize); - if (!This || !data) + if (!This) return E_OUTOFMEMORY; + + if (view) data = (BYTE *)view + offset; + else if (!(data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, datasize))) { HeapFree(GetProcessHeap(), 0, This); - HeapFree(GetProcessHeap(), 0, data); return E_OUTOFMEMORY; } - if (bits) memcpy(data, bits, datasize); This->IWICBitmap_iface.lpVtbl = &BitmapImpl_Vtbl; This->IMILBitmapSource_iface.lpVtbl = &IMILBitmapImpl_Vtbl; @@ -731,6 +735,8 @@ HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, This->palette_set = 0; This->lock = 0; This->data = data; + This->view = view; + This->offset = offset; This->width = uiWidth; This->height = uiHeight; This->stride = stride; diff --git a/dlls/windowscodecs/imgfactory.c b/dlls/windowscodecs/imgfactory.c index e1bcc89a8b4..06e3f6acebe 100644 --- a/dlls/windowscodecs/imgfactory.c +++ b/dlls/windowscodecs/imgfactory.c @@ -473,7 +473,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmap(IWICComponentFactory *iface, { TRACE("(%p,%u,%u,%s,%u,%p)\n", iface, uiWidth, uiHeight, debugstr_guid(pixelFormat), option, ppIBitmap); - return BitmapImpl_Create(uiWidth, uiHeight, 0, 0, NULL, pixelFormat, option, ppIBitmap); + return BitmapImpl_Create(uiWidth, uiHeight, 0, 0, NULL, 0, pixelFormat, option, ppIBitmap); } static HRESULT WINAPI ComponentFactory_CreateBitmapFromSource(IWICComponentFactory *iface, @@ -520,7 +520,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromSource(IWICComponentFacto } if (SUCCEEDED(hr)) - hr = BitmapImpl_Create(width, height, 0, 0, NULL, &pixelformat, option, &result); + hr = BitmapImpl_Create(width, height, 0, 0, NULL, 0, &pixelformat, option, &result); if (SUCCEEDED(hr)) { @@ -595,12 +595,36 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromMemory(IWICComponentFacto UINT width, UINT height, REFWICPixelFormatGUID format, UINT stride, UINT size, BYTE *buffer, IWICBitmap **bitmap) { + HRESULT hr; + TRACE("(%p,%u,%u,%s,%u,%u,%p,%p\n", iface, width, height, debugstr_guid(format), stride, size, buffer, bitmap); if (!stride || !size || !buffer || !bitmap) return E_INVALIDARG; - return BitmapImpl_Create(width, height, stride, size, buffer, format, WICBitmapCacheOnLoad, bitmap); + hr = BitmapImpl_Create(width, height, stride, size, NULL, 0, format, WICBitmapCacheOnLoad, bitmap); + if (SUCCEEDED(hr)) + { + IWICBitmapLock *lock; + + hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); + if (SUCCEEDED(hr)) + { + UINT buffersize; + BYTE *data; + + IWICBitmapLock_GetDataPointer(lock, &buffersize, &data); + memcpy(data, buffer, buffersize); + + IWICBitmapLock_Release(lock); + } + else + { + IWICBitmap_Release(*bitmap); + *bitmap = NULL; + } + } + return hr; } static BOOL get_16bpp_format(HBITMAP hbm, WICPixelFormatGUID *format) @@ -710,7 +734,8 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHBITMAP(IWICComponentFact return E_INVALIDARG; } - hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, &format, WICBitmapCacheOnLoad, bitmap); + hr = BitmapImpl_Create(bm.bmWidth, bm.bmHeight, bm.bmWidthBytes, 0, NULL, 0, &format, + WICBitmapCacheOnLoad, bitmap); if (hr != S_OK) return hr; hr = IWICBitmap_Lock(*bitmap, NULL, WICBitmapLockWrite, &lock); @@ -794,7 +819,7 @@ static HRESULT WINAPI ComponentFactory_CreateBitmapFromHICON(IWICComponentFactor stride = width * 4; size = stride * height; - hr = BitmapImpl_Create(width, height, stride, size, NULL, + hr = BitmapImpl_Create(width, height, stride, size, NULL, 0, &GUID_WICPixelFormat32bppBGRA, WICBitmapCacheOnLoad, bitmap); if (hr != S_OK) goto failed; @@ -1176,3 +1201,63 @@ HRESULT ComponentFactory_CreateInstance(REFIID iid, void** ppv) return ret; } + +HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, UINT stride, + UINT offset, WICSectionAccessLevel wicaccess, IWICBitmap **bitmap) +{ + SYSTEM_INFO sysinfo; + UINT bpp, access, size, view_offset, view_size; + void *view; + HRESULT hr; + + TRACE("%u,%u,%s,%p,%u,%u,%#x,%p\n", width, height, debugstr_guid(format), + section, stride, offset, wicaccess, bitmap); + + if (!width || !height || !section || !bitmap) return E_INVALIDARG; + + hr = get_pixelformat_bpp(format, &bpp); + if (FAILED(hr)) return hr; + + switch (wicaccess) + { + case WICSectionAccessLevelReadWrite: + access = FILE_MAP_READ | FILE_MAP_WRITE; + break; + + case WICSectionAccessLevelRead: + access = FILE_MAP_READ; + break; + + default: + FIXME("unsupported access %#x\n", wicaccess); + return E_INVALIDARG; + } + + if (!stride) stride = (((bpp * width) + 31) / 32) * 4; + size = stride * height; + if (size / height != stride) return E_INVALIDARG; + + GetSystemInfo(&sysinfo); + view_offset = offset - (offset % sysinfo.dwAllocationGranularity); + view_size = size + (offset - view_offset); + + view = MapViewOfFile(section, access, 0, view_offset, view_size); + if (!view) return HRESULT_FROM_WIN32(GetLastError()); + + offset -= view_offset; + hr = BitmapImpl_Create(width, height, stride, 0, view, offset, format, WICBitmapCacheOnLoad, bitmap); + if (FAILED(hr)) UnmapViewOfFile(view); + return hr; +} + +HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, + REFWICPixelFormatGUID format, HANDLE section, + UINT stride, UINT offset, IWICBitmap **bitmap) +{ + TRACE("%u,%u,%s,%p,%u,%u,%p\n", width, height, debugstr_guid(format), + section, stride, offset, bitmap); + + return WICCreateBitmapFromSectionEx(width, height, format, section, + stride, offset, WICSectionAccessLevelRead, bitmap); +} diff --git a/dlls/windowscodecs/tests/bitmap.c b/dlls/windowscodecs/tests/bitmap.c index 42f452acaf7..6e01f0b1d12 100644 --- a/dlls/windowscodecs/tests/bitmap.c +++ b/dlls/windowscodecs/tests/bitmap.c @@ -972,6 +972,64 @@ static void test_clipper(void) IWICBitmapClipper_Release(clipper); } +static HRESULT (WINAPI *pWICCreateBitmapFromSectionEx) + (UINT, UINT, REFWICPixelFormatGUID, HANDLE, UINT, UINT, WICSectionAccessLevel, IWICBitmap **); + +static void test_WICCreateBitmapFromSectionEx(void) +{ + SYSTEM_INFO sysinfo; + HANDLE hsection; + BITMAPINFO info; + void *bits; + HBITMAP hdib; + IWICBitmap *bitmap; + HRESULT hr; + pWICCreateBitmapFromSectionEx = + (void *)GetProcAddress(LoadLibraryA("windowscodecs"), "WICCreateBitmapFromSectionEx"); + + if (!pWICCreateBitmapFromSectionEx) + { + win_skip("WICCreateBitmapFromSectionEx not available\n"); + return; + } + + GetSystemInfo(&sysinfo); + hsection = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, + sysinfo.dwAllocationGranularity * 2, NULL); + ok(hsection != NULL, "CreateFileMapping failed %u\n", GetLastError()); + + memset(&info, 0, sizeof(info)); + info.bmiHeader.biSize = sizeof(info.bmiHeader); + info.bmiHeader.biWidth = 3; + info.bmiHeader.biHeight = -3; + info.bmiHeader.biBitCount = 24; + info.bmiHeader.biPlanes = 1; + info.bmiHeader.biCompression = BI_RGB; + + hdib = CreateDIBSection(0, &info, DIB_RGB_COLORS, &bits, hsection, 0); + ok(hdib != NULL, "CreateDIBSection failed\n"); + + hr = pWICCreateBitmapFromSectionEx(3, 3, &GUID_WICPixelFormat24bppBGR, hsection, 0, 0, + WICSectionAccessLevelReadWrite, &bitmap); + ok(hr == S_OK, "WICCreateBitmapFromSectionEx returned %#x\n", hr); + IWICBitmap_Release(bitmap); + + /* non-zero offset, smaller than allocation granularity */ + hr = pWICCreateBitmapFromSectionEx(3, 3, &GUID_WICPixelFormat24bppBGR, hsection, 0, 0x100, + WICSectionAccessLevelReadWrite, &bitmap); + ok(hr == S_OK, "WICCreateBitmapFromSectionEx returned %#x\n", hr); + IWICBitmap_Release(bitmap); + + /* offset larger than allocation granularity */ + hr = pWICCreateBitmapFromSectionEx(3, 3, &GUID_WICPixelFormat24bppBGR, hsection, 0, + sysinfo.dwAllocationGranularity + 1, + WICSectionAccessLevelReadWrite, &bitmap); + ok(hr == S_OK, "WICCreateBitmapFromSectionEx returned %#x\n", hr); + IWICBitmap_Release(bitmap); + DeleteObject(hdib); + CloseHandle(hsection); +} + START_TEST(bitmap) { HRESULT hr; @@ -992,4 +1050,6 @@ START_TEST(bitmap) IWICImagingFactory_Release(factory); CoUninitialize(); + + test_WICCreateBitmapFromSectionEx(); } diff --git a/dlls/windowscodecs/wincodecs_private.h b/dlls/windowscodecs/wincodecs_private.h index 8bba8112509..c2c5ce4e6c1 100644 --- a/dlls/windowscodecs/wincodecs_private.h +++ b/dlls/windowscodecs/wincodecs_private.h @@ -91,7 +91,7 @@ extern HRESULT IcnsEncoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDE extern HRESULT TgaDecoder_CreateInstance(REFIID iid, void** ppv) DECLSPEC_HIDDEN; extern HRESULT BitmapImpl_Create(UINT uiWidth, UINT uiHeight, - UINT stride, UINT datasize, BYTE *bits, + UINT stride, UINT datasize, void *view, UINT offset, REFWICPixelFormatGUID pixelFormat, WICBitmapCreateCacheOption option, IWICBitmap **ppIBitmap) DECLSPEC_HIDDEN; extern HRESULT BitmapScaler_Create(IWICBitmapScaler **scaler) DECLSPEC_HIDDEN; diff --git a/dlls/windowscodecs/windowscodecs.spec b/dlls/windowscodecs/windowscodecs.spec index 49346fc86b7..905ef835afc 100644 --- a/dlls/windowscodecs/windowscodecs.spec +++ b/dlls/windowscodecs/windowscodecs.spec @@ -105,7 +105,8 @@ @ stdcall IWICStream_InitializeFromIStream_Proxy(ptr ptr) IWICStream_InitializeFromIStream_Proxy_W @ stdcall IWICStream_InitializeFromMemory_Proxy(ptr ptr long) IWICStream_InitializeFromMemory_Proxy_W @ stdcall WICConvertBitmapSource(ptr ptr ptr) -@ stub WICCreateBitmapFromSection +@ stdcall WICCreateBitmapFromSection(long long ptr long long long ptr) +@ stdcall WICCreateBitmapFromSectionEx(long long ptr long long long long ptr) @ stdcall WICCreateColorContext_Proxy(ptr ptr) @ stdcall WICCreateImagingFactory_Proxy(long ptr) @ stub WICGetMetadataContentSize diff --git a/include/wincodec.idl b/include/wincodec.idl index f2c5a9e6269..50d7db76201 100644 --- a/include/wincodec.idl +++ b/include/wincodec.idl @@ -189,6 +189,12 @@ typedef enum WICPngFilterOption { WICPNFFILTEROPTION_FORCE_DWORD = CODEC_FORCE_DWORD } WICPngFilterOption; +typedef enum WICSectionAccessLevel { + WICSectionAccessLevelRead = 0x00000001, + WICSectionAccessLevelReadWrite = 0x00000003, + WICSectionAccessLevel_FORCE_DWORD = CODEC_FORCE_DWORD +} WICSectionAccessLevel; + typedef GUID WICPixelFormatGUID; typedef REFGUID REFWICPixelFormatGUID; @@ -1058,6 +1064,8 @@ interface IWICEnumMetadataItem : IUnknown } cpp_quote("HRESULT WINAPI WICConvertBitmapSource(REFWICPixelFormatGUID dstFormat, IWICBitmapSource *pISrc, IWICBitmapSource **ppIDst);") +cpp_quote("HRESULT WINAPI WICCreateBitmapFromSection(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, IWICBitmap **bitmap);") +cpp_quote("HRESULT WINAPI WICCreateBitmapFromSectionEx(UINT width, UINT height, REFWICPixelFormatGUID format, HANDLE section, UINT stride, UINT offset, WICSectionAccessLevel access, IWICBitmap **bitmap);") cpp_quote("HRESULT WINAPI WICMapGuidToShortName(REFGUID,UINT,WCHAR *,UINT *);") cpp_quote("HRESULT WINAPI WICMapShortNameToGuid(PCWSTR,GUID *);")