How to draw an image transparently on the printer DC

DevO 21 Reputation points
2023-03-28T00:12:03.59+00:00

I'm currently researching how to draw images transparently on a printer DC.

When AlphaBlend was used, I heard that most Printer Drivers do not support it, and even if you write and run the code, the image becomes transparent when outputting Microsoft PDF, but the image is not completely drawn when outputting the actual printer.

So I want to draw an image that makes it transparent.

The image is 512x512, and it should be drawn by pasting it as much as the entire DC size of the printer.

Also, I would like to adjust the density value for additional transparency.

For example, I previously made images transparent through DrawImage, but it was too slow to use properly.

My code currently looks like this:

hr = SHCreateStreamOnFile(tszLogoPath, STGM_READ | STGM_SHARE_DENY_WRITE, &pStream);
	if (SUCCEEDED(hr))
	{
		Gdiplus::Bitmap* pBitmap = new Gdiplus::Bitmap(pStream);
		if (pBitmap)
		{
			pBitmap->GetHBITMAP(Gdiplus::Color(255, 255, 255), &hBitmap);
			GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bmp);

			hDCImage = GetDC(NULL);
			hDCImageMem = CreateCompatibleDC(hDCImage);
			hBitmapOld = (HBITMAP)SelectObject(hDCImageMem, hBitmap);

			szImageRect.cx = bmp.bmWidth;
			szImageRect.cy = bmp.bmHeight;

			hr = CreateNBitHBITMAP(NULL, &szImageRect, (void**)&pbBitmap, &hbm, 32);
			if (NULL == hbm)
			{
				// error 
			}
			else
			{
				hDCMemory = CreateCompatibleDC(hDCImage);
				SelectObject(hDCMemory, hbm);
				GetObject(hbm, sizeof(DIBSECTION), &ds);

				for (int y = 0; y < m_nHeight; y += szImageRect.cy)
				{
					for (int x = 0; x < m_nWidth; x += szImageRect.cx)
					{
						BitBlt(hDCMemory, x, y, bmp.bmWidth, bmp.bmHeight, hDCImageMem, 0, 0, SRCCOPY);
					}
				}
				
				// Maybe I should put the code for adjusting the image transparency density here? 

				for (int y = 0; y < m_nHeight; y += szImageRect.cy)
				{
					for (int x = 0; x < m_nWidth; x += szImageRect.cx)
					{
						bResult = StretchDIBits(hDC, x, y, bmp.bmWidth, bmp.bmHeight, 0, 0, bmp.bmWidth, bmp.bmHeight, ds.dsBm.bmBits, (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, SRCCOPY);
					}
				}

				DeleteDC(hDCMemory);
				SelectObject(hDCImageMem, hBitmapOld);
				DeleteDC(hDCImageMem);
				ReleaseDC(NULL, hDCImage);
				DeleteObject(hbm);
			}

			DeleteObject(hBitmap);
		}

		DeleteObject(pBitmap);
		DeleteObject(hBitmapOld);
		pStream->Release();
	}


HRESULT CreateNBitHBITMAP(HDC hDC, const SIZE* psize, void** ppvBits, HBITMAP* phBitmap, WORD nBitCount)
{
	*phBitmap = NULL;
	BITMAPINFO bmi = { 0 };
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = psize->cx;
	bmi.bmiHeader.biHeight = psize->cy;
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = nBitCount;
	bmi.bmiHeader.biCompression = BI_RGB;
	HDC hDCUsed = hDC ? hDC : GetDC(NULL);
	if (hDCUsed)
	{
		*phBitmap = CreateDIBSection(hDCUsed, &bmi, DIB_RGB_COLORS, ppvBits, NULL, 0);
		if (hDC != hDCUsed)
		{
			ReleaseDC(NULL, hDCUsed);
		}
	}
	return (NULL == *phBitmap) ? E_OUTOFMEMORY : S_OK;
}

