【问题标题】:Rotating HDC using WinGDI使用 WinGDI 旋转 HDC
【发布时间】:2018-09-01 10:39:05
【问题描述】:

这篇文章代码密集,所以忽略第一个块。它只是作为参考,以了解该功能最初是如何工作的。

我目前正在尝试在以下代码中对 hdcText 执行 -270 或 90 度旋转:

    void CImageWindow::Show()
        {
            BITMAP bm;
            PAINTSTRUCT ps;
            //Start Drawing Segment
            int iWidth = m_rLocation.right - m_rLocation.left;
            int iHeight = m_rLocation.bottom - m_rLocation.top;

            //Drawing plane for this window
            HDC hdcScreen = BeginPaint(m_hWindow, &ps);
            HBITMAP hWorking = CreateCompatibleBitmap(hdcScreen, iWidth,iHeight);
            SelectObject(hdcScreen, hWorking);
            SetStretchBltMode(hdcScreen, HALFTONE);
            SetBrushOrgEx(hdcScreen,0,0,0);

            //Background
            HDC hdcMem = CreateCompatibleDC(hdcScreen);
            HBITMAP hBmp = (HBITMAP)LoadImage(m_hInstance, m_sTexture.c_str(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
            SelectObject(hdcMem, hBmp);
            GetObject(hBmp, sizeof(bm), &bm);
            StretchBlt(hdcScreen,0,0, iWidth, iHeight, hdcMem, 0,0,bm.bmWidth,bm.bmHeight, SRCCOPY);

            //Text
            HDC hdcText = CreateCompatibleDC(hdcScreen);
            HBITMAP hbmpText = CreateCompatibleBitmap(hdcText, iWidth,iHeight);
            SelectObject(hdcText, hbmpText);
            RECT rTextLoc;
            rTextLoc.top = iHeight/4;
            rTextLoc.bottom = 3 * iHeight / 4;
            rTextLoc.left = iWidth / 4;
            rTextLoc.right =3 * iWidth / 4;
            SetTextColor(hdcText, RGB(255,255,255));
            SetBkMode(hdcText, TRANSPARENT);
            HFONT hfFont = CreateFont((iHeight/2) - 2, 0,0,0,0,0,0,0,0,0,0,0,0,"Tahoma"); //-2 to ensure it can fit in the rectangle
            SelectObject(hdcText, hfFont);
            DrawText(hdcText, m_sIdentifier.c_str(), -1, &rTextLoc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
            StretchBlt(hdcScreen, 0,0,iWidth,iHeight, hdcText, 0,0,iWidth,iHeight, SRCINVERT);

            if(m_bFlipped)
                StretchBlt(hdcScreen, iWidth,iHeight,-iWidth,-iHeight, hdcScreen, 0,0,iWidth,iHeight, SRCCOPY);

             DeleteObject(hWorking);
             DeleteObject(hBmp);
             DeleteObject(hbmpText);

             DeleteObject(hfFont);

             DeleteObject(hdcMem);
             DeleteObject(hdcText);

             EndPaint( m_hWindow, &ps );

        }

我已尝试执行以下操作来解决此问题。

  1. 使用 XForm 旋转 HDC。

这对 hdcText 的位置没有任何影响。我不确定为什么,而且信息很少。

注意:我使用过 XForm 值,所以即使这些值不正确,我认为这不是问题。

    void CImageWindow::Show()
        {
            BITMAP bm;
            PAINTSTRUCT ps;
            //Start Drawing Segment
            int iWidth = m_rLocation.right - m_rLocation.left;
            int iHeight = m_rLocation.bottom - m_rLocation.top;

            //Drawing plane for this window
            HDC hdcScreen = BeginPaint(m_hWindow, &ps);
            HBITMAP hWorking = CreateCompatibleBitmap(hdcScreen, iWidth,iHeight);
            SelectObject(hdcScreen, hWorking);
            SetStretchBltMode(hdcScreen, HALFTONE);
            SetBrushOrgEx(hdcScreen,0,0,0);

            //Background
            HDC hdcMem = CreateCompatibleDC(hdcScreen);
            HBITMAP hBmp = (HBITMAP)LoadImage(m_hInstance, m_sTexture.c_str(), IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
            SelectObject(hdcMem, hBmp);
            GetObject(hBmp, sizeof(bm), &bm);
            StretchBlt(hdcScreen,0,0, iWidth, iHeight, hdcMem, 0,0,bm.bmWidth,bm.bmHeight, SRCCOPY);

            //Text
            HDC hdcText = CreateCompatibleDC(hdcScreen);
            //Added
            SetGraphicsMode(hdcText, GM_ADVANCED);
            SetMapMode(hdcText, MM_TEXT); 

            HBITMAP hbmpText = CreateCompatibleBitmap(hdcText, iWidth,iHeight);
            SelectObject(hdcText, hbmpText);

            RECT rTextLoc;
            rTextLoc.top = iHeight/4;
            rTextLoc.bottom = 3 * iHeight / 4;
            rTextLoc.left = iWidth / 4;
            rTextLoc.right =3 * iWidth / 4;
            SetTextColor(hdcText, RGB(255,255,255));
            SetBkMode(hdcText, TRANSPARENT);

            lf.lfWeight = FW_NORMAL;
            lstrcpy(lf.lfFaceName, _T("Tahoma"));
            float iAngle = 2700;
            //float fAngle = -static_cast<float>(iAngle) * static_cast<float>(M_PI) / 180.0f; 

            rTextLoc.top = iHeight/4;
            rTextLoc.bottom = 3 * iHeight / 4;
            rTextLoc.left = iWidth / 4;
            rTextLoc.right =3 * iWidth / 4;

            HFONT hFont = CreateFont((iHeight/2) - 2, 0,0,0,0,0,0,0,0,0,0,0,0,"Tahoma"); //-2 to ensure it can fit in the rectangle

            long y = (rTextLoc.bottom - rTextLoc.top) / 2;
            long x = (rTextLoc.right - rTextLoc.left) / 2;
            XFORM xForm;
            float iAngle = 270;
            float fAngle = -static_cast<float>(iAngle) * static_cast<float>(M_PI) / 180.0f;         
xForm.eM11 = (FLOAT) cos(fAngle);
            xForm.eM12 = (FLOAT) sin(fAngle);
            xForm.eM21 = (FLOAT) -sin(fAngle);
            xForm.eM22 = (FLOAT) cos(fAngle);
            xForm.eDx  = (FLOAT) (x * (1 - cos(fAngle))) + (sin(fAngle) * y);
            xForm.eDy  = (FLOAT) (-sin(fAngle) * x) + (y * (1 - cos(fAngle)));


                xForm.eDx += (FLOAT) ((rTextLoc.bottom - rTextLoc.top) / 2) - ((rTextLoc.right - rTextLoc.left) / 2);
                xForm.eDy += (FLOAT) ((rTextLoc.bottom - rTextLoc.top) / 2) - ((rTextLoc.right - rTextLoc.left) / 2);

            SetWorldTransform(hdcScreen, &xForm); 
            SetGraphicsMode(hdcText, GM_COMPATIBLE);

            SelectObject(hdcText, hFont);
            DrawText(hdcText, m_sIdentifier.c_str(), -1, &rTextLoc, DT_CENTER | DT_SINGLELINE | DT_VCENTER);
            StretchBlt(hdcScreen, 0,0,iWidth,iHeight, hdcText, 0,0,iWidth,iHeight, SRCINVERT);
            ReleaseDC(m_hWindow, hdcText);

            if(m_bFlipped)
                StretchBlt(hdcScreen, iWidth,iHeight,-iWidth,-iHeight, hdcScreen, 0,0,iWidth,iHeight, SRCCOPY);

             DeleteObject(hWorking);
             DeleteObject(hBmp);
             DeleteObject(hbmpText);

             DeleteObject(hFont);

             DeleteObject(hdcMem);
             DeleteObject(hdcText);

             EndPaint( m_hWindow, &ps );

        }
  1. 使用 LOGFONT 进行旋转。我已经设置了 lfEscapement 和 lfOrientation 的值。文本在移动,但仅在擒纵矢量上。期望的结果是在设定点上进行旋转。

感谢任何帮助。

【问题讨论】:

  • SetWorldTransform 函数将失败,除非通过先前调用 SetGraphicsMode 函数将给定设备上下文的图形模式设置为 GM_ADVANCED”。您确实调用了SetGraphicsMode,但不在您调用SetWorldTransform 的HDC 上。检查返回值 - 调用可能失败。
  • "使用 LOGFONT 进行旋转。我已经设置了 lfEscapement lf.Orientation 的值。文本在移动,但仅在擒纵矢量上。期望的结果是在设定点上进行旋转。"你能解释一下这是什么意思吗?你的意思是要指定旋转的中心?
  • 对@IgorTandetnik 的回复:我已经更改了它,现在我尝试旋转的 HDC 值没有显示在屏幕上。
  • @JerryCoffin 我想将屏幕上的文本逆时针旋转 270 度,即文本的方向。发生的事情是该值沿擒纵矢量移动,而不是在其原始位置上旋转。即使我没有设置 lfEscapement 的值,也会发生这种情况。
  • @Dprog:“值沿擒纵矢量移动”并不能解释太多,至少对我而言。也许你可以画一张图来帮助像我这样慢的人理解什么? (不,我不是在讽刺——老实说,我对正在发生的事情或你想要什么感到迷茫。

标签: c++ gdi


【解决方案1】:

基于 cmets,您显然希望旋转打印输出的字符串中的各个字符,而不改变字符串本身的基线角度。

为此,您希望将lfEscapement 保留为0,并仅更改字体的lfOrientation。要创建lfEscapementlfOrientation 具有不同值的字体,您需要设置“高级”图形模式,因此序列如下所示:

SetGraphicsMode(yourDC, GM_ADVANCED);
HFONT font = CreateFont(20, 0, 0, 1800, FW_NORMAL, 0, 0, 0, FF_SWISS,
                        OUT_OUTLINE_PRECIS, CLIP_CHARACTER_PRECIS, CLEARTYPE_QUALITY,
                        ANSI_CHARSET, L"Arial");

auto old_font = SelectObject(yourDC, font);

TextOutW(yourDC, 50, 50, L"Your Text");

你的结果应该是这样的:

当然,如果您希望文字颠倒(如评论中的链接所示),您需要将 lfOrientation 更改为 1800,以获得如下结果:

附带说明一下,对于某些中间角度,字距调整可能会变得非常时髦。例如旋转 130 度:

委婉地说,相当糟糕。

【讨论】:

  • 在我创建 LOGFONT lf 并通过 lf.lfOrientation 访问方向之前更改方向时。这没有用。然而,改变 CreateFont 函数的方向就像一个魅力。干杯杰瑞。
猜你喜欢
  • 2019-02-26
  • 2013-06-13
  • 2011-08-30
  • 2011-01-21
  • 2011-11-27
  • 2018-01-30
  • 2018-05-01
  • 2012-04-12
  • 1970-01-01
相关资源
最近更新 更多