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; } ///////////////////////////////