2,782 questions
A test with AlphaBlend by using some MS WIC utility functions =>
#include <windows.h>
#include <tchar.h>
#pragma comment (lib, "Msimg32") // AlphaBlend
#include <Urlmon.h> // URLDownloadToCacheFile
#pragma comment (lib, "Urlmon")
#include <shlwapi.h> // SHCreateStreamOnFile
#pragma comment (lib, "Shlwapi")
#include <Wincodec.h> // IWICBitmapSource
#pragma comment (lib, "windowscodecs")
#include <thumbcache.h> // WTS_ALPHATYPE
#pragma comment(linker,"\"/manifestdependency:type='win32' \
name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \
processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
HINSTANCE hInst;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int nWidth = 520, nHeight = 400;
#define IDC_BUTTON 10
HRESULT WICCreate32BitsPerPixelHBITMAP(IStream* pstm, UINT /* cx */, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);
int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow)
{
CoInitialize(NULL);
hInst = hInstance;
WNDCLASSEX wcex =
{
sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW, WndProc, 0, 0, hInst, LoadIcon(NULL, IDI_APPLICATION),
LoadCursor(NULL, IDC_ARROW), (HBRUSH)(COLOR_WINDOW + 1), NULL, TEXT("WindowClass"), NULL,
};
if (!RegisterClassEx(&wcex))
return MessageBox(NULL, TEXT("Cannot register class !"), TEXT("Error"), MB_ICONERROR | MB_OK);
int nX = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2, nY = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
HWND hWnd = CreateWindowEx(0, wcex.lpszClassName, TEXT("Test"), WS_OVERLAPPEDWINDOW, nX, nY, nWidth, nHeight, NULL, NULL, hInst, NULL);
if (!hWnd)
return MessageBox(NULL, TEXT("Cannot create window !"), TEXT("Error"), MB_ICONERROR | MB_OK);
ShowWindow(hWnd, SW_SHOWNORMAL);
UpdateWindow(hWnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
return (int)msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static HWND hWndButton = NULL;
static HBITMAP hBitmap = NULL, hBitmapBackground = NULL;
static BITMAP bm;
static double i = 0;
int wmId, wmEvent;
switch (message)
{
case WM_CREATE:
{
hWndButton = CreateWindowEx(0, L"Button", L"Click", WS_CHILD | WS_VISIBLE | BS_PUSHLIKE, 220, 60, 60, 32, hWnd, (HMENU)IDC_BUTTON, hInst, NULL);
WCHAR wszURL[MAX_PATH] = L"https://i.ibb.co/DG7XSsB/Butterfly.png";
WCHAR wszFilename[MAX_PATH];
HRESULT hr = URLDownloadToCacheFile(NULL, wszURL, wszFilename, ARRAYSIZE(wszFilename), 0x0, NULL);
if (SUCCEEDED(hr))
{
IStream* pstm = NULL;
hr = SHCreateStreamOnFile(wszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pstm);
if (SUCCEEDED(hr))
{
WTS_ALPHATYPE alphatype;
WICCreate32BitsPerPixelHBITMAP(pstm, NULL, &hBitmap, &alphatype);
GetObject(hBitmap, sizeof(BITMAP), &bm);
pstm->Release();
}
}
lstrcpy(wszURL, L"https://i.ibb.co/L5rryfx/Beautiful-nature-with-white-cloud-on-blue-sky-background.jpg");
hr = URLDownloadToCacheFile(NULL, wszURL, wszFilename, ARRAYSIZE(wszFilename), 0x0, NULL);
if (SUCCEEDED(hr))
{
IStream* pstm = NULL;
hr = SHCreateStreamOnFile(wszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pstm);
if (SUCCEEDED(hr))
{
WTS_ALPHATYPE alphatype;
WICCreate32BitsPerPixelHBITMAP(pstm, NULL, &hBitmapBackground, &alphatype);
pstm->Release();
}
}
return 0;
}
break;
case WM_COMMAND:
{
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDC_BUTTON:
{
if (wmEvent == BN_CLICKED)
{
SetTimer(hWnd, 1, 10, NULL);
}
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_TIMER:
{
HDC hDC = GetDC(hWnd);
HDC hDCMem = CreateCompatibleDC(hDC);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hDCMem, hBitmap);
BLENDFUNCTION bf = { AC_SRC_OVER, 0, i, AC_SRC_ALPHA };
AlphaBlend(hDC, 0, 0, bm.bmWidth, bm.bmHeight, hDCMem, 0, 0, bm.bmWidth, bm.bmHeight, bf);
i+=0.02;
if (i >= 255 * 0.02)
{
KillTimer(hWnd, 1);
i = 0;
InvalidateRect(hWnd, NULL, TRUE);
}
SelectObject(hDCMem, hBitmapOld);
DeleteObject(hDCMem);
ReleaseDC(hWnd, hDC);
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BITMAP bmBackground;
BeginPaint(hWnd, &ps);
HDC hMemDC = CreateCompatibleDC(ps.hdc);
HBITMAP hBitmapOld = (HBITMAP)SelectObject(hMemDC, hBitmapBackground);
GetObject(hBitmapBackground, sizeof(BITMAP), &bmBackground);
RECT rect;
GetClientRect(hWnd, &rect);
SetStretchBltMode(ps.hdc, COLORONCOLOR);
StretchBlt(ps.hdc, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, bmBackground.bmWidth, bmBackground.bmHeight, SRCCOPY);
SelectObject(hMemDC, hBitmapOld);
DeleteDC(hMemDC);
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
// From MS SDK RecipeThumbnailProvider.cpp
HRESULT ConvertBitmapSourceTo32BPPHBITMAP(IWICBitmapSource* pBitmapSource, IWICImagingFactory* pImagingFactory, HBITMAP* phbmp)
{
*phbmp = NULL;
IWICBitmapSource* pBitmapSourceConverted = NULL;
WICPixelFormatGUID guidPixelFormatSource;
HRESULT hr = pBitmapSource->GetPixelFormat(&guidPixelFormatSource);
if (SUCCEEDED(hr) && (guidPixelFormatSource != GUID_WICPixelFormat32bppBGRA))
{
IWICFormatConverter* pFormatConverter;
hr = pImagingFactory->CreateFormatConverter(&pFormatConverter);
if (SUCCEEDED(hr))
{
// Create the appropriate pixel format converter
hr = pFormatConverter->Initialize(pBitmapSource, GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, NULL, 0, WICBitmapPaletteTypeCustom);
if (SUCCEEDED(hr))
{
hr = pFormatConverter->QueryInterface(&pBitmapSourceConverted);
}
pFormatConverter->Release();
}
}
else
{
hr = pBitmapSource->QueryInterface(&pBitmapSourceConverted); // No conversion necessary
}
if (SUCCEEDED(hr))
{
UINT nWidth, nHeight;
hr = pBitmapSourceConverted->GetSize(&nWidth, &nHeight);
if (SUCCEEDED(hr))
{
BITMAPINFO bmi = {};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nWidth;
bmi.bmiHeader.biHeight = -static_cast<LONG>(nHeight);
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
BYTE* pBits;
HBITMAP hbmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, reinterpret_cast<void**>(&pBits), NULL, 0);
hr = hbmp ? S_OK : E_OUTOFMEMORY;
if (SUCCEEDED(hr))
{
WICRect rect = { 0, 0, nWidth, nHeight };
// Convert the pixels and store them in the HBITMAP. Note: the name of the function is a little
// misleading - we're not doing any extraneous copying here. CopyPixels is actually converting the
// image into the given buffer.
hr = pBitmapSourceConverted->CopyPixels(&rect, nWidth * 4, nWidth * nHeight * 4, pBits);
if (SUCCEEDED(hr))
{
*phbmp = hbmp;
}
else
{
DeleteObject(hbmp);
}
}
}
pBitmapSourceConverted->Release();
}
return hr;
}
HRESULT WICCreate32BitsPerPixelHBITMAP(IStream* pstm, UINT /* cx */, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha)
{
*phbmp = NULL;
IWICImagingFactory* pImagingFactory;
HRESULT hr = CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pImagingFactory));
if (SUCCEEDED(hr))
{
IWICBitmapDecoder* pDecoder;
hr = pImagingFactory->CreateDecoderFromStream(pstm, &GUID_VendorMicrosoft, WICDecodeMetadataCacheOnDemand, &pDecoder);
//hr = CoCreateInstance(CLSID_WICPngDecoder, NULL, CLSCTX_INPROC_SERVER, __uuidof(pDecoder), reinterpret_cast<void**>(&pDecoder));
//hr = pDecoder->Initialize(pstm, WICDecodeMetadataCacheOnLoad);
if (SUCCEEDED(hr))
{
IWICBitmapFrameDecode* pBitmapFrameDecode;
hr = pDecoder->GetFrame(0, &pBitmapFrameDecode);
if (SUCCEEDED(hr))
{
hr = ConvertBitmapSourceTo32BPPHBITMAP(pBitmapFrameDecode, pImagingFactory, phbmp);
if (SUCCEEDED(hr))
{
*pdwAlpha = WTSAT_ARGB;
}
pBitmapFrameDecode->Release();
}
pDecoder->Release();
}
pImagingFactory->Release();
}
return hr;
}