Taking screenshot is zoomed and clipped under Retina display

Do you have a typical platform dependent issue you're battling with ? Ask it here. Make sure you mention your platform, compiler, and wxWidgets version.
Post Reply
Anil8753
Experienced Solver
Experienced Solver
Posts: 93
Joined: Sat Jan 16, 2016 5:57 am
Location: India

Taking screenshot is zoomed and clipped under Retina display

Post by Anil8753 »

I am trying to take a screenshot of a window. I have used the following code.

Code: Select all

    wxClientDC bgdc(this);

    int width = bgdc.GetSize().GetWidth();
    int height = bgdc.GetSize().GetHeight();

    //Create a Bitmap that will later on hold the screenshot image
    //Note that the Bitmap must have a size big enough to hold the screenshot
    //-1 means using the current default colour depth
    wxBitmap bmpWin = wxBitmap(m_width, m_height, -1);

    wxMemoryDC memDC;
    memDC.SelectObject(bmpWin);
    memDC.Blit(0, 0, width, height, &bgdc, 0, 0);

    wxASSERT(bmpWin.IsOk());
This code works perfectly under Windows.
On Mac I am facing the issue. Captured bitmap is zoomed and goes out of width and height value, hence clipped.

I am not sure what is wrong with the code.

Note* This is happening on Retina display only
Manolo
Can't get richer than this
Can't get richer than this
Posts: 827
Joined: Mon Apr 30, 2012 11:07 pm

Re: Taking screenshot is zoomed and clipped under Retina display

Post by Manolo »

Retina has its own style. wxWindow::FromDIP() may help
http://docs.wxwidgets.org/trunk/classwx ... a1100b0dc5
Anil8753
Experienced Solver
Experienced Solver
Posts: 93
Joined: Sat Jan 16, 2016 5:57 am
Location: India

Re: Taking screenshot is zoomed and clipped under Retina display

Post by Anil8753 »

wxWidgets 2.9 handled it nicely and this issue came in wxWidgets 3.x.x
When I checked the changes, I found the difference in wxGCDCImpl::DoStretchBlit implementation in 2.9 and 3.0

wxWidgets 2.9

Code: Select all

bool wxGCDCImpl::DoStretchBlit(
    wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight,
    wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight,
    wxRasterOperationMode logical_func , bool useMask,
    wxCoord xsrcMask, wxCoord ysrcMask )
{
    wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") );
    wxCHECK_MSG( source->IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") );

    if ( logical_func == wxNO_OP )
        return true;

    wxCompositionMode mode = TranslateRasterOp(logical_func);
    if ( mode == wxCOMPOSITION_INVALID )
    {
        wxFAIL_MSG( wxT("Blitting is not supported with this logical operation.") );
        return false;
    }

    bool retval = true;

    wxCompositionMode formerMode = m_graphicContext->GetCompositionMode();
    if (m_graphicContext->SetCompositionMode(mode))
    {
        wxAntialiasMode formerAa = m_graphicContext->GetAntialiasMode();
        if (mode == wxCOMPOSITION_XOR)
        {
            m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE);
        }

        if (xsrcMask == -1 && ysrcMask == -1)
        {
            xsrcMask = xsrc;
            ysrcMask = ysrc;
        }

        wxRect subrect(source->LogicalToDeviceX(xsrc),
                       source->LogicalToDeviceY(ysrc),
                       source->LogicalToDeviceXRel(srcWidth),
                       source->LogicalToDeviceYRel(srcHeight));

        // if needed clip the subrect down to the size of the source DC
        wxCoord sw, sh;
        source->GetSize(&sw, &sh);
        sw = source->LogicalToDeviceXRel(sw);
        sh = source->LogicalToDeviceYRel(sh);
        if (subrect.x + subrect.width > sw)
            subrect.width = sw - subrect.x;
        if (subrect.y + subrect.height > sh)
            subrect.height = sh - subrect.y;

        wxBitmap blit = source->GetAsBitmap( &subrect );

        if ( blit.IsOk() )
        {
            if ( !useMask && blit.GetMask() )
                blit.SetMask(NULL);

            m_graphicContext->DrawBitmap( blit, xdest, ydest,
                                          dstWidth, dstHeight);
        }
        else
        {
            wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
            retval = false;
        }

        if (mode == wxCOMPOSITION_XOR)
        {
            m_graphicContext->SetAntialiasMode(formerAa);
        }
    }
    // reset composition
    m_graphicContext->SetCompositionMode(formerMode);

    return retval;
}

