Print transparent bitmaps via regions

This is a modification of Mr Lachand-Robert's BitmapToRegion() function.

The new routine, SetBitmapPixels(), lets you print a CBitmap transparently, even on an HP printer, where you can't use the normal raster operation codes. It is too slow for display, but can be used for printing in place of the normal "blitting" of the bits to the DC.

I have compiled it clean on VC5.0, warning level 4, and have used it in my own code. It has not been thoroughly checked for all pathological logic cases, but does not (seem to) leak any memory.

Here is a sample of calling the routine:

////////////////////////////////////////////
//This sample assumes a mapping mod
//of MM_LOENGLISH (100 pts/inch)
//with the viewport origin in the upper lef
//corner of the DC. It assumes the DC has bee
//built and prepared, and is referenced vi
//a printer DC ptr named pDC
/
//The bitmap is initialized with a resourc
//built and included in the project workspace
/
//The bitmap will be drawn into the D
//centered on a point 2" over and 2" down
/////////////////////////////////////////////
CBitmap bmStamp;

bmStamp.LoadBitmap(IDB_BITMAP_WOODS);

BOOL bOk = SetBitmapPixels(
           pDC,
	       HBITMAP(bmStamp),
	       RGB(255,255,255), // Transparency color = whit
		   200,
		  -200);



And here is the routine:

///////////////////////////////////////////
//Set pixels in a DC drawing surfac
//which are not transparent in a bitmap
/
//If you have a CBitmap object, you can us
//this function to print it transparentl
//on an HP printer
/
//pDC:             DC pointe
//hBmp:            Source bitma
//rgbTransparent:  Color base for the "transparent" pixel
//nXOffset:        Offset to bitmap UL corner, in logical unit
//nYOffset:        Offset to bitmap UL corner, in logical unit
//                 (usually negative
/
//Returns true if OK, else false
/
//This code is based on the BitmapToRegion(
//function contributed by Mr. Lachand-Robert
/
//It is a modification of the original function
//which does the following
/
//1) Given a DC which is being drawn int
//   (such as a printer), the functio
//   makes sure that the regions draw
//   will be centered on the X,Y offsets
/
//2) The function then loops thru the bit
//   in the bitmap. When it encounters 
//   block of bits which are all of the sam
//   color, and which are not the transparenc
//   color, it creates a small region an
//   fills it with a brush of the pixel color
/
/
//The function assumes a mapping mode othe
//than MM_TEXT for the passed-in Devic
//Context. I used it successfully wit
//MM_ANISOTROPIC, for example, and was abl
//to "zoom" the bitmap correctly
///////////////////////////////////////////
BOOL SetBitmapPixels(CDC*     pDC,
                    HBITMAP  hBmp,
                    COLORREF rgbTransparent,
					int      nXOffset,
					int      nYOffset)
{
	//Sanity..
	if (hBmp    == NULL || pDC     == NULL)
		return FALSE;

	// Create a memory DC inside which we will scan the bitmap conten
	HDC hMemDC = CreateCompatibleDC(NULL);
	ASSERT(hMemDC);

	if (hMemDC)
	{
		// Get bitmap siz
		BITMAP bm;
		GetObject(hBmp, sizeof(bm), &bm);

		//Make sure x and Y offset are relativ
		//to center of the bitmap; thi
		//way the bitmap will appear centere
		//on (nXOffset,nYOffset
		nXOffset -= bm.bmWidth /2;
		nYOffset -= bm.bmHeight/2;

		// Create a 32 bits depth bitmap and select it into the memory DC
		BITMAPINFOHEADER RGB32BITSBITMAPINFO =
		{	
			sizeof(BITMAPINFOHEADER),// biSize
			bm.bmWidth,				 // biWidth;
           -bm.bmHeight,			 // biHeight
			1,						 // biPlanes;
			32,						 // biBitCount
			BI_RGB,					 // biCompression;
			0,						 // biSizeImage;
			0,						 // biXPelsPerMeter;
			0,						 // biYPelsPerMeter;
			0,						 // biClrUsed;
			0						 // biClrImportant;
		};

		VOID * pbits32; 

		HBITMAP hbm32 = CreateDIBSection(
		                hMemDC,
		                (BITMAPINFO *)&RGB32BITSBITMAPINFO,
							 DIB_RGB_COLORS,
							 &pbits32,
							 NULL,
							 0);

		if (hbm32)
		{
			HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);

			// Create a DC just to copy the bitmap into the memory D
			HDC hDC = CreateCompatibleDC(hMemDC);

			if (hDC)
			{
				// Get how many bytes per row w
				//have for the bitmap bit
				//(rounded up to 32 bits
				BITMAP bm32;
				VERIFY(GetObject(hbm32, sizeof(bm32), &bm32));

				while (bm32.bmWidthBytes % 4)
					bm32.bmWidthBytes++;

				// Copy the bitmap into the memory D
				HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
				VERIFY(BitBlt(hMemDC,
					           0,
								  0,
								  bm.bmWidth,
								  bm.bmHeight,
								  hDC,
								  0,
								  0,
								  SRCCOPY));

				//Scan each bitmap row from bottom to to
				//(the bitmap is inverted vertically
				BYTE *p32 = (BYTE *)bm32.bmBits +
				            (bm32.bmHeight - 1) * bm32.bmWidthBytes;

				//Scan each bitmap pixel from left to right
				//Search for a continuous lin
				//of non transparent pixel
				for (int y = 0; y < bm.bmHeight; y++)
				{
					for (int x = 0; x < bm.bmWidth; x++)
					{
						int  x0 = x; //Ptr to start of region to fil
						LONG *p = (LONG *)p32 + x;

						COLORREF
						rgbBase =RGB(GetBValue((DWORD)(*p)),
								   	 GetGValue((DWORD)(*p)),
										 GetRValue((DWORD)(*p)));

						COLORREF rgbCurr = rgbBase;

						if (rgbBase != rgbTransparent)
						{
							while(rgbCurr == rgbBase &&
							      x        < bm.bmWidth)
							{
								p++;
								x++;
  								rgbCurr = RGB(GetBValue((DWORD)(*p)),
							  	   			  GetGValue((DWORD)(*p)),
												  GetRValue((DWORD)(*p)));
							}

							CRgn rgnTemp;

							rgnTemp.CreateRectRgn(
									  x0 + nXOffset,
									  y  + nYOffset,
									  x  + nXOffset,
									  y+1+ nYOffset);

							CBrush  brTemp(rgbBase);
							pDC->FillRgn(&rgnTemp,&brTemp);

							x--; //Decrement to account for x for loo
						}	//end if not transparent
					}	//end for 

					// Go to next ro
					//(remember, the bitmap is inverted vertically
					p32 -= bm32.bmWidthBytes;
				}	//end for 

				// Clean u
				SelectObject(hDC, holdBmp);
				DeleteDC(hDC);
			}

			DeleteObject(SelectObject(hMemDC, holdBmp));
		}

		DeleteDC(hMemDC);
	}	

	return TRUE;
}
///////////////////////////////