Microsoft Graph
Microsoft Graph
A Microsoft programmability model that exposes REST APIs and client libraries to access data on Microsoft 365 services.
10,517 questions
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
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Castorix31 81,461 Reputation points
    2023-03-28T12:01:46.9666667+00:00

    This test with DrawImage and ColorMatrix does not seem too slow :

    				WCHAR wsURL[MAX_PATH] = TEXT("https://image.ibb.co/buLv2e/Little_Girl3.jpg");
    				WCHAR wsFilename[MAX_PATH];
    				HRESULT hr = URLDownloadToCacheFile(NULL, wsURL, wsFilename, ARRAYSIZE(wsFilename), 0x0, NULL);
    				if (SUCCEEDED(hr))
    				{
    					{
    						PrintBitmapAlphaBlend(wsFilename, DMORIENT_PORTRAIT, 0.5f);
    						return 0;
    					}
    				}
    
    
    // GdiplusStartup at beginning
    // https://learn.microsoft.com/en-us/dotnet/desktop/winforms/advanced/how-to-use-a-color-matrix-to-set-alpha-values-in-images?view=netframeworkdesktop-4.8
    
    void PrintBitmapAlphaBlend(LPWSTR wsFilename, int nOrientation, float fAlpha)
    {
    	HDC hDCPrinter = NULL;
    
    	PRINTDLG pd;
    	ZeroMemory(&pd, sizeof(PRINTDLG));
    	pd.lStructSize = sizeof(PRINTDLG);
    	pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
    	PrintDlg(&pd);
    	hDCPrinter = pd.hDC;
    
    	DEVMODE* dm = (DEVMODE*)GlobalLock(pd.hDevMode);
    	dm->dmOrientation = nOrientation;
    	ResetDC(pd.hDC, dm);
    	GlobalUnlock(pd.hDevMode);
    
    	ColorMatrix cm = {
    		1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
    		0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
    		0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
    		0.0f, 0.0f, 0.0f, fAlpha, 0.0f,
    		0.0f, 0.0f, 0.0f ,0.0f, 1.0f
    	};
    
    	ImageAttributes ia;
    	ia.SetColorMatrix(&cm, ColorMatrixFlagsDefault, ColorAdjustTypeBitmap);
    
    	Image img(wsFilename);
    	UINT nImageWidth = img.GetWidth();
    	UINT nImageHeight = img.GetHeight();
    
    	Graphics* gr = new Graphics(hDCPrinter);
    	gr->SetPageUnit(UnitPixel);
    
    	DOCINFO di;
    	ZeroMemory(&di, sizeof(di));
    	di.cbSize = sizeof(di);
    	di.lpszDocName = TEXT("Image Printing");
    	if (StartDoc(hDCPrinter, &di))
    	{
    		if (StartPage(hDCPrinter))
    		{
    			int nPrinterWidth = GetDeviceCaps(hDCPrinter, HORZRES);
    			int nPrinterHeight = GetDeviceCaps(hDCPrinter, VERTRES);
    			int nBitmapWidth = nImageWidth * nPrinterWidth / GetSystemMetrics(SM_CXSCREEN);
    			int nBitmapHeight = nBitmapWidth * nImageHeight / nImageWidth;
    
    			Bitmap* bitmap = new Bitmap(nPrinterWidth, nPrinterHeight, PixelFormat32bppARGB);
    			Graphics* g = Graphics::FromImage(bitmap);
    			for (int x = 0; x < nPrinterWidth; x += nBitmapWidth)
    			{
    				for (int y = 0; y < nPrinterHeight; y += nBitmapHeight)
    				{
    					g->DrawImage(&img, x, y, nBitmapWidth, nBitmapHeight);
    				}				
    			}
    			delete g;
    
    			//RectF rectF(0, 0, nBitmapWidth, nBitmapHeight);
    			RectF rectF(0, 0, nPrinterWidth, nPrinterHeight);
    			/*gr->DrawImage(&img, rectF, 0, 0, nImageWidth, nImageHeight, UnitPixel, &ia);*/
    			gr->DrawImage(bitmap, rectF, 0, 0, nPrinterWidth, nPrinterHeight, UnitPixel, &ia);
    			delete bitmap;
    			EndPage(hDCPrinter);
    		}
    		EndDoc(hDCPrinter);
    	}
    
    	delete gr;
    	DeleteDC(hDCPrinter);
    }
    
    

    Original image :

    User's image

    Result :

    User's image