wxWidgets 3.0

Code: Select all

bool wxGCDCImpl::DoStretchBlit(
    wxCoord xdest, wxCoord ydest, wxCoord dstWidth, wxCoord dstHeight,
    wxDC *source, wxCoord xsrc, wxCoord ysrc, wxCoord srcWidth, wxCoord srcHeight,
    wxRasterOperationMode logical_func , bool useMask,
    wxCoord xsrcMask, wxCoord ysrcMask )
{
    wxCHECK_MSG( IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid DC") );
    wxCHECK_MSG( source->IsOk(), false, wxT("wxGCDC(cg)::DoStretchBlit - invalid source DC") );

    if ( logical_func == wxNO_OP )
        return true;

    wxCompositionMode mode = TranslateRasterOp(logical_func);
    if ( mode == wxCOMPOSITION_INVALID )
    {
        wxFAIL_MSG( wxT("Blitting is not supported with this logical operation.") );
        return false;
    }

    wxRect subrect(source->LogicalToDeviceX(xsrc),
                   source->LogicalToDeviceY(ysrc),
                   source->LogicalToDeviceXRel(srcWidth),
                   source->LogicalToDeviceYRel(srcHeight));
    const wxRect subrectOrig = subrect;
    // clip the subrect down to the size of the source DC
    wxRect clip;
    source->GetSize(&clip.width, &clip.height);
    subrect.Intersect(clip);
    if (subrect.width == 0)
        return true;

    bool retval = true;

    wxCompositionMode formerMode = m_graphicContext->GetCompositionMode();
    if (m_graphicContext->SetCompositionMode(mode))
    {
        wxAntialiasMode formerAa = m_graphicContext->GetAntialiasMode();
        if (mode == wxCOMPOSITION_XOR)
        {
            m_graphicContext->SetAntialiasMode(wxANTIALIAS_NONE);
        }

        if (xsrcMask == -1 && ysrcMask == -1)
        {
            xsrcMask = xsrc;
            ysrcMask = ysrc;
        }

        wxBitmap blit = source->GetAsBitmap( &subrect );

        if ( blit.IsOk() )
        {
            if ( !useMask && blit.GetMask() )
                blit.SetMask(NULL);

            double x = xdest;
            double y = ydest;
            double w = dstWidth;
            double h = dstHeight;
            // adjust dest rect if source rect is clipped
            if (subrect.width != subrectOrig.width || subrect.height != subrectOrig.height)
            {
                x += (subrect.x - subrectOrig.x) / double(subrectOrig.width) * dstWidth;
                y += (subrect.y - subrectOrig.y) / double(subrectOrig.height) * dstHeight;
                w *= double(subrect.width) / subrectOrig.width;
                h *= double(subrect.height) / subrectOrig.height;
            }
            m_graphicContext->DrawBitmap(blit, x, y, w, h);
        }
        else
        {
            wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") );
            retval = false;
        }

        if (mode == wxCOMPOSITION_XOR)
        {
            m_graphicContext->SetAntialiasMode(formerAa);
        }
    }
    // reset composition
    m_graphicContext->SetCompositionMode(formerMode);

    CalcBoundingBox(xdest, ydest);
    CalcBoundingBox(xdest + dstWidth, ydest + dstHeight);

    return retval;
}

I can see refactoring is done in wxWidgets 3.0 and can see the following line are missing from wxWindgets 3.0. When I placed back these two line issue is fixed.

Code: Select all

        sw = source->LogicalToDeviceXRel(sw);
        sh = source->LogicalToDeviceYRel(sh);

Could anyone please confirm the reason of removing these lines.
Manolo
Can't get richer than this
Can't get richer than this
Posts: 827
Joined: Mon Apr 30, 2012 11:07 pm

Re: Taking screenshot is zoomed and clipped under Retina display

Post by Manolo »

You should better ask at https://groups.google.com/forum/?fromgr ... rum/wx-dev
Or if you confirm it's a bug, open a ticket at http://trac.wxwidgets.org/wiki
Post Reply