计算优化校准中图像的正确位置,并正确绘制背景(在 MFC 对话框中)

Posted

技术标签:

【中文标题】计算优化校准中图像的正确位置,并正确绘制背景(在 MFC 对话框中)【英文标题】:Calculating correct position of image in Picture Control, and drawing the background correctly (on MFC dialog) 【发布时间】:2020-10-18 19:51:46 【问题描述】:

我有这个对话框:

这是对话框的 RC:

IDD_DIALOG_SPECIAL_EVENT_VIDEOCONF DIALOGEX 0, 0, 541, 233
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
EXSTYLE WS_EX_APPWINDOW
CAPTION "Special Event — Videoconference"
FONT 8, "MS Shell Dlg", 0, 0, 0x1
BEGIN
    GROUPBOX        "Details",IDC_STATIC,7,7,301,201
    LTEXT           "Path to image to display:",IDC_STATIC,15,22,80,8
    CONTROL         "",IDC_BROWSE_SPECIAL_EVENT_VIDEOCONF_PATH_IMAGE,
                    "MfcEditBrowse",WS_BORDER | WS_TABSTOP | 0x880,14,32,288,14
    LTEXT           "50%",IDC_STATIC,13,49,16,8
    CONTROL         "",IDC_SLIDER_SPECIAL_EVENT_VIDEOCONF_IMAGE_WIDTH,
                    "msctls_trackbar32",TBS_AUTOTICKS | TBS_BOTH | WS_TABSTOP,8,58,294,15
    LTEXT           "Width of image:",IDC_STATIC,15,77,52,8
    LTEXT           "%",IDC_STATIC_SPECIAL_EVENT_VIDEOCONF_IMAGE_WIDTH,70,77,19,8
    LTEXT           "Text to display before the image:",IDC_STATIC,15,97,108,8
    EDITTEXT        IDC_EDIT_SPECIAL_EVENT_VIDEOCONF_TEXT_BEFORE_IMAGE,14,109,288,37,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
    LTEXT           "Text to display after the image:",IDC_STATIC,16,152,102,8
    EDITTEXT        IDC_EDIT_SPECIAL_EVENT_VIDEOCONF_TEXT_AFTER_IMAGE,14,163,288,37,ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL
    DEFPUSHBUTTON   "OK",IDOK,198,212,50,14
    PUSHBUTTON      "Cancel",IDCANCEL,252,212,50,14
    LTEXT           "100%",IDC_STATIC,287,48,20,8
    GROUPBOX        "Image Preview",IDC_STATIC,314,7,224,201
    CONTROL         "",IDC_STATIC_IMAGE_PREVIEW,"Static",SS_OWNERDRAW,321,18,210,181
END

上面有一个图片控制。我已将其设置为 Owner Draw。当用户浏览文件时,对话框会将图像加载到CImage

void CSpecialEventVideoconferenceInfoDlg::OnEnChangeBrowseSpecialEventVideoconfPathImage()

    CString strImagePath;
    GetDlgItemText(IDC_BROWSE_SPECIAL_EVENT_VIDEOCONF_PATH_IMAGE, strImagePath);
    m_imgPreview.Load(strImagePath);

而且,渲染是这样的:

void CSpecialEventVideoconferenceInfoDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

    if (nIDCtl == IDC_STATIC_IMAGE_PREVIEW && !m_imgPreview.IsNull())
    
        SetStretchBltMode(lpDrawItemStruct->hDC, HALFTONE);
        CRect dest(lpDrawItemStruct->rcItem);
        float nRatioImage = m_imgPreview.GetWidth() / (float)m_imgPreview.GetHeight();
        float nRatioDest = dest.Width() / (float)dest.Height();
        CRect rectDraw = dest;
        if (nRatioImage > nRatioDest)
            rectDraw.SetRect(0, 0, rectDraw.right, rectDraw.right / nRatioImage);
        else if (nRatioImage < nRatioDest)
            rectDraw.SetRect(0, 0, rectDraw.bottom * nRatioImage, rectDraw.bottom);
        m_imgPreview.Draw(lpDrawItemStruct->hDC, rectDraw);
    

我这里有两个问题目前无法解决:

    图像未集中绘制到我的容器中:

    如果我决定使用另一张图片,图片控件无法正确擦除背景:

更新

如果我这样调整代码:

void CSpecialEventVideoconferenceInfoDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

    if (nIDCtl == IDC_STATIC_IMAGE_PREVIEW && !m_imgPreview.IsNull())
    
        SetStretchBltMode(lpDrawItemStruct->hDC, HALFTONE);
        FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)GetStockObject(WHITE_BRUSH));
        CRect dest(lpDrawItemStruct->rcItem);
        float nRatioImage = m_imgPreview.GetWidth() / (float)m_imgPreview.GetHeight();
        float nRatioDest = dest.Width() / (float)dest.Height();
        CRect rectDraw = dest;
        if (nRatioImage > nRatioDest)
            rectDraw.SetRect(0, 0, rectDraw.right, rectDraw.right / nRatioImage);
        else if (nRatioImage < nRatioDest)
            rectDraw.SetRect(0, 0, rectDraw.bottom * nRatioImage, rectDraw.bottom);
        m_imgPreview.Draw(lpDrawItemStruct->hDC, rectDraw);
    

...它解决了第二个问题。它使用FillRect。所以它只是改变我的代码来集中图片来解决。

【问题讨论】:

【参考方案1】:

这是我的解决方案:

void CSpecialEventVideoconferenceInfoDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)

    if (nIDCtl == IDC_STATIC_IMAGE_PREVIEW && !m_imgPreview.IsNull())
    
        SetStretchBltMode(lpDrawItemStruct->hDC, HALFTONE);
        FillRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)GetStockObject(WHITE_BRUSH));
        CRect dest(lpDrawItemStruct->rcItem);
        float nRatioImage = m_imgPreview.GetWidth() / (float)m_imgPreview.GetHeight();
        float nRatioDest = dest.Width() / (float)dest.Height();
        CRect rectDraw = dest;
        if (nRatioImage > nRatioCanvas)
            rectDraw.SetRect(0, 0, rectDraw.right, (int)(rectDraw.right / nRatioImage));
        else if (nRatioImage < nRatioCanvas)
            rectDraw.SetRect(0, 0, (int)(rectDraw.bottom * nRatioImage), rectDraw.bottom);

        rectDraw.DeflateRect(5, 5);
        CSize ptOffset = dest.CenterPoint() - rectDraw.CenterPoint();
        rectDraw.OffsetRect(ptOffset);
        FrameRect(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
        m_imgPreview.Draw(lpDrawItemStruct->hDC, rectDraw);
    

    我使用FillRect 擦除背景。 我使用CenterPointOffsetRect 来设计新中心。 我使用FrameRect 在图像周围添加一个漂亮的矩形。

【讨论】:

以上是关于计算优化校准中图像的正确位置,并正确绘制背景(在 MFC 对话框中)的主要内容,如果未能解决你的问题,请参考以下文章

calc() 是不是适用于 CSS 中图像的背景大小?

响应 Ktor 中图像的缓存标头

通过传递的参数位置获取jQuery中图像的宽度? [复制]

相对于情节提要中图像的特定点定位元素

获取 Canvas 中图像的更新高度

如何使节点画布中图像的大小始终为 128 像素