Win32 GetPixel () возвращает неправильные значения, тогда как SetPixel () работает нормально, даже когда включена поддержка DPI - PullRequest
0 голосов
/ 26 ноября 2018

Я боролся с этой проблемой в течение всего дня, и я до сих пор не добился никакого прогресса.

КОНТЕКСТ

Я пытаюсь воспроизвести виртуальную клавиатуру пианино (управляемую с помощью файлов MIDI) на светодиодах, прикрепленных к физической клавиатуре, чтобы моя жена могла научиться играть на пианино быстрее (рождественский подарок),Вот изображение программы: enter image description here

ЧТО ДЕЛАЕТ КОД

(или должен делать) Я ввожу координаты клавиатуры, измеренные вPaint.NET сделав скриншот программы в полноэкранном режиме.Пользователю предлагается поставить программное обеспечение на весь экран.Затем я вычисляю координаты середины всех клавиш и получаю цвет ключа, когда он не активирован.Наконец, я проверяю, что все белые клавиши имеют одинаковый цвет, и что черные клавиши имеют одинаковый цвет (чтобы убедиться, что клавиатура отображается правильно).Позже я зациклюсь навсегда, получая цвет каждой клавиши и подсвечивая соответствующий светодиод на физической клавиатуре, если цвет этой клавиши изменился из состояния «покоя».

ПРОБЛЕМА

Я знаю, что выбираю цвета в нужном месте, потому что SetPixel () отображает красные пиксели в середине всех клавиш (как видно из кода).Однако GetPixel по-прежнему часто возвращает неправильные значения (1/4 времени для белых клавиш, всегда для черных).Что происходит?

ЧТО Я ПОПЫТАЛ

A добавил в проект файл манифеста, который успешно изменил размер рабочего стола до правильного значения 1920x1080 - но даже при том, что значения RGB немного изменилисьони все еще отключены - я добавил функцию captureAndSave () на тот случай, если компьютер «видит» что-то другое, чем я, когда я делаю снимок экрана (чтобы получить все входные координаты), или что-либо еще, что SetPixel (), потому что это работает- но изображение действительно идентично, поэтому я не знаю, что происходит.- Многие отладочные прогоны ...

CODE

(перейдите к VirtualKeyboard :: init ())

#include <iostream>
#include <windows.h>

using namespace std;

const unsigned int N_WHITE_KEYS = 49;
const unsigned int N_PIANO_KEYS = N_WHITE_KEYS+35;
const unsigned int N_ABSENT_BLK_KEYS = N_WHITE_KEYS*2-N_PIANO_KEYS-1;
const unsigned int ABSENT_BLK_KEYS[N_ABSENT_BLK_KEYS] = {3,7,10,14,17,21,24,28,31,35,38,42,45}; //TODO: find a formula rather than this list

const unsigned int VKxLeft = 19,
                   VKyTop = 150,
                   VKxRight = 1731,
                   VKyBtm = 324;


//TEMP
#include <stdio.h>

bool captureAndSave(const HWND& hWnd, int nBitCount, const char* szFilePath)
{
    if(!szFilePath || !strlen(szFilePath))
    {
        cout << "bad function arguments\n";
        return false;
    }

    //calculate the number of color indexes in the color table
    int nColorTableEntries = -1;
    switch(nBitCount)
    {
        case 1:
            nColorTableEntries = 2;
            break;
        case 4:
            nColorTableEntries = 16;
            break;
        case 8:
            nColorTableEntries = 256;
            break;
        case 16:
        case 24:
        case 32:
            nColorTableEntries = 0;
            break;
        default:
            nColorTableEntries = -1;
            break;
    }

    if(nColorTableEntries == -1)
    {
        cout << "bad bits-per-pixel argument\n";
        return false;
    }

    HDC hDC = GetDC(hWnd);
    HDC hMemDC = CreateCompatibleDC(hDC);

    int nWidth = 0;
    int nHeight = 0;

    if(hWnd != HWND_DESKTOP)
    {
        RECT rect;
        GetClientRect(hWnd, &rect);
        nWidth = rect.right - rect.left;
        nHeight = rect.bottom - rect.top;
    }
    else
    {
        nWidth = ::GetSystemMetrics(SM_CXSCREEN);
        nHeight = ::GetSystemMetrics(SM_CYSCREEN);
    }


    HBITMAP hBMP = CreateCompatibleBitmap(hDC, nWidth, nHeight);
    SelectObject(hMemDC, hBMP);
    BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);

    int nStructLength = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
    LPBITMAPINFOHEADER lpBitmapInfoHeader = (LPBITMAPINFOHEADER)new char[nStructLength];
    ::ZeroMemory(lpBitmapInfoHeader, nStructLength);

    lpBitmapInfoHeader->biSize = sizeof(BITMAPINFOHEADER);
    lpBitmapInfoHeader->biWidth = nWidth;
    lpBitmapInfoHeader->biHeight = nHeight;
    lpBitmapInfoHeader->biPlanes = 1;
    lpBitmapInfoHeader->biBitCount = nBitCount;
    lpBitmapInfoHeader->biCompression = BI_RGB;
    lpBitmapInfoHeader->biXPelsPerMeter = 0;
    lpBitmapInfoHeader->biYPelsPerMeter = 0;
    lpBitmapInfoHeader->biClrUsed = nColorTableEntries;
    lpBitmapInfoHeader->biClrImportant = nColorTableEntries;

    DWORD dwBytes = ((DWORD) nWidth * nBitCount) / 32;
    if(((DWORD) nWidth * nBitCount) % 32) {
        dwBytes++;
    }
    dwBytes *= 4;

    DWORD dwSizeImage = dwBytes * nHeight;
    lpBitmapInfoHeader->biSizeImage = dwSizeImage;

    LPBYTE lpDibBits = 0;
    HBITMAP hBitmap = ::CreateDIBSection(hMemDC, (LPBITMAPINFO)lpBitmapInfoHeader, DIB_RGB_COLORS,  (void**)&lpDibBits, NULL, 0);
    SelectObject(hMemDC, hBitmap);
    BitBlt(hMemDC, 0, 0, nWidth, nHeight, hDC, 0, 0, SRCCOPY);
    ReleaseDC(hWnd, hDC);

    BITMAPFILEHEADER bmfh;
    bmfh.bfType = 0x4d42;  // 'BM'
    int nHeaderSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;
    bmfh.bfSize = 0;
    bmfh.bfReserved1 = bmfh.bfReserved2 = 0;
    bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * nColorTableEntries;

    FILE *pFile = 0;
    pFile = fopen(szFilePath, "wb");
    if(!pFile)
    {
        ::DeleteObject(hBMP);
        ::DeleteObject(hBitmap);
        delete[]lpBitmapInfoHeader;
        cout << "can not open file\n";
        return false;
    }

    DWORD nColorTableSize = 0;
    if (nBitCount != 24)
        nColorTableSize = (1 << nBitCount) * sizeof(RGBQUAD);
    else
        nColorTableSize = 0;


    fwrite(&bmfh, sizeof(BITMAPFILEHEADER), 1, pFile);
    fwrite(lpBitmapInfoHeader, nHeaderSize,1,pFile);

    if(nBitCount < 16)
    {
        int nBytesWritten = 0;
        RGBQUAD *rgbTable = new RGBQUAD[nColorTableEntries * sizeof(RGBQUAD)];
        //fill RGBQUAD table and write it in file
        for(int i = 0; i < nColorTableEntries; ++i)
        {
            rgbTable[i].rgbRed = rgbTable[i].rgbGreen = rgbTable[i].rgbBlue = i;
            rgbTable[i].rgbReserved = 0;

            fwrite(&rgbTable[i], sizeof(RGBQUAD), 1, pFile);
        }
        delete[]rgbTable;

        /*
        RGBQUAD rgb;
        for (DWORD i = 0; i < nColorTableEntries ; i++)
        {
            rgb.rgbBlue = rgb.rgbGreen = rgb.rgbRed = (BYTE)(i*(255/(nColorTableEntries-1)));
            nBytesWritten = fwrite(&rgb, 1, sizeof(rgb), pFile);
            if (nBytesWritten != sizeof(rgb))
            {
                printf("error while writing rgb header\n");
                fclose(pFile);

                ::DeleteObject(hBMP);
                ::DeleteObject(hBitmap);
                delete[]lpBitmapInfoHeader;

                return false;
            }
        }
        */
    }

    fwrite(lpDibBits, dwSizeImage, 1, pFile);

    fclose(pFile);

    ::DeleteObject(hBMP);
    ::DeleteObject(hBitmap);
    delete[]lpBitmapInfoHeader;
}
//End TEMP


inline bool SameColours(COLORREF const &a, COLORREF const &b) {
    bool ret = true;

    ret &= GetRValue(a) == GetRValue(b);
    ret &= GetGValue(a) == GetGValue(b);
    ret &= GetBValue(a) == GetBValue(b);

    return ret;
}

class VirtualKeyboard
{
    COLORREF keyColUnpressed[N_PIANO_KEYS];
    unsigned int keyX[N_PIANO_KEYS]; //White then black, from left to right
    unsigned int keyY[N_PIANO_KEYS]; //White then black, from left to right

public:
    bool init(unsigned int xLeft, unsigned int yTop, unsigned int xRight, unsigned yBtm) {
        bool ret = true;

        //Calculate parameters of the virtual keyboard
        const float whtKeyHeight = (yBtm-yTop);
        const float whtKeyWidth = float(xRight-xLeft)/(N_WHITE_KEYS);

        //Calculate coordinates of the white keys
        for(unsigned int i = 0; i < N_WHITE_KEYS ; ++i) {
            keyX[i]=xLeft+(i+1.f/2)*float(whtKeyWidth);
            keyY[i]=yTop+3.f/4*float(whtKeyHeight);
        }

        //Calculate coordinates of the black keys
        unsigned int iBlkKey = 0;
        for(unsigned int i = 0 ; i < N_WHITE_KEYS-1 ; ++i) {
            //Determine if there is a black key
            bool skip = false;

            //Some black keys are absent from the offset white keys pattern - skip if applicable
            for(unsigned int j = 0 ; j < N_ABSENT_BLK_KEYS ; ++j) {
                if(i+1 == ABSENT_BLK_KEYS[j]) {
                    skip = true;
                    break;
                }
            }

            //If that key exists, add it to the list
            if(!skip) {
                keyX[iBlkKey+N_WHITE_KEYS]=xLeft+whtKeyWidth*(i+1);
                keyY[iBlkKey+N_WHITE_KEYS]=yTop+1.f/4*float(whtKeyHeight);
                iBlkKey++;
            }
        }

        //Capture the screen
        HDC hdcScreen = ::GetDC(GetDesktopWindow());
        captureAndSave(GetDesktopWindow(),32,"./capture.bmp");
        //And fill in the colors "at rest" for all the keys
        for(unsigned int i = 0 ; i < N_PIANO_KEYS ; ++i) {
            keyColUnpressed[i] = ::GetPixel(hdcScreen, keyX[i], keyY[i]);
            unsigned int r = GetRValue(keyColUnpressed[i]);
            unsigned int g = GetGValue(keyColUnpressed[i]);
            unsigned int b = GetBValue(keyColUnpressed[i]);

            ::SetPixel(hdcScreen, keyX[i], keyY[i], RGB(255,0,0)); //DEBUG: Breakpoint on this line, the RGB values are wrong for some keys (e.g. i=8 and all blacks)
            Sleep(100);
        }
        ReleaseDC(GetDesktopWindow(),hdcScreen);

        //Sanity check : all white keys should have the same colour, and all black keys their own colour as well
        for(unsigned int i = 1 ; i < N_PIANO_KEYS ; ++i) {
            if(i != 1 && i != N_WHITE_KEYS) {
                if(
                    !SameColours(
                                    keyColUnpressed[i],(i < N_WHITE_KEYS ? keyColUnpressed[0]
                                                                         : keyColUnpressed[N_WHITE_KEYS])
                                )
                  )
                {
                    ret = false;
                    break;
                }
            }
        }

        return 0;
    }
};


int main()
{
    VirtualKeyboard vk;

    cout << "You have 3 seconds to minimize this window and maximise MidiSheetMusic" << endl;
    Sleep(3000);

    cout << "Result of init() : " << vk.init(VKxLeft, VKyTop, VKxRight, VKyBtm) << endl;

    while(1)
    {
        //Get all keys pixels and reproduce on the LEDs on the physical keyboard
        Sleep(10); //Runs while not Ctrl+c
    }

    return 0;
}

Заранее большое спасибо.

...