Вращение HDC с использованием WinGDI - PullRequest
0 голосов
/ 30 августа 2018

Этот пост имеет плотность кода, поэтому игнорируйте первый блок. Это только для справки, чтобы увидеть, как изначально работала функция.

В настоящее время я пытаюсь выполнить поворот на 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. Текст движется, но только по вектору спуска. Желаемый результат заключается в повороте на заданную точку.

Любая помощь приветствуется.

1 Ответ

0 голосов
/ 31 августа 2018

Исходя из комментариев, вы, очевидно, хотите повернуть отдельные символы в строке, которую вы печатаете, без изменения угла базовой линии самой строки.

Чтобы сделать это, вы должны оставить lfEscapement на 0 и изменить только lfOrientation шрифта. Чтобы создать шрифт, в котором lfEscapement и lfOrientation имеют разные значения, необходимо установить «расширенный» графический режим, чтобы последовательность выглядела следующим образом:

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");

И ваш результат должен выглядеть примерно так:

enter image description here

Конечно, если вы хотите, чтобы текст был перевернут (как показано в ссылке в вашем комментарии), вам нужно изменить lfOrientation на 1800, чтобы получить такой результат:

enter image description here

Как примечание стороны, кернинг может стать довольно забавным для некоторых промежуточных углов. Например, при повороте на 130 градусов:

enter image description here

Довольно плохо, мягко говоря.

...