Clipping in GDI

Started by
4 comments, last by Extrarius 18 years, 1 month ago
I'm a bit stumped here. My problem is that I want to create a polygon with a bitmap in the background, and the bitmap is clipped into the polygon's region. I have succeeded in doing this with this code:

CBitmap* pBitmap = pDoc->GetBitmap(); //bitmap is in my doc

CDC memDC;
memDC.CreateCompatibleDC(pDC); 

CPalette* pOldPalette;
CPalette* pPalette = pDoc->GetPalette();

if( pPalette ) {
   pOldPalette = pDC->SelectPalette(pPalette, FALSE);
   pDC->RealizePalette();
}

DIBSECTION ds;
pBitmap->GetObject( sizeof(DIBSECTION), &ds );

CPoint poly[numpts];
// (assign poly points here)

CRgn rgn1;
rgn1.CreatePolygonRgn( poly, numpts, ALTERNATE );

pDC->SelectClipRgn(&rgn1);

CBitmap* pOldBitmap = memDC.SelectObject(pBitmap);        
pDC->StretchBlt( 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight, 
                 &memDC, 
                 0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
                  SRCCOPY );
        
memDC.SelectObject(pOldBitmap);

if( pPalette != NULL ) {
   pDC->SelectPalette( pPalette, FALSE );
}



As I said, this works. Here's the catch though: my objective is to print this, so I need to change the mapmode to MM_TWIPS:


pDC->SetMapMode( MM_TWIPS ); //at the beginning of the draw function



...and likewise, I update my coordinates to match the new mapmode (such as y is negative, and the numbers need to be quite larger). If I don't call SelectClipRgn(), the whole bitmap displays, as it should, but when I do call to clip region, nothing displays at all. So in conclusion, everything works as intended before I change mapmodes. Has anyone else solved this problem before? EDIT: Here is the OnDraw() function in its entirety. Note this works if I get rid of the mapmode, and change coordinates back the default coordinate mode.


void CPolyPrintView::OnDraw(CDC* pDC)
{
   CPolyPrintDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   if (!pDoc)
      return;

    CBitmap* pBitmap = pDoc->GetBitmap();

    CDC memDC;
    memDC.CreateCompatibleDC(pDC); 

    pDC->SetMapMode( MM_TWIPS );

    if( pBitmap ) {
        CPalette* pOldPalette;
        CPalette* pPalette = pDoc->GetPalette();

        if( pPalette ) {
            pOldPalette = pDC->SelectPalette(pPalette, FALSE);
            pDC->RealizePalette();
        }

        DIBSECTION ds;
        pBitmap->GetObject( sizeof(DIBSECTION), &ds );        

        CRgn rgn1;

        //plygon region

        CPoint poly[5];
        poly[0].x = 100;
        poly[0].y = -100;
        poly[1].x = 250;
        poly[1].y = -250;
        poly[2].x = 500;
        poly[2].y = -150;
        poly[3].x = 200;
        poly[3].y = -1500;
        poly[4].x = 150;
        poly[4].y = -1000;

        rgn1.CreatePolygonRgn( poly, 5, ALTERNATE );

        pDC->SelectClipRgn(&rgn1);

        CBitmap* pOldBitmap = memDC.SelectObject(pBitmap);        
        pDC->StretchBlt( 0, 0, ds.dsBm.bmWidth*10, -ds.dsBm.bmHeight*10, 
            &memDC, 
            0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
            SRCCOPY );
        
        memDC.SelectObject(pOldBitmap);

        if( pPalette != NULL ) {
            pDC->SelectPalette( pPalette, FALSE );
        }

    }
}


// CFlandersXView printing

BOOL CPolyPrintView::OnPreparePrinting(CPrintInfo* pInfo)
{
    pInfo->SetMaxPage(1);

	return DoPreparePrinting(pInfo);
}

void CPolyPrintView::OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo)
{
	int px, py;
    px = pDC->GetDeviceCaps(HORZRES);
    py = pDC->GetDeviceCaps(VERTRES);

    pInfo->m_rectDraw.SetRect(0, 0, px, py);
}


[Edited by - Scint on March 7, 2006 1:41:45 PM]
Advertisement
Could you show the code as it stands when it doesn't work? It's a little hard to look at working code and figure out why different code that we can't see doesn't work. ;)
You might try using DPtoLP() to convert your values to logical units rather than trying to manually figure them out. It may be that your clip region points are clipping out the image because they are too large. Try using your original (non-MM_TWIPS) values and convert them to logical units via DPtoLP(). Note that all coordinates passed to StretchBlt are supposed to be logical, as well. I'm not sure how that applies to the source coords, since they refer to a different DC, but you might try converting all coordinates as above.

I don't know if that will solve the problem, but it seems logical.
Thanks, the DPtoLP() function does make my code a little easier, since it will convert my coordinates for me. Unfortunately it still isn't working. If I don't change mapmode, SelectClipRgn() returns COMPLEXREGION and properly shows the clipped image. But if I do change mapmode to logical coordinates, SelectClipRgn() returns NULLREGION and nothing gets displayed. I know the coords are good, because if I draw without calling SelectClipRgn() everything is in the right place.

The problem seems to be SelectClipRgn() does not like to be used when the mapmode is in logical units instead of device units.
Hmmm. Just noticed something in the docs for SelectClipRgn:

Quote:MSDN
The SelectClipRgn function assumes that the coordinates for a region are specified in device units.


I suspect that is significant.

It might be easier to do the clipping into a temporary context in default (MM_TEXT) mode. Then blit the temporary to your target context using MM_TWIPS without clipping (since it's already clipped).
Alternately, you could just use LPtoDP to make sure you're giving SelectClipRgn device coordinates =-)
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk

This topic is closed to new replies.

Advertisement