1
votes

We're currently shifting an older application to draw through GDI+, instead of using GDI directly. As we are progressively translating teh system as we go, sometimes we need to grab a HDC from a Gdiplus::Graphics object in order to allow code which hasn't been translated yet to draw straight to it using GDI.

The drawing happens fine, except we seem to be losing antialias on images drawn directly to the DC using GDI. If, after grabbing the DC from the Graphics object, we draw a filled rectangle over the entire area, and then proceed with the drawing, it comes out fine. If we just get straight to drawing everything comes in without antialias.

void Draw(Gdiplus::Graphics& renderContext)
{
    auto hdc = renderContext.GetHDC();
    auto dc = HDC::FromHandle(nativeDC);

    //Required to antialias drawing below
    dc->FillSolidRect(GetClientRect(), RGB(255, 255, 255));
    /* Do Drawing */

    dc ->Detach();
    renderContext.ReleaseHDC(hdc );
}

To be more precise, it seems like the antialias alpha get's flattened, which explains why filling a rectangle in GDI before drawing removes the artifacts. It's a similar effect you might get if you draw with antialias on onto one Bitmap, and then try to alphablend it on top of another Bitmap - the alpha information on the top gets flattened and then the new alpha value specified in a ColorMatrix is applied to the whole image.

If anyone could provide some insight into what exactly is going on when you grab/release a HDC from a graphics object, and why drawing with GDI directly looses the alpha, I'd be appreciated.

1
Images are not anti-aliased. If the image contains transparent pixels (alpha < 255) then the background you use matters a great deal. If the image is resized when it is drawn then Graphics::SetInterpolationMode() matters a great deal.Hans Passant

1 Answers

1
votes

The bitmap backing the HDC is a copy, not the original, as described here.

Using GDI on a GDI+ Graphics Object Backed by a Bitmap

When Graphics::GetHDC() is called for a Graphics object that is backed by a bitmap rather than the screen, a memory HDC is created and a new HBITMAP is created and selected into the memory HDC. This new memory bitmap is not initialized with the original bitmap's image but rather with a sentinel pattern, which allows GDI+ to track changes to the bitmap. Any changes that are made to the memory bitmap through the use of GDI code become apparent in changes to the sentinel pattern. When Graphics::ReleaseHDC() is called, those changes are copied back to the original bitmap... Also, there is a performance cost to this approach because GDI+ must copy the changes back to the original bitmap.

Obviously when you draw on an HDC with GDI you won't get any antialiasing. GDI doesn't support it. That's what GDI+ is for.