C++: how calculate alphablend?

Joaquim Miguel Jesus 1 Reputation point
2022-04-11T21:55:08.633+00:00

We have 2 array pointers pixels.
How combine, using math, the 2 pixels for get the alphablend? And the same for stretch?

C++
C++
A high-level, general-purpose programming language, created as an extension of the C programming language, that has object-oriented, generic, and functional features in addition to facilities for low-level memory manipulation.
3,519 questions
{count} votes

7 answers

Sort by: Most helpful
  1. Castorix31 81,461 Reputation points
    2022-04-15T08:59:13.967+00:00

    I did it with GDI + WIC, maybe it could be simplified with GDI+ or Direct2D (Blend effect, Using Color in Direct2D)

    =>

    193421-blend-xor.jpg

    #include <windows.h>  
    #include <tchar.h>  
      
    #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 = 680, nHeight = 600;  
      
    HRESULT WICCreate32BitsPerPixelHBITMAP(IStream* pstm, UINT /* cx */, HBITMAP* phbmp, WTS_ALPHATYPE* pdwAlpha);  
    void DrawBitmapTransparent(HDC hDCDest, int nXDest, int nYDest, int nBitmapWidth, int nBitmapHeight, HBITMAP hBitmap, int nXSrc, int nYSrc, int nTransparentColor, bool bXOR);  
      
    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 HBITMAP hBitmap1 = NULL, hBitmap2 = NULL, hBitmap3 = NULL;  
      
    	switch (message)  
    	{  
    	case WM_CREATE:  
    	{  
    		WCHAR wszURL1[MAX_PATH] = L"https://i.ibb.co/t8dNP1c/Red-Circle.png";  
    		WCHAR wszURL2[MAX_PATH] = L"https://i.ibb.co/4fXcqM8/Green-Circle.png";  
    		WCHAR wszURL3[MAX_PATH] = L"https://i.ibb.co/fCL4LrT/Blue-Circle.png";  
    		WCHAR wszFilename[MAX_PATH];  
      
    		HRESULT hr = URLDownloadToCacheFile(NULL, wszURL1, wszFilename, ARRAYSIZE(wszFilename), 0x0, NULL);	  
    		IStream* pstm = NULL;  
    		hr = SHCreateStreamOnFile(wszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pstm);  
    		if (SUCCEEDED(hr))  
    		{  
    			WTS_ALPHATYPE alphatype;  
    			WICCreate32BitsPerPixelHBITMAP(pstm, NULL, &hBitmap1, &alphatype);  
    			pstm->Release();  
    		}  
      
    		hr = URLDownloadToCacheFile(NULL, wszURL2, wszFilename, ARRAYSIZE(wszFilename), 0x0, NULL);		  
    		hr = SHCreateStreamOnFile(wszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pstm);  
    		if (SUCCEEDED(hr))  
    		{  
    			WTS_ALPHATYPE alphatype;  
    			WICCreate32BitsPerPixelHBITMAP(pstm, NULL, &hBitmap2, &alphatype);  
    			pstm->Release();  
    		}  
      
    		hr = URLDownloadToCacheFile(NULL, wszURL3, wszFilename, ARRAYSIZE(wszFilename), 0x0, NULL);	  
    		hr = SHCreateStreamOnFile(wszFilename, STGM_READ | STGM_SHARE_DENY_WRITE, &pstm);  
    		if (SUCCEEDED(hr))  
    		{  
    			WTS_ALPHATYPE alphatype;  
    			WICCreate32BitsPerPixelHBITMAP(pstm, NULL, &hBitmap3, &alphatype);  
    			pstm->Release();  
    		}  
      
    		return 0;  
    	}  
    	break;  
    	case WM_PAINT:  
    	{  
    		PAINTSTRUCT ps;  
    		HDC hDC = BeginPaint(hWnd, &ps);  
    		RECT rc;  
    		GetClientRect(hWnd, &rc);  
    		  
    		HBRUSH hBrush = CreateSolidBrush(RGB(0, 0, 0));  
    		FillRect(hDC, &rc, hBrush);  
    		DeleteObject(hBrush);  
      
    		BITMAP bm;  
    		GetObject(hBitmap1, sizeof(BITMAP), &bm);  
    		DrawBitmapTransparent(hDC, bm.bmWidth / 3, 10, bm.bmWidth, bm.bmHeight, hBitmap1, 0, 0, RGB(0, 0, 0), FALSE);  
      
    		GetObject(hBitmap2, sizeof(BITMAP), &bm);  
    		DrawBitmapTransparent(hDC, bm.bmWidth / 6, 10 + bm.bmHeight/3, bm.bmWidth, bm.bmHeight, hBitmap2, 0, 0, RGB(0, 0, 0), TRUE);  
      
    		GetObject(hBitmap3, sizeof(BITMAP), &bm);  
    		DrawBitmapTransparent(hDC, bm.bmWidth / 2, 10 + bm.bmHeight/3, bm.bmWidth, bm.bmHeight, hBitmap3, 0, 0, RGB(0, 0, 0), TRUE);  
      
    		EndPaint(hWnd, &ps);  
    	}  
    	break;  
    	case WM_DESTROY:  
    	{  
    		PostQuitMessage(0);  
    		return 0;  
    	}  
    	break;  
    	default:  
    		return DefWindowProc(hWnd, message, wParam, lParam);  
    	}  
    	return 0;  
    }  
      
      
    void DrawBitmapTransparent(HDC hDCDest, int nXDest, int nYDest, int nBitmapWidth, int nBitmapHeight, HBITMAP hBitmap, int nXSrc, int nYSrc, int nTransparentColor, bool bXOR)  
    {  
    	HDC hDCSrc;  
    	HBITMAP hBitmapOld;  
    	HDC hDCMask;  
    	HBITMAP hBitmapMask;  
    	HBITMAP hBitmapMaskOld;  
    	HDC hDCMem;  
    	HBITMAP hBitmapMem;  
    	HBITMAP hBitmapMemOld;  
    	int nBkColorOld;  
    	int nTextColorOld;  
    	BITMAP bm;  
      
    	GetObject(hBitmap, sizeof(BITMAP), &bm);  
    	if (!nBitmapWidth)  
    		nBitmapWidth = bm.bmWidth;  
    	if (!nBitmapHeight)  
    		nBitmapHeight = bm.bmHeight;  
    	hDCSrc = CreateCompatibleDC(hDCDest);  
    	hBitmapOld = (HBITMAP)SelectObject(hDCSrc, hBitmap);  
    	hDCMask = CreateCompatibleDC(hDCDest);  
    	hBitmapMask = CreateBitmap(nBitmapWidth, nBitmapHeight, 1, 1, 0);  
    	hBitmapMaskOld = (HBITMAP)SelectObject(hDCMask, hBitmapMask);  
    	hDCMem = CreateCompatibleDC(hDCDest);  
    	hBitmapMem = CreateCompatibleBitmap(hDCDest, nBitmapWidth, nBitmapHeight);  
    	hBitmapMemOld = (HBITMAP)SelectObject(hDCMem, hBitmapMem);  
    	nBkColorOld = SetBkColor(hDCSrc, nTransparentColor);  
    	BitBlt(hDCMask, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCCOPY);  
    	SetBkColor(hDCSrc, nBkColorOld);  
    	nBkColorOld = SetBkColor(hDCDest, RGB(255, 255, 255));  
    	nTextColorOld = SetTextColor(hDCDest, RGB(0, 0, 0));  
    	if (!bXOR)  
    	{  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCDest, nXDest, nYDest, SRCCOPY);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCINVERT);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCMask, 0, 0, SRCAND);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCINVERT);  
    		BitBlt(hDCDest, nXDest, nYDest, nBitmapWidth, nBitmapHeight, hDCMem, 0, 0, SRCCOPY);  
    	}  
    	else  
    	{  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCDest, nXDest, nYDest, SRCCOPY);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCCOPY);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCMask, 0, 0, SRCAND);  
    		BitBlt(hDCMem, 0, 0, nBitmapWidth, nBitmapHeight, hDCSrc, nXSrc, nYSrc, SRCINVERT);  
    		BitBlt(hDCDest, nXDest, nYDest, nBitmapWidth, nBitmapHeight, hDCMem, 0, 0, SRCINVERT);  
    	}  
    	SetBkColor(hDCDest, nBkColorOld);  
    	SetTextColor(hDCDest, nTextColorOld);  
    	SelectObject(hDCMem, hBitmapMemOld);  
    	DeleteDC(hDCMem);  
    	DeleteObject(hBitmapMem);  
    	SelectObject(hDCMask, hBitmapMaskOld);  
    	DeleteDC(hDCMask);  
    	DeleteObject(hBitmapMask);  
    	SelectObject(hDCSrc, hBitmapOld);  
    	DeleteDC(hDCSrc);  
    }  
      
    // 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;  
    }  
    
    1 person found this answer helpful.
    0 comments No comments

  2. Joaquim Miguel Jesus 1 Reputation point
    2022-04-13T19:23:00.533+00:00

    no luck... please correct me these code:
    BLENDFUNCTION bf;
    bf.AlphaFormat = 0;
    bf.BlendFlags = 0;
    bf.BlendOp = AC_SRC_OVER;
    bf.SourceConstantAlpha = alphavalue;

    AlphaBlend(hdc,x,y,width,height,memdc,0,0,width,height,bf);
    

    'AlphaBlend()' can work with 'Reserve' on 'RGBQUAD' and with 'AC_SRC_ALPHA' on 'bf.BlendOp'? i mean: see the all pixels alpha?


  3. Joaquim Miguel Jesus 1 Reputation point
    2022-04-13T19:46:47.783+00:00

    using these code:
    COLORREF AlphaBlend2(COLORREF Top, COLORREF Source,BYTE Alpha)
    {
    BYTE R = GetRValue(Top) + (GetRValue(Source) * Alpha) >> 8;
    BYTE G = GetGValue(Top) + (GetGValue(Source) * Alpha) >> 8;
    BYTE B = GetBValue(Top) + (GetBValue(Source) * Alpha) >> 8;
    return (RGB(R,G,B));
    }

     void Draw(HDC HDCDestination, int PosX, int PosY, BYTE SourceConstantAlpha=0x00 )  
            {  
               //StretchDIBits(HDCDestination,PosX, PosY, Width, Height,0,0,Width,Height, Pixels,&BitInfo,DIB_RGB_COLORS,SRCCOPY);  
      
                for(unsigned int Y = 0; Y < Height; Y++)  
                {  
                    for(unsigned int X = 0; X< Width; X++)  
                    {  
                        COLORREF color2 = RGB(Pixels[(Y* Width) + (X)].rgbRed, Pixels[(Y* Width) + (X)].rgbGreen, Pixels[(Y* Width) + (X)].rgbBlue);  
      
                        COLORREF color=AlphaBlend2(::GetPixel(HDCDestination, (PosX+ X), (PosY+Y)), color2,200 );  
                        ::SetPixel(HDCDestination,(PosX+X), (PosY + Y) ,color );  
      
                    }  
                }  
      
            }  
    

    heres what i get with 200(the red seems nothing link blend :( ):
    192824-image.png

    0 comments No comments

  4. Joaquim Miguel Jesus 1 Reputation point
    2022-04-14T21:25:54.06+00:00

    Castorix31: "I had posted a sample with AlphaBlend in this thread : How to make a bitmap with alpha using TransparentBlt but I don't see what you're trying to do..."
    see these image:
    193207-image.png

    now thing that we have 3 images(one for R, one for G and other for B)... we must draw them... the top images must be transparent(no backcolor) and Opacy(AlphaBlend).
    is what i'm loking for... but i didn't find a correct formulas, because i don't get results :(

    0 comments No comments

  5. Joaquim Miguel Jesus 1 Reputation point
    2022-04-21T14:07:16.217+00:00

    i'm sorry Castorix31, but my code is using, for now, GDI(not Plus) and i need use math for 3D positions.
    imagine the image have these corners positions(X, Y and Z):
    TopLeft(0,0,0); TopRight(100,0,100);
    BottomLeft(0,100,0); BottomRight(100,100,100)
    the AlphaBlend() don't works... the PlgBlt() maybe can do transparent and stretch, but not AlphaBlend :(
    unless... i use both... the AlphaBlend() for Alpha and Transparent... then using the PlgBlt() for draw the image... what you can tell me?

    https://learn.microsoft.com/en-us/windows/win32/api/wingdi/nf-wingdi-plgblt

    and how can i use the lpPoint parameter?

    BOOL PlgBlt(  
      [in] HDC         hdcDest,  
      [in] const POINT *lpPoint,  
      [in] HDC         hdcSrc,  
      [in] int         xSrc,  
      [in] int         ySrc,  
      [in] int         width,  
      [in] int         height,  
      [in] HBITMAP     hbmMask,  
      [in] int         xMask,  
      [in] int         yMask  
    );  
    

    "[in] lpPoint

    A pointer to an array of three points in logical space that identify three corners of the destination parallelogram. The upper-left corner of the source rectangle is mapped to the first point in this array, the upper-right corner to the second point in this array, and the lower-left corner to the third point. The lower-right corner of the source rectangle is mapped to the implicit fourth point in the parallelogram."