Comments

  • adding code

    Posted by Legacy on 12/03/2002 12:00am

    Originally posted by: alexis

    may be i'm in new in this field, but can anyone tell mi how to add this code into the application?should i create another new header and source file?
    or where can i copy this codes?
    thnx alot!

    Reply
  • My solution

    Posted by Legacy on 10/18/2002 12:00am

    Originally posted by: yang chisheng

    In my project,I also face the problem of printing transparent bitmap,I also want to print some graphic support alpha channel like TGA.My solution is :
    1.create a printer compatible memory dc
    2.create a dib base on the resolution of the priter
    3.blend all text ,shape or image to the dib.
    4.use SetDIBitsToDevice send dib to the printer dc.

    when drawing a image with alpha channel,firstly get the background image(a dib buffer) and do alpha blend on the background then send result dib to the printer compatible memory dc.

    My problem is :create a dib base on the resolution of the printer will cost huge memory some like 30M bytes.

    Any comments will be appreciated.

    Reply
  • Excellent!

    Posted by Legacy on 09/19/2002 12:00am

    Originally posted by: LavishJack

    Thank you Sir ....
    you guys are great! :)

    Reply
  • Great!!

    Posted by Legacy on 06/27/2002 12:00am

    Originally posted by: PJ

    I just used your code and works as expected.

    Thanks

    Reply
  • Thanks, exactly what I needed to print a bitmap to my HP Printer!

    Posted by Legacy on 08/14/2001 12:00am

    Originally posted by: Michael

    It took me two wasted days to find this code which solved my blank printing problems.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds