Как работать с адской SetDIBitsToDevice?

451
16 мая 2017, 05:02

Здравствуйте! Помогите разобраться с SetDIBitsToDevice. В программе, в которую я хочу внедрить эту функцию, используется двойная буферизация, на конечный HDC выводиться всё с помощью ф-ии BitBlt. Естественно проблемы с производительностью. Раньше, при изучении, пропустил мимо SetDIBitsToDevice, теперь понял что она, видимо то что мне нужно.

Итак, если я правильно понял алгоритм таков:

Создаём массив, который будет нашей "матрицей" - создаём BITMAPINFO, заполняем - "рисуем" в нашей "матрице" - вызываем SetDIBitsToDevice.

Код ниже выполнятся правильно, видим розовый фон и чёрный квадрат.

    BITMAPINFO bif;
    ZeroMemory(&bif, sizeof(BITMAPINFO));
    bif.bmiHeader.biSize = sizeof(bif);
    RGBQUAD *im = new RGBQUAD[r.right*r.bottom];
    for (int i(0); i < r.right*r.bottom; i++)
    {
        im[i].rgbBlue = 255;
        im[i].rgbRed = 255;
        im[i].rgbGreen = 0;
    }
    for (int i(0); i < 200; i++)
        for (int ii(0); ii < 200; ii++)
    {
        if (r.right*i + ii < r.right*r.bottom)
        {
            im[r.right*i + ii].rgbBlue = 0;
            im[r.right*i + ii].rgbRed = 0;
            im[r.right*i + ii].rgbGreen = 0;
        }
    }
    bif.bmiHeader.biHeight = -r.bottom;
    bif.bmiHeader.biWidth = r.right;
    bif.bmiHeader.biSizeImage = ((bif.bmiHeader.biWidth * 24 + 31)& ~31) / 8 * bif.bmiHeader.biHeight;
    bif.bmiHeader.biPlanes = 1;
    bif.bmiHeader.biBitCount = sizeof(RGBQUAD)*8;
    SetDIBitsToDevice(hdc, 0, 0, r.right, r.bottom, 0, 0, 0, r.bottom, im, &bif, DIB_PAL_COLORS);
    delete[] im;

Но писать свои Rectangle Ellipse и т.д. времени нету, да и я о сглаживании молчу. Значит нужно использовать GDI и GDI+. Каков алгоритм в этом случае(если я не прав, то поправьте):

Создаём совместный ДС, и битмап - рисуем там - создаём массив, который будет нашей "матрицей" - создаём BITMAPINFO, заполняем, с помощью SetDIBits - вызываем SetDIBitsToDevice.

Код ниже не выполнятся правильно, просто белый фон

    tagPAINTSTRUCT ps;
    hdc=BeginPaint(hWnd, &ps);
    HDC hdcc = CreateCompatibleDC(hdc);
    HBITMAP bm = CreateCompatibleBitmap(hdc, r.right, r.bottom);
    SelectObject(hdcc, bm);
    HBRUSH hb = CreateSolidBrush(RGB(0, 0, 0));
    SelectObject(hdcc, hb);
    Rectangle(hdcc, 0, 0, 100, 100);
    DeleteObject(hb);
    BITMAPINFO bif;
    ZeroMemory(&bif, sizeof(BITMAPINFO));
    bif.bmiHeader.biSize = sizeof(bif);
    RGBQUAD *im = new RGBQUAD[r.right*r.bottom];
    SetDIBits(hdcc, bm, 0, r.bottom, im, &bif, DIB_PAL_COLORS);
    SetDIBitsToDevice(hdc, 0, 0, r.right, r.bottom, 0, 0, 0, r.bottom, im, &bif, DIB_PAL_COLORS);
    delete[] im;
    DeleteObject(bm);
    DeleteDC(hdcc);
    EndPaint(hWnd, &ps);

1)На МСДН написано, что нельзя в SetDIBits передавать использующийся в данный момент HBITMAP, но как тогда в него рисовать?

2)Возможно я не полностью\не правильно заполняю HBITMAP. В одном из примеров видел что SetDIBits вызывается дважды, в первый раз в качестве указателя на массив передаётся 0, как объяснял автор, именно так заполняется HBITMAPINFO.

P.S. час ночи, голова не варит, может я просто туплю

Answer 1

Походу всё из-за того, что на часах было час ночи. Вся проблема была в том, что я для конвертации HBITMAP использовал SetDIBits, a надо было GetDIBits. И да, вызвать надо дважды. Вот полностью рабочий пример:

    GetClientRect(hWnd, &r);
    tagPAINTSTRUCT ps;
    hdc=BeginPaint(hWnd, &ps);
    HDC hdcc = CreateCompatibleDC(hdc);
    HBITMAP bm = CreateCompatibleBitmap(hdc, r.right, r.bottom), sec = CreateCompatibleBitmap(hdc, r.right, r.bottom);
    SelectObject(hdcc, bm);
    //ТОДО: код прорисовки
    HBRUSH hb = CreateSolidBrush(RGB(255, 0, 0));
    SelectObject(hdcc, hb);
    Rectangle(hdcc, 0, 0, 100, 100);
    DeleteObject(hb);
    //
    BITMAPINFO bif;
    ZeroMemory(&bif, sizeof(BITMAPINFO));
    //Эти поля нужно зполнять вручную
    bif.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bif.bmiHeader.biBitCount = 4*8;
    bif.bmiHeader.biWidth = r.right;
    bif.bmiHeader.biHeight = r.bottom;
    GetDIBits(hdcc, bm, 0, 0, 0, &bif, DIB_RGB_COLORS);
    RGBQUAD *im = new RGBQUAD[r.right*r.bottom];
    GetDIBits(hdcc, bm, 0, r.bottom, im, &bif, DIB_RGB_COLORS);
    SetDIBitsToDevice(hdc, 0, 0, r.right, r.bottom, 0, 0, 0, r.bottom, im, &bif, DIB_RGB_COLORS);
    delete[] im;
    DeleteObject(bm);
    DeleteDC(hdcc);
    EndPaint(hWnd, &ps);

Как всегда пришлось перерыть 300 форумов, мсднов и стэковерфлоувов...

READ ALSO
Read access violation [требует правки]

Read access violation [требует правки]

Если закрыть глаза на "особенности кода", то похоже Ваше проблема закралась здесь

242
Доступ к закрытому полю класса извне

Доступ к закрытому полю класса извне

Здравствуйте, нашел на неком ресурсе подобный код(немного его модифицировал под себя):

365
Преобразовать код Pascal в C++ [требует правки]

Преобразовать код Pascal в C++ [требует правки]

Помогите преобразовать код Pascal в C++

357
Потоки, WaitForMultipleObject

Потоки, WaitForMultipleObject

Здравствуйте, использование WaitForMultipleObject(